浏览代码

Implemented handling of time-stamped vector layers


git-svn-id: https://svn.osgeo.org/grass/grass/trunk@50467 15284696-431f-4ddb-bdfa-cd5b030d7da7
Soeren Gebbert 13 年之前
父节点
当前提交
a7e5727e68

+ 33 - 0
lib/python/temporal/abstract_dataset.py

@@ -66,8 +66,41 @@ class abstract_dataset(object):
 	self.metadata.print_self()
 	self.metadata.print_self()
 
 
     def get_id(self):
     def get_id(self):
+	"""Return the unique identifier of the dataset"""
         return self.base.get_id()
         return self.base.get_id()
 
 
+    def get_name(self):
+	"""Return the name"""
+        return self.base.get_name()
+
+    def get_mapset(self):
+	"""Return the mapset"""
+        return self.base.get_mapset()
+
+    def build_id(name, mapset, layer=None):
+	"""Build and return the id (primary key) based on name, mapset and layer of a dataset.
+	
+	   @param name: The name of the map
+	   @param mapset: The name of the mapset
+	   @param layer: The name of the layer (optional)
+	
+	   Return None in case the name can not be build (name or mapset are None)
+	"""
+	
+	if not name or not mapset:
+	    return None
+	    
+	# Make sure to extract the pure mapname
+	pure_name = name.split("@")[0].split(":")[0]
+	
+	if layer:
+	    return "%s:%s@%s"%(name, layer, mapset)
+	else:
+	    return "%s@%s"%(name, mapset)
+	
+	return None
+	
+
     def get_valid_time(self):
     def get_valid_time(self):
         """Returns a tuple of the start, the end valid time, this can be either datetime or double values
         """Returns a tuple of the start, the end valid time, this can be either datetime or double values
            @return A tuple of (start_time, end_time)
            @return A tuple of (start_time, end_time)

+ 73 - 16
lib/python/temporal/abstract_map_dataset.py

@@ -58,6 +58,41 @@ class abstract_map_dataset(abstract_dataset):
         """Load the content of this object from map files"""
         """Load the content of this object from map files"""
         raise IOError("This method must be implemented in the subclasses")
         raise IOError("This method must be implemented in the subclasses")
  
  
+    def get_map_id(self):
+	"""Return the map id. The map id is the unique map identifier in grass and must not be equal to the 
+	   primary key identifier (id) of the map in the database. Since vector maps may have layer information,
+	   the unique id is a combination of name, layer and mapset.
+	   
+	   Use get_map_id() every time your need to access the grass map in the file system but not to identify
+	   map information in the temporal database.
+	
+	"""
+        return self.base.get_map_id()
+
+    def build_id(self, name, mapset, layer=None):
+	"""Convenient method to build the unique identifier
+	
+	    Existing layer and mapset definitions in the name string will be reused
+
+           @param return the id of the vector map as name(:layer)@mapset while layer is optional
+        """
+        
+        # Check if the name includes any mapset
+	if name.find("@") >= 0:
+	    name, mapset = name.split("@")[0]
+
+	if name.find(":") >= 0:
+	    name, layer = name.split(":")[0]
+	    
+        if layer:	    
+	    return "%s:%s@%s"%(name, layer, mapset)
+	else:
+	    return "%s@%s"%(name, mapset)
+	    
+    def get_layer(self):
+	"""Return the layer of the map or None in case no layer is defined"""
+	return self.base.get_layer()
+        
     def print_info(self):
     def print_info(self):
         """Print information about this class in human readable style"""
         """Print information about this class in human readable style"""
         
         
@@ -128,14 +163,23 @@ class abstract_map_dataset(abstract_dataset):
         
         
         """
         """
         if start_time and not isinstance(start_time, datetime) :
         if start_time and not isinstance(start_time, datetime) :
-            core.fatal(_("Start time must be of type datetime for %s map <%s>") % (self.get_type(), self.get_id()))
+	    if self.get_layer():
+		core.fatal(_("Start time must be of type datetime for %s map <%s> with layer: %s") % (self.get_type(), self.get_map_id(), self.get_layer()))
+	    else:
+		core.fatal(_("Start time must be of type datetime for %s map <%s>") % (self.get_type(), self.get_map_id()))
 
 
         if end_time and not isinstance(end_time, datetime) :
         if end_time and not isinstance(end_time, datetime) :
-            core.fatal(_("End time must be of type datetime for %s map <%s>") % (self.get_type(), self.get_id()))
+	    if self.get_layer():
+		core.fatal(_("End time must be of type datetime for %s map <%s> with layer: %s") % (self.get_type(), self.get_map_id(), self.get_layer()))
+	    else:
+		core.fatal(_("End time must be of type datetime for %s map <%s>") % (self.get_type(), self.get_map_id()))
 
 
         if start_time and end_time:
         if start_time and end_time:
             if start_time > end_time:
             if start_time > end_time:
-                core.fatal(_("End time must be greater than start time for %s map <%s>") % (self.get_type(), self.get_id()))
+		if self.get_layer():
+		    core.fatal(_("End time must be greater than start time for %s map <%s> with layer: %s") % (self.get_type(), self.get_map_id(), self.get_layer()))
+		else:
+		    core.fatal(_("End time must be greater than start time for %s map <%s>") % (self.get_type(), self.get_map_id()))
             else:
             else:
                 # Do not create an interval in case start and end time are equal
                 # Do not create an interval in case start and end time are equal
                 if start_time == end_time:
                 if start_time == end_time:
@@ -182,27 +226,33 @@ class abstract_map_dataset(abstract_dataset):
             end = datetime_to_grass_datetime_string(end_time)
             end = datetime_to_grass_datetime_string(end_time)
             start += " / %s"%(end)
             start += " / %s"%(end)
 
 
-        core.run_command(self.get_timestamp_module_name(), map=self.get_id(), date=start)
+        core.run_command(self.get_timestamp_module_name(), map=self.get_map_id(), date=start)
 
 
     def set_relative_time(self, start_time, end_time, unit):
     def set_relative_time(self, start_time, end_time, unit):
         """Set the relative time interval 
         """Set the relative time interval 
         
         
            @param start_time: A double value 
            @param start_time: A double value 
            @param end_time: A double value 
            @param end_time: A double value 
-           @param unit: The unit of the relative time. Supported uits: years, months, days, hours, minutes, seconds
+           @param unit: The unit of the relative time. Supported units: years, months, days, hours, minutes, seconds
 
 
            Return True for success and False otherwise
            Return True for success and False otherwise
 
 
         """
         """
 
 
         if not self.check_relative_time_unit(unit):
         if not self.check_relative_time_unit(unit):
-            core.error(_("Unsupported relative time unit type for %s map <%s>: %s") % (self.get_type(), self.get_id(), unit))
+	    if self.get_layer():
+		core.error(_("Unsupported relative time unit type for %s map <%s> with layer %s: %s") % (self.get_type(), self.get_id(), self.get_layer(), unit))
+	    else:
+		core.error(_("Unsupported relative time unit type for %s map <%s>: %s") % (self.get_type(), self.get_id(), unit))
             return False
             return False
         
         
 
 
         if start_time != None and end_time != None:
         if start_time != None and end_time != None:
             if int(start_time) > int(end_time):
             if int(start_time) > int(end_time):
-                core.error(_("End time must be greater than start time for %s map <%s>") % (self.get_type(), self.get_id()))
+		if self.get_layer():
+		    core.error(_("End time must be greater than start time for %s map <%s> with layer %s") % (self.get_type(), self.get_id(), self.get_layer()))
+		else:
+		    core.error(_("End time must be greater than start time for %s map <%s>") % (self.get_type(), self.get_id()))
                 return False
                 return False
             else:
             else:
                 # Do not create an interval in case start and end time are equal
                 # Do not create an interval in case start and end time are equal
@@ -255,7 +305,7 @@ class abstract_map_dataset(abstract_dataset):
         if end_time:
         if end_time:
             end = "%i %s"%(int(end_time), unit)
             end = "%i %s"%(int(end_time), unit)
             start += " / %s"%(end)
             start += " / %s"%(end)
-        core.run_command(self.get_timestamp_module_name(), map=self.get_id(), date=start)
+        core.run_command(self.get_timestamp_module_name(), map=self.get_map_id(), date=start)
 
 
     def set_spatial_extent(self, north, south, east, west, top=0, bottom=0):
     def set_spatial_extent(self, north, south, east, west, top=0, bottom=0):
         """Set the spatial extent of the map
         """Set the spatial extent of the map
@@ -265,7 +315,7 @@ class abstract_map_dataset(abstract_dataset):
            @param east: The eastern edge
            @param east: The eastern edge
            @param west: The western edge
            @param west: The western edge
            @param top: The top edge
            @param top: The top edge
-           @param bottom: The bottom ege
+           @param bottom: The bottom edge
         """
         """
         self.spatial_extent.set_spatial_extent(north, south, east, west, top, bottom)
         self.spatial_extent.set_spatial_extent(north, south, east, west, top, bottom)
         
         
@@ -279,10 +329,13 @@ class abstract_map_dataset(abstract_dataset):
         if start != None:
         if start != None:
             if end != None:
             if end != None:
                 if start >= end:
                 if start >= end:
-                    core.error(_("Map <%s> has incorrect time interval, start time is greater than end time") % (self.get_id()))
+		    if self.get_layer():
+			core.error(_("Map <%s> with layer %s has incorrect time interval, start time is greater than end time") % (self.get_map_id(), self.get_layer()))
+		    else:
+			core.error(_("Map <%s> has incorrect time interval, start time is greater than end time") % (self.get_map_id()))
                     return False
                     return False
         else:
         else:
-            core.error(_("Map <%s> has incorrect start time") % (self.get_id()))
+            core.error(_("Map <%s> has incorrect start time") % (self.get_map_id()))
             return False
             return False
 
 
         return True
         return True
@@ -327,7 +380,7 @@ class abstract_map_dataset(abstract_dataset):
             self.base.delete(dbif)
             self.base.delete(dbif)
 
 
         # Remove the timestamp from the file system
         # Remove the timestamp from the file system
-        core.run_command(self.get_timestamp_module_name(), map=self.get_id(), date="none")
+        core.run_command(self.get_timestamp_module_name(), map=self.get_map_id(), date="none")
 
 
         self.reset(None)
         self.reset(None)
         dbif.connection.commit()
         dbif.connection.commit()
@@ -339,11 +392,15 @@ class abstract_map_dataset(abstract_dataset):
 	""" Remove the map entry in each space time dataset in which this map is registered
 	""" Remove the map entry in each space time dataset in which this map is registered
 
 
            @param dbif: The database interface to be used
            @param dbif: The database interface to be used
-           @param update: Call for each unregister statement the update_from_registered_maps 
-                          of the space time dataset. This can slow down the unregistration process significantly.
+           @param update: Call for each unregister statement the update from registered maps 
+                          of the space time dataset. This can slow down the un-registration process significantly.
         """
         """
 
 
-        core.verbose(_("Unregister %s dataset <%s> from space time datasets") % (self.get_type(), self.get_id()))
+	if self.get_layer():
+	    core.verbose(_("Unregister %s map <%s> with layer %s from space time datasets") % \
+	                   (self.get_type(), self.get_map_id(), self.get_layer()))
+	else:
+	    core.verbose(_("Unregister %s map <%s> from space time datasets") % (self.get_type(), self.get_map_id()))
         
         
         connect = False
         connect = False
 
 
@@ -368,7 +425,7 @@ class abstract_map_dataset(abstract_dataset):
                 stds.select(dbif)
                 stds.select(dbif)
                 stds.unregister_map(self, dbif)
                 stds.unregister_map(self, dbif)
                 # Take care to update the space time dataset after
                 # Take care to update the space time dataset after
-                # the map has been unregistred
+                # the map has been unregistered
                 if update == True:
                 if update == True:
                     stds.update_from_registered_maps(dbif)
                     stds.update_from_registered_maps(dbif)
 
 

+ 67 - 30
lib/python/temporal/abstract_space_time_dataset.py

@@ -183,7 +183,7 @@ class abstract_space_time_dataset(abstract_dataset):
             self.relative_time.set_unit(unit)
             self.relative_time.set_unit(unit)
 
 
     def get_map_time(self):
     def get_map_time(self):
-        """Return the type of the map time, interval, point, maixed or invalid"""
+        """Return the type of the map time, interval, point, mixed or invalid"""
         
         
         temporal_type = self.get_temporal_type()
         temporal_type = self.get_temporal_type()
 
 
@@ -197,7 +197,7 @@ class abstract_space_time_dataset(abstract_dataset):
     def print_temporal_relation_matrix(self, maps):
     def print_temporal_relation_matrix(self, maps):
         """Print the temporal relation matrix of all registered maps to stdout
         """Print the temporal relation matrix of all registered maps to stdout
 
 
-           The temproal relation matrix includes the temporal relations between
+           The temporal relation matrix includes the temporal relations between
            all registered maps. The relations are strings stored in a list of lists.
            all registered maps. The relations are strings stored in a list of lists.
            
            
            @param dbif: The database interface to be used
            @param dbif: The database interface to be used
@@ -227,11 +227,11 @@ class abstract_space_time_dataset(abstract_dataset):
                 print maps[i].base.get_name()
                 print maps[i].base.get_name()
 
 
     def get_temporal_relation_matrix(self, maps):
     def get_temporal_relation_matrix(self, maps):
-        """Return the temporal relation matrix of all registered maps as listof lists
+        """Return the temporal relation matrix of all registered maps as list of lists
 
 
            The map list must be ordered by start time
            The map list must be ordered by start time
 
 
-           The temproal relation matrix includes the temporal relations between
+           The temporal relation matrix includes the temporal relations between
            all registered maps. The relations are strings stored in a list of lists.
            all registered maps. The relations are strings stored in a list of lists.
            
            
            @param maps: a ordered by start_time list of map objects
            @param maps: a ordered by start_time list of map objects
@@ -293,10 +293,10 @@ class abstract_space_time_dataset(abstract_dataset):
         return tcount
         return tcount
 
 
     def count_gaps(self, maps):
     def count_gaps(self, maps):
-        """Count the number of gaps between temporal neighbours
+        """Count the number of gaps between temporal neighbors
         
         
            @param maps: A sorted (start_time) list of abstract_dataset objects
            @param maps: A sorted (start_time) list of abstract_dataset objects
-           @return The numbers of gaps between temporal neighbours
+           @return The numbers of gaps between temporal neighbors
         """
         """
 
 
         gaps = 0
         gaps = 0
@@ -473,7 +473,7 @@ class abstract_space_time_dataset(abstract_dataset):
         use_contain = False
         use_contain = False
         use_equal = False
         use_equal = False
 
 
-        # Inititalize the methods
+        # Initialize the methods
         if method:
         if method:
             for name in method:
             for name in method:
                 if name == "start":
                 if name == "start":
@@ -731,7 +731,7 @@ class abstract_space_time_dataset(abstract_dataset):
     def get_registered_maps(self, columns=None, where = None, order = None, dbif=None):
     def get_registered_maps(self, columns=None, where = None, order = None, dbif=None):
         """Return sqlite rows of all registered maps.
         """Return sqlite rows of all registered maps.
         
         
-           In case columsn are not specified, each row includes all columns specified in the datatype specific view
+           In case columns are not specified, each row includes all columns specified in the datatype specific view
 
 
            @param columns: Columns to be selected as SQL compliant string
            @param columns: Columns to be selected as SQL compliant string
            @param where: The SQL where statement to select a subset of the registered maps without "WHERE"
            @param where: The SQL where statement to select a subset of the registered maps without "WHERE"
@@ -856,14 +856,19 @@ class abstract_space_time_dataset(abstract_dataset):
         if map.is_in_db(dbif) == False:
         if map.is_in_db(dbif) == False:
             dbif.close()
             dbif.close()
             core.fatal(_("Only maps with absolute or relative valid time can be registered"))
             core.fatal(_("Only maps with absolute or relative valid time can be registered"))
-
-        core.verbose(_("Register %s map <%s> in space time %s dataset <%s>") %  (map.get_type(), map.get_id(), map.get_type(), self.get_id()))
+	if map.get_layer():
+	    core.verbose(_("Register %s map <%s> with layer %s in space time %s dataset <%s>") %  (map.get_type(), map.get_map_id(), map.get_layer(), map.get_type(), self.get_id()))
+	else:
+	    core.verbose(_("Register %s map <%s> in space time %s dataset <%s>") %  (map.get_type(), map.get_map_id(), map.get_type(), self.get_id()))
 
 
         # First select all data from the database
         # First select all data from the database
         map.select(dbif)
         map.select(dbif)
 
 
         if not map.check_valid_time():
         if not map.check_valid_time():
-            core.fatal(_("Map <%s> has invalid time") % map.get_id())
+	    if map.get_layer():
+		core.fatal(_("Map <%s> with layer %s has invalid time") % map.get_map_id(), map.get_layer())
+	    else:
+		core.fatal(_("Map <%s> has invalid time") % map.get_map_id())
 
 
         map_id = map.base.get_id()
         map_id = map.base.get_id()
         map_name = map.base.get_name()
         map_name = map.base.get_name()
@@ -882,7 +887,10 @@ class abstract_space_time_dataset(abstract_dataset):
 
 
         # Check temporal types
         # Check temporal types
         if stds_ttype != map_ttype:
         if stds_ttype != map_ttype:
-            core.fatal(_("Temporal type of space time dataset <%s> and map <%s> are different") % (self.get_id(), map.get_id()))
+	    if map.get_layer():
+		core.fatal(_("Temporal type of space time dataset <%s> and map <%s> with layer %s are different") % (self.get_id(), map.get_map_id(), map.get_layer()))
+	    else:
+		core.fatal(_("Temporal type of space time dataset <%s> and map <%s> are different") % (self.get_id(), map.get_map_id()))
 
 
         # In case no map has been registered yet, set the relative time unit from the first map
         # In case no map has been registered yet, set the relative time unit from the first map
         if self.metadata.get_number_of_maps() == None and self.map_counter == 0 and self.is_time_relative():
         if self.metadata.get_number_of_maps() == None and self.map_counter == 0 and self.is_time_relative():
@@ -894,7 +902,10 @@ class abstract_space_time_dataset(abstract_dataset):
 
 
         # Check the relative time unit
         # Check the relative time unit
         if self.is_time_relative() and (stds_rel_time_unit != map_rel_time_unit):
         if self.is_time_relative() and (stds_rel_time_unit != map_rel_time_unit):
-            core.fatal(_("Relative time units of space time dataset <%s> and map <%s> are different") % (self.get_id(), map.get_id()))
+	    if map.get_layer():
+		core.fatal(_("Relative time units of space time dataset <%s> and map <%s> with layer %s are different") % (self.get_id(), map.get_map_id(), map.get_layer()))
+	    else:
+		core.fatal(_("Relative time units of space time dataset <%s> and map <%s> are different") % (self.get_id(), map.get_map_id()))
 
 
         #print "STDS register table", stds_register_table
         #print "STDS register table", stds_register_table
 
 
@@ -902,7 +913,7 @@ class abstract_space_time_dataset(abstract_dataset):
             dbif.close()
             dbif.close()
             core.fatal(_("Only maps from the same mapset can be registered"))
             core.fatal(_("Only maps from the same mapset can be registered"))
 
 
-        # Check if map is already registred
+        # Check if map is already registered
         if stds_register_table:
         if stds_register_table:
 	    if dbmi.paramstyle == "qmark":
 	    if dbmi.paramstyle == "qmark":
 		sql = "SELECT id FROM " + stds_register_table + " WHERE id = (?)"
 		sql = "SELECT id FROM " + stds_register_table + " WHERE id = (?)"
@@ -914,13 +925,17 @@ class abstract_space_time_dataset(abstract_dataset):
             if row and row[0] == map_id:
             if row and row[0] == map_id:
                 if connect == True:
                 if connect == True:
                     dbif.close()
                     dbif.close()
-                core.warning(_("Map <%s> is already registered.") % (map_id))
+                    
+		if map.get_layer():
+		    core.warning(_("Map <%s> with layer %s is already registered.") % (map.get_map_id(), map.get_layer()))
+		else:
+		    core.warning(_("Map <%s> is already registered.") % (map.get_map_id()))
                 return False
                 return False
 
 
         # Create tables
         # Create tables
         sql_path = get_sql_template_path()
         sql_path = get_sql_template_path()
 
 
-        # We need to create the map raster register table bevor we can register the map
+        # We need to create the map raster register table before we can register the map
         if map_register_table == None:
         if map_register_table == None:
             # Create a unique id
             # Create a unique id
             uuid_rand = "map_" + str(uuid.uuid4()).replace("-", "")
             uuid_rand = "map_" + str(uuid.uuid4()).replace("-", "")
@@ -943,16 +958,24 @@ class abstract_space_time_dataset(abstract_dataset):
             except:
             except:
                 if connect == True:
                 if connect == True:
                     dbif.close()
                     dbif.close()
-                core.error(_("Unable to create the space time %s dataset register table for <%s>") % \
-                            (map.get_type(), map.get_id()))
+		if map.get_layer():
+		    core.error(_("Unable to create the space time %s dataset register table for map <%s> with layer %s") % \
+                            (map.get_type(), map.get_map_id(), map.get_layer()))
+                else:
+		    core.error(_("Unable to create the space time %s dataset register table for <%s>") % \
+                            (map.get_type(), map.get_map_id()))
                 raise
                 raise
 
 
             # Set the stds register table name and put it into the DB
             # Set the stds register table name and put it into the DB
             map.set_stds_register(map_register_table)
             map.set_stds_register(map_register_table)
             map.metadata.update(dbif)
             map.metadata.update(dbif)
             
             
-            core.verbose(_("Created register table <%s> for %s map <%s>") % \
-                          (map_register_table, map.get_type(), map.get_id()))
+            if map.get_layer():
+		core.verbose(_("Created register table <%s> for %s map <%s> with layer %s") % \
+				(map_register_table, map.get_type(), map.get_map_id(), map.get_layer()))
+	    else:
+		core.verbose(_("Created register table <%s> for %s map <%s>") % \
+				(map_register_table, map.get_type(), map.get_map_id()))
 
 
         # We need to create the table and register it
         # We need to create the table and register it
         if stds_register_table == None:
         if stds_register_table == None:
@@ -980,8 +1003,12 @@ class abstract_space_time_dataset(abstract_dataset):
             except:
             except:
                 if connect == True:
                 if connect == True:
                     dbif.close()
                     dbif.close()
-                core.error(_("Unable to create the space time %s dataset register table for <%s>") % \
-                            (map.get_type(), map.get_id()))
+		if map.get_layer():
+		    core.error(_("Unable to create the space time %s dataset register table for map <%s> with layer %s") % \
+                            (map.get_type(), map.get_map_id(), map.get_layer()))
+                else:
+		    core.error(_("Unable to create the space time %s dataset register table for <%s>") % \
+                            (map.get_type(), map.get_map_id()))
                 raise
                 raise
 
 
             # Set the map register table name and put it into the DB
             # Set the map register table name and put it into the DB
@@ -1028,7 +1055,7 @@ class abstract_space_time_dataset(abstract_dataset):
     def unregister_map(self, map, dbif = None):
     def unregister_map(self, map, dbif = None):
         """Unregister a map from the space time dataset.
         """Unregister a map from the space time dataset.
 
 
-           This method takes care of the unregistration of a map
+           This method takes care of the un-registration of a map
            from a space time dataset.
            from a space time dataset.
 
 
            @param map: The map object to unregister
            @param map: The map object to unregister
@@ -1043,13 +1070,20 @@ class abstract_space_time_dataset(abstract_dataset):
 
 
         if map.is_in_db(dbif) == False:
         if map.is_in_db(dbif) == False:
             dbif.close()
             dbif.close()
-            core.fatal(_("Unable to find map <%s> in temporal database") % (map.get_id()))
+            
+	    if map.get_layer():
+		core.fatal(_("Unable to find map <%s> with layer %s in temporal database") % (map.get_map_id(), map.get_layer()))
+	    else:
+		core.fatal(_("Unable to find map <%s> in temporal database") % (map.get_map_id()))
 
 
-        core.verbose(_("Unregister %s map <%s>") % (map.get_type(), map.get_id()))
+	if map.get_layer():
+	    core.verbose(_("Unregister %s map <%s> with layer %s") % (map.get_type(), map.get_map_id(), map.get_layer()))
+	else:
+	    core.verbose(_("Unregister %s map <%s>") % (map.get_type(), map.get_map_id()))
 
 
         # First select all data from the database
         # First select all data from the database
         map.select(dbif)
         map.select(dbif)
-        map_id = map.base.get_id()
+        map_id = map.get_id()
         map_register_table = map.get_stds_register()
         map_register_table = map.get_stds_register()
         stds_register_table = self.get_map_register()
         stds_register_table = self.get_map_register()
 
 
@@ -1063,7 +1097,10 @@ class abstract_space_time_dataset(abstract_dataset):
 
 
         # Break if the map is not registered
         # Break if the map is not registered
         if row == None:
         if row == None:
-            core.warning(_("Map <%s> is not registered in space time dataset") %(map_id, self.base.get_id()))
+	    if map.get_layer():
+		core.warning(_("Map <%s> with layer %s is not registered in space time dataset <%s>") %(map.get_map_id(), map.get_layer(), self.base.get_id()))
+	    else:
+		core.warning(_("Map <%s> is not registered in space time dataset <%s>") %(map.get_map_id(), self.base.get_id()))
             if connect == True:
             if connect == True:
                 dbif.close()
                 dbif.close()
             return False
             return False
@@ -1100,9 +1137,9 @@ class abstract_space_time_dataset(abstract_dataset):
            will be used. If the end time is earlier than the maximum start time, it will
            will be used. If the end time is earlier than the maximum start time, it will
            be replaced by the maximum start time.
            be replaced by the maximum start time.
 
 
-           An other solution to automate this is to use the diactivated trigger
+           An other solution to automate this is to use the deactivated trigger
            in the SQL files. But this will result in a huge performance issue
            in the SQL files. But this will result in a huge performance issue
-           in case many maps are registred (>1000).
+           in case many maps are registered (>1000).
            
            
            @param dbif: The database interface to be used
            @param dbif: The database interface to be used
         """
         """
@@ -1286,7 +1323,7 @@ class abstract_space_time_dataset(abstract_dataset):
 
 
 def create_temporal_relation_sql_where_statement(start, end, use_start=True, use_during=False, 
 def create_temporal_relation_sql_where_statement(start, end, use_start=True, use_during=False, 
                                         use_overlap=False, use_contain=False, use_equal=False):
                                         use_overlap=False, use_contain=False, use_equal=False):
-    """ Create a SQL WHERE statement for temporal relation selection of maps in space time datastes
+    """ Create a SQL WHERE statement for temporal relation selection of maps in space time datasets
 
 
         @param start: The start time
         @param start: The start time
         @param end: The end time
         @param end: The end time

+ 1 - 1
lib/python/temporal/aggregation.py

@@ -42,7 +42,7 @@ def collect_map_names(sp, dbif, start, end, sampling):
     use_contain = False
     use_contain = False
     use_equal = False
     use_equal = False
 
 
-    # Inititalize the methods
+    # Initialize the methods
     if sampling:
     if sampling:
         for name in sampling.split(","):
         for name in sampling.split(","):
             if name == "start":
             if name == "start":

+ 60 - 9
lib/python/temporal/base.py

@@ -5,8 +5,8 @@
 Temporal GIS base classes to be used in other
 Temporal GIS base classes to be used in other
 Python temporal gis packages.
 Python temporal gis packages.
 
 
-This packages includes all base classes to stor basic information like id, name,
-mapset creation and modification time as well as sql serialization and deserialization
+This packages includes all base classes to store basic information like id, name,
+mapset creation and modification time as well as sql serialization and de-serialization
 and the sql database interface.
 and the sql database interface.
 
 
 Usage:
 Usage:
@@ -35,11 +35,11 @@ class dict_sql_serializer(object):
         self.D = {}
         self.D = {}
     def serialize(self, type, table, where=None):
     def serialize(self, type, table, where=None):
 	"""Convert the internal dictionary into a string of semicolon separated SQL statements
 	"""Convert the internal dictionary into a string of semicolon separated SQL statements
-	   The keys are the colum names and the values are the row entries
+	   The keys are the column names and the values are the row entries
 
 
 	   @type must be SELECT. INSERT, UPDATE
 	   @type must be SELECT. INSERT, UPDATE
 	   @table The name of the table to select, insert or update
 	   @table The name of the table to select, insert or update
-	   @where The optinal where statment
+	   @where The optional where statement
 	   @return the sql string
 	   @return the sql string
 	"""
 	"""
 
 
@@ -142,14 +142,14 @@ class dict_sql_serializer(object):
     def deserialize(self, row):
     def deserialize(self, row):
 	"""Convert the content of the dbmi dictionary like row into the internal dictionary
 	"""Convert the content of the dbmi dictionary like row into the internal dictionary
 
 
-           @param row: The dixtionary like row to stoe in the internal dict
+           @param row: The dictionary like row to store in the internal dict
         """
         """
 	self.D = {}
 	self.D = {}
 	for key in row.keys():
 	for key in row.keys():
 	    self.D[key] = row[key]
 	    self.D[key] = row[key]
 
 
     def clear(self):
     def clear(self):
-	"""Inititalize the internal storage"""
+	"""Initialize the internal storage"""
 	self.D = {}
 	self.D = {}
 
 
     def print_self(self):
     def print_self(self):
@@ -390,6 +390,8 @@ class dataset_base(sql_database_interface):
         if ident != None and name == None and mapset == None:
         if ident != None and name == None and mapset == None:
             if ident.find("@") >= 0:
             if ident.find("@") >= 0:
                 name, mapset = ident.split("@")
                 name, mapset = ident.split("@")
+            if name.find(":") >= 0:
+                name, layer = ident.split(":")
 	self.set_name(name)
 	self.set_name(name)
 	self.set_mapset(mapset)
 	self.set_mapset(mapset)
 	self.set_creator(creator)
 	self.set_creator(creator)
@@ -401,7 +403,7 @@ class dataset_base(sql_database_interface):
     def set_id(self, ident):
     def set_id(self, ident):
 	"""Convenient method to set the unique identifier (primary key)
 	"""Convenient method to set the unique identifier (primary key)
 
 
-           @param ident: The unique identififer should be a combination of the dataset name and the mapset name@mapset
+           @param ident: The unique identifier should be a combination of the dataset name, layer name and the mapset name@mapset
         """
         """
 	self.ident = ident
 	self.ident = ident
 	self.D["id"] = ident
 	self.D["id"] = ident
@@ -416,10 +418,19 @@ class dataset_base(sql_database_interface):
     def set_mapset(self, mapset):
     def set_mapset(self, mapset):
 	"""Set the mapset of the dataset
 	"""Set the mapset of the dataset
 
 
-           @param mapsets: The name of the mapset in whoch this dataset is stored
+           @param mapsets: The name of the mapset in which this dataset is stored
         """
         """
 	self.D["mapset"] = mapset
 	self.D["mapset"] = mapset
 
 
+    def set_layer(self, layer):
+	"""Convenient method to set the layer of the map (part of primary key)
+	
+	   Layer are currently supported for vector maps
+
+           @param layer: The layer of the map
+        """
+	self.D["layer"] = layer
+
     def set_creator(self, creator):
     def set_creator(self, creator):
 	"""Set the creator of the dataset
 	"""Set the creator of the dataset
 
 
@@ -468,6 +479,30 @@ class dataset_base(sql_database_interface):
         else:
         else:
 	    return None
 	    return None
 
 
+    def get_map_id(self):
+	"""Convenient method to get the unique map identifier without layer information
+
+           @param return the name of the vector map as name@mapset
+        """
+        id = self.get_id()
+        if id.find(":") >= 0:
+	    # Remove the layer identifier from the id
+	    return id.split("@")[0].split(":")[0] + "@" + id.split("@")[1]
+	else:
+	    return id
+	    
+    def get_layer(self):
+	"""Convenient method to get the layer of the map (part of primary key)
+	
+	   Layer are currently supported for vector maps
+        
+	   @return None if not found
+	"""
+	if self.D.has_key("layer"):
+	    return self.D["layer"]
+        else:
+	    return None
+
     def get_name(self):
     def get_name(self):
 	"""Get the name of the dataset
 	"""Get the name of the dataset
 	   @return None if not found"""
 	   @return None if not found"""
@@ -531,6 +566,8 @@ class dataset_base(sql_database_interface):
         print " | Id: ........................ " + str(self.get_id())
         print " | Id: ........................ " + str(self.get_id())
         print " | Name: ...................... " + str(self.get_name())
         print " | Name: ...................... " + str(self.get_name())
         print " | Mapset: .................... " + str(self.get_mapset())
         print " | Mapset: .................... " + str(self.get_mapset())
+        if self.get_layer():
+	    print " | Layer:...................... " + str(self.get_layer())
         print " | Creator: ................... " + str(self.get_creator())
         print " | Creator: ................... " + str(self.get_creator())
         print " | Creation time: ............. " + str(self.get_ctime())
         print " | Creation time: ............. " + str(self.get_ctime())
 #        print " | Modification time: ......... " + str(self.get_mtime())
 #        print " | Modification time: ......... " + str(self.get_mtime())
@@ -542,6 +579,8 @@ class dataset_base(sql_database_interface):
         print "id=" + str(self.get_id())
         print "id=" + str(self.get_id())
         print "name=" + str(self.get_name())
         print "name=" + str(self.get_name())
         print "mapset=" + str(self.get_mapset())
         print "mapset=" + str(self.get_mapset())
+        if self.get_layer():
+	    print "layer=" + str(self.get_layer())
         print "creator=" + str(self.get_creator())
         print "creator=" + str(self.get_creator())
         print "creation_time=" + str(self.get_ctime())
         print "creation_time=" + str(self.get_ctime())
 #        print "modification_time=" + str(self.get_mtime())
 #        print "modification_time=" + str(self.get_mtime())
@@ -563,11 +602,23 @@ class raster3d_base(dataset_base):
 	            modification_time, temporal_type, revision)
 	            modification_time, temporal_type, revision)
 
 
 class vector_base(dataset_base):
 class vector_base(dataset_base):
-    def __init__(self, ident=None, name=None, mapset=None, creator=None, creation_time=None,\
+    def __init__(self, ident=None, name=None, mapset=None, layer=None, creator=None, creation_time=None,\
 		    modification_time=None, temporal_type=None, revision=1):
 		    modification_time=None, temporal_type=None, revision=1):
         dataset_base.__init__(self, "vector_base", ident, name, mapset, creator, creation_time,\
         dataset_base.__init__(self, "vector_base", ident, name, mapset, creator, creation_time,\
 	            modification_time, temporal_type, revision)
 	            modification_time, temporal_type, revision)
 
 
+	self.set_id(ident)
+        if ident != None and name == None and mapset == None:
+            if ident.find("@") >= 0:
+                name, mapset = ident.split("@")
+            if layer == None:
+		if name.find(":") >= 0:
+		    name, layer = name.split(":")
+	self.set_name(name)
+	self.set_mapset(mapset)
+	# Layer currently only in use by vector maps
+	self.set_layer(layer)
+
 ###############################################################################
 ###############################################################################
 
 
 class stds_base(dataset_base):
 class stds_base(dataset_base):

+ 3 - 3
lib/python/temporal/core.py

@@ -2,7 +2,7 @@
 
 
 @brief GRASS Python scripting module (temporal GIS functions)
 @brief GRASS Python scripting module (temporal GIS functions)
 
 
-Temporal GIS core functions to be used in Python sripts.
+Temporal GIS core functions to be used in Python scripts.
 
 
 Usage:
 Usage:
 
 
@@ -27,7 +27,7 @@ import grass.script.core as core
 
 
 ###############################################################################
 ###############################################################################
 
 
-# The chosen DBMI backend can be defined on runtime
+# The chosen DBMI back-end can be defined on runtime
 # Check the grass environment before import
 # Check the grass environment before import
 core.run_command("t.connect", flags="c")
 core.run_command("t.connect", flags="c")
 kv = core.parse_command("t.connect", flags="pg")
 kv = core.parse_command("t.connect", flags="pg")
@@ -79,7 +79,7 @@ def create_temporal_database():
     """This function creates the grass location database structure for raster, vector and raster3d maps
     """This function creates the grass location database structure for raster, vector and raster3d maps
        as well as for the space-time datasets strds, str3ds and stvds
        as well as for the space-time datasets strds, str3ds and stvds
 
 
-       This functions must be called befor any spatio-temporal processing is started
+       This functions must be called before any spatio-temporal processing is started
     """
     """
     
     
     database = get_temporal_dbmi_init_string()
     database = get_temporal_dbmi_init_string()

+ 5 - 5
lib/python/temporal/datetime_math.py

@@ -2,7 +2,7 @@
 
 
 @brief GRASS Python scripting module (temporal GIS functions)
 @brief GRASS Python scripting module (temporal GIS functions)
 
 
-Temporal GIS datetime math functions to be used in Python sripts.
+Temporal GIS datetime math functions to be used in Python scripts.
 
 
 Usage:
 Usage:
 
 
@@ -51,7 +51,7 @@ def time_delta_to_relative_time(delta):
 
 
 def increment_datetime_by_string(mydate, increment, mult = 1):
 def increment_datetime_by_string(mydate, increment, mult = 1):
     """Return a new datetime object incremented with the provided relative dates specified as string.
     """Return a new datetime object incremented with the provided relative dates specified as string.
-       Additional a multiplier can be specified to multiply the increment bevor adding to the provided datetime object.
+       Additional a multiplier can be specified to multiply the increment before adding to the provided datetime object.
 
 
        @param mydate A datetime object to incremented
        @param mydate A datetime object to incremented
        @param increment A string providing increment information:
        @param increment A string providing increment information:
@@ -126,7 +126,7 @@ def increment_datetime(mydate, years=0, months=0, weeks=0, days=0, hours=0, minu
         # Make a deep copy of the datetime object
         # Make a deep copy of the datetime object
         dt1 = copy.copy(mydate)
         dt1 = copy.copy(mydate)
 
 
-        # Make sure the montha starts with a 1
+        # Make sure the month starts with a 1
         if residual_months == 0:
         if residual_months == 0:
             residual_months = 1
             residual_months = 1
 
 
@@ -321,7 +321,7 @@ def compute_datetime_delta(start, end):
 def string_to_datetime(time_string):
 def string_to_datetime(time_string):
     """Convert a string into a datetime object using the dateutil parser. Return None in case of failure"""
     """Convert a string into a datetime object using the dateutil parser. Return None in case of failure"""
 
 
-    # BC is not suported
+    # BC is not supported
     if time_string.find("bc") > 0:
     if time_string.find("bc") > 0:
         core.error("Dates Before Christ are not supported in the temporal database")
         core.error("Dates Before Christ are not supported in the temporal database")
         return None
         return None
@@ -340,7 +340,7 @@ def datetime_to_grass_datetime_string(dt):
     # GRASS datetime month names
     # GRASS datetime month names
     month_names  = ["", "jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"]
     month_names  = ["", "jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"]
 
 
-    # Check for time zone infor in the datetime object
+    # Check for time zone info in the datetime object
     if dt.tzinfo != None:
     if dt.tzinfo != None:
         string = "%.2i %s %.2i %.2i:%.2i:%.2i %+.4i"%(dt.day, month_names[dt.month], dt.year, \
         string = "%.2i %s %.2i %.2i:%.2i:%.2i %+.4i"%(dt.day, month_names[dt.month], dt.year, \
                  dt.hour, dt.minute, dt.second, dt.tzinfo._offset.seconds/60)
                  dt.hour, dt.minute, dt.second, dt.tzinfo._offset.seconds/60)

+ 12 - 5
lib/python/temporal/space_time_datasets.py

@@ -78,7 +78,7 @@ class raster_dataset(abstract_map_dataset):
         """Load all info from an existing raster map into the internal structure"""
         """Load all info from an existing raster map into the internal structure"""
 
 
         # Get the data from an existing raster map
         # Get the data from an existing raster map
-        kvp = raster.raster_info(self.ident)
+        kvp = raster.raster_info(self.get_map_id())
 
 
         # Fill base information
         # Fill base information
 
 
@@ -156,7 +156,7 @@ class raster3d_dataset(abstract_map_dataset):
         """Load all info from an existing raster3d map into the internal structure"""
         """Load all info from an existing raster3d map into the internal structure"""
 
 
         # Get the data from an existing raster map
         # Get the data from an existing raster map
-        kvp = raster3d.raster3d_info(self.ident)
+        kvp = raster3d.raster3d_info(self.get_map_id())
 
 
         # Fill base information
         # Fill base information
 
 
@@ -224,6 +224,10 @@ class vector_dataset(abstract_map_dataset):
         """Return the name of the C-module to set the time stamp in the file system"""
         """Return the name of the C-module to set the time stamp in the file system"""
         return "v.timestamp"
         return "v.timestamp"
 
 
+    def get_layer(self):
+        """Return the layer"""
+        return self.base.get_layer()
+
     def reset(self, ident):
     def reset(self, ident):
 	"""Reset the internal structure and set the identifier"""
 	"""Reset the internal structure and set the identifier"""
 	self.ident = ident
 	self.ident = ident
@@ -238,11 +242,14 @@ class vector_dataset(abstract_map_dataset):
         """Load all info from an existing vector map into the internal structure"""
         """Load all info from an existing vector map into the internal structure"""
 
 
         # Get the data from an existing raster map
         # Get the data from an existing raster map
-        kvp = vector.vector_info(self.ident)
+        kvp = vector.vector_info(self.get_map_id())
 
 
         # Fill base information
         # Fill base information
-
-        self.base.set_name(self.ident.split("@")[0])
+	if self.ident.find(":") >= 0:
+	    self.base.set_name(self.ident.split("@")[0].split(":")[0])
+	    self.base.set_layer(self.ident.split("@")[0].split(":")[1])
+	else:
+	    self.base.set_name(self.ident.split("@")[0])
         self.base.set_mapset(self.ident.split("@")[1])
         self.base.set_mapset(self.ident.split("@")[1])
         self.base.set_creator(str(getpass.getuser()))
         self.base.set_creator(str(getpass.getuser()))
 
 

+ 146 - 59
lib/python/temporal/space_time_datasets_tools.py

@@ -26,7 +26,9 @@ from space_time_datasets import *
 
 
 ###############################################################################
 ###############################################################################
 
 
-def register_maps_in_space_time_dataset(type, name, maps=None, file=None, start=None, end=None, unit=None, increment=None, dbif = None, interval=False, fs="|"):
+def register_maps_in_space_time_dataset(type, name, maps=None, layer=None, file=None, start=None, \
+                                        end=None, unit=None, increment=None, dbif = None, \
+                                        interval=False, fs="|"):
     """Use this method to register maps in space time datasets. This function is generic and
     """Use this method to register maps in space time datasets. This function is generic and
 
 
        Additionally a start time string and an increment string can be specified
        Additionally a start time string and an increment string can be specified
@@ -50,6 +52,7 @@ def register_maps_in_space_time_dataset(type, name, maps=None, file=None, start=
 
 
     start_time_in_file = False
     start_time_in_file = False
     end_time_in_file = False
     end_time_in_file = False
+    layer_in_file = False
 
 
     if maps and file:
     if maps and file:
         core.fatal(_("%s= and %s= are mutually exclusive") % ("input","file"))
         core.fatal(_("%s= and %s= are mutually exclusive") % ("input","file"))
@@ -63,6 +66,9 @@ def register_maps_in_space_time_dataset(type, name, maps=None, file=None, start=
     if not maps and not file:
     if not maps and not file:
         core.fatal(_("Please specify %s= or %s=") % ("input","file"))
         core.fatal(_("Please specify %s= or %s=") % ("input","file"))
 
 
+    if layer and layer == "file":
+        layer_in_file = True
+        
     if start and start == "file":
     if start and start == "file":
         start_time_in_file = True
         start_time_in_file = True
 
 
@@ -94,15 +100,39 @@ def register_maps_in_space_time_dataset(type, name, maps=None, file=None, start=
         dbif.close()
         dbif.close()
         core.fatal(_("Space time %s dataset <%s> no found") % (sp.get_new_map_instance(None).get_type(), name))
         core.fatal(_("Space time %s dataset <%s> no found") % (sp.get_new_map_instance(None).get_type(), name))
 
 
+    dummy = sp.get_new_map_instance(None)
+        
     maplist = []
     maplist = []
-
+    layerlist = []
+    
     # Map names as comma separated string
     # Map names as comma separated string
     if maps:
     if maps:
-        if maps.find(",") == -1:
-            maplist = (maps,)
+        if maps.find(",") < 0:
+            maplist = [maps,]
         else:
         else:
-            maplist = tuple(maps.split(","))
-
+            maplist = maps.split(",")
+
+	# Layer as comma separated string
+	if layer:
+	    if layer.find(",") < 0:
+		layerlist = (layer,)
+	    else:
+		layerlist = layer.split(",")
+		
+	    if len(maplist) != len(layerlist):
+		core.fatal(_("Number of %s= and %s= must be equal") % ("maps","layer"))
+	    
+	# Build the maplist again with the ids
+	for count in range(len(maplist)):
+	    row = {}
+	    if layer:
+		mapid = dummy.build_id(maplist[count], mapset, layerlist[count])
+            else:
+		mapid = dummy.build_id(maplist[count], mapset, None)
+		
+	    row["id"] = mapid
+            maplist[count] = row
+            
     # Read the map list from file
     # Read the map list from file
     if file:
     if file:
         fd = open(file, "r")
         fd = open(file, "r")
@@ -117,66 +147,73 @@ def register_maps_in_space_time_dataset(type, name, maps=None, file=None, start=
 
 
             mapname = line_list[0].strip()
             mapname = line_list[0].strip()
 
 
-            if mapname.find("@") < 0:
-                mapid = mapname + "@" + mapset
-            else:
-                mapid = mapname
-
             row = {}
             row = {}
-            row["id"] = mapid
-
-            if start_time_in_file and  end_time_in_file:
-                row["start"] = line_list[1].strip()
-                row["end"] = line_list[2].strip()
-
-            if start_time_in_file and  not end_time_in_file:
-                row["start"] = line_list[1].strip()
+            
+	    if layer_in_file:
+		row["layer"] = line_list[1].strip()
+		if start_time_in_file and  end_time_in_file:
+		    row["start"] = line_list[2].strip()
+		    row["end"] = line_list[3].strip()
+
+		if start_time_in_file and  not end_time_in_file:
+		    row["start"] = line_list[2].strip()
+		    
+		row["id"] = dummy.build_id(mapname, mapset, row["layer"])
+	    else:
+		if start_time_in_file and  end_time_in_file:
+		    row["start"] = line_list[1].strip()
+		    row["end"] = line_list[2].strip()
+
+		if start_time_in_file and  not end_time_in_file:
+		    row["start"] = line_list[1].strip()
+		
+		row["id"] = dummy.build_id(mapname, mapset)
 
 
             maplist.append(row)
             maplist.append(row)
     
     
     num_maps = len(maplist)
     num_maps = len(maplist)
-    count = 0
-    for entry in maplist:
+    for count in range(len(maplist)):
 	core.percent(count, num_maps, 1)
 	core.percent(count, num_maps, 1)
 
 
         # Get a new instance of the space time dataset map type
         # Get a new instance of the space time dataset map type
-        if file:
-            map = sp.get_new_map_instance(entry["id"])
-        else:
-            if entry.find("@") < 0:
-                mapid = entry + "@" + mapset
-            else:
-                mapid = entry
-
-            map = sp.get_new_map_instance(mapid)
+        map = sp.get_new_map_instance(maplist[count]["id"])
 
 
         # Use the time data from file
         # Use the time data from file
         if start_time_in_file:
         if start_time_in_file:
-            start = entry["start"]
+            start = maplist[count]["start"]
         if end_time_in_file:
         if end_time_in_file:
-            end = entry["end"]
+            end = maplist[count]["end"]
 
 
         # Put the map into the database
         # Put the map into the database
         if map.is_in_db(dbif) == False:
         if map.is_in_db(dbif) == False:
             # Break in case no valid time is provided
             # Break in case no valid time is provided
             if start == "" or start == None:
             if start == "" or start == None:
                 dbif.close()
                 dbif.close()
-                core.fatal(_("Unable to register %s map <%s>. The map has no valid time and the start time is not set.") % \
-                            (map.get_type(), map.get_id() ))
+                if map.get_layer():
+		    core.fatal(_("Unable to register %s map <%s> with layer %s. The map has no valid time and the start time is not set.") % \
+				(map.get_type(), map.get_map_id(), map.get_layer() ))
+		else:
+		    core.fatal(_("Unable to register %s map <%s>. The map has no valid time and the start time is not set.") % \
+				(map.get_type(), map.get_map_id() ))
             # Load the data from the grass file database
             # Load the data from the grass file database
             map.load()
             map.load()
-
+	    
             if sp.get_temporal_type() == "absolute":
             if sp.get_temporal_type() == "absolute":
                 map.set_time_to_absolute()
                 map.set_time_to_absolute()
             else:
             else:
                 map.set_time_to_relative()
                 map.set_time_to_relative()
+                
             #  Put it into the temporal database
             #  Put it into the temporal database
             map.insert(dbif)
             map.insert(dbif)
         else:
         else:
             map.select(dbif)
             map.select(dbif)
             if map.get_temporal_type() != sp.get_temporal_type():
             if map.get_temporal_type() != sp.get_temporal_type():
                 dbif.close()
                 dbif.close()
-                core.fatal(_("Unable to register %s map <%s>. The temporal types are different.") %  (map.get_type(), map.get_id()))
+                if map.get_layer():
+		    core.fatal(_("Unable to register %s map <%s> with layer. The temporal types are different.") %  \
+		                 (map.get_type(), map.get_map_id(), map.get_layer()))
+		    core.fatal(_("Unable to register %s map <%s>. The temporal types are different.") %  \
+		                 (map.get_type(), map.get_map_id()))
 
 
         # In case the time is in the input file we ignore the increment counter
         # In case the time is in the input file we ignore the increment counter
         if start_time_in_file:
         if start_time_in_file:
@@ -188,7 +225,6 @@ def register_maps_in_space_time_dataset(type, name, maps=None, file=None, start=
 
 
         # Finally Register map in the space time dataset
         # Finally Register map in the space time dataset
         sp.register_map(map, dbif)
         sp.register_map(map, dbif)
-        count += 1
 
 
     # Update the space time tables
     # Update the space time tables
     sp.update_from_registered_maps(dbif)
     sp.update_from_registered_maps(dbif)
@@ -200,7 +236,7 @@ def register_maps_in_space_time_dataset(type, name, maps=None, file=None, start=
         
         
 ###############################################################################
 ###############################################################################
 
 
-def unregister_maps_from_space_time_datasets(type, name, maps, file=None, dbif = None):
+def unregister_maps_from_space_time_datasets(type, name, maps, layer=None, file=None, dbif=None):
     """Unregister maps from a single space time dataset or, in case no dataset name is provided,
     """Unregister maps from a single space time dataset or, in case no dataset name is provided,
        unregister from all datasets within the maps are registered.
        unregister from all datasets within the maps are registered.
 
 
@@ -220,6 +256,11 @@ def unregister_maps_from_space_time_datasets(type, name, maps, file=None, dbif =
         dbif.connect()
         dbif.connect()
         connect = True
         connect = True
 
 
+    layer_in_file = False
+    
+    if layer and layer == "file":
+        layer_in_file = True
+        
     # In case a space time dataset is specified
     # In case a space time dataset is specified
     if name:
     if name:
         # Check if the dataset name contains the mapset as well
         # Check if the dataset name contains the mapset as well
@@ -240,14 +281,38 @@ def unregister_maps_from_space_time_datasets(type, name, maps, file=None, dbif =
             core.fatal("Space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> not found")
             core.fatal("Space time " + sp.get_new_map_instance(None).get_type() + " dataset <" + name + "> not found")
 
 
     maplist = []
     maplist = []
+    layerlist = []
 
 
-    # Map names as comma separated string
-    if maps:
-        if maps.find(",") == -1:
-            maplist = (maps,)
-        else:
-            maplist = tuple(maps.split(","))
+    dummy = raster_dataset(None)
 
 
+    # Map names as comma separated string
+    if maps != None:
+	if maps.find(",") == -1:
+	    maplist = [maps,]
+	else:
+	    maplist = maps.split(",")
+	    
+	if layer:
+	    if layer.find(",") < 0:
+		layerlist = (layer,)
+	    else:
+		layerlist = layer.split(",")
+		
+	    if len(maplist) != len(layerlist):
+		core.fatal(_("Number of %s= and %s= must be equal") % ("maps","layer"))
+		
+	# Build the maplist
+	for count in range(len(maplist)):
+	    mapname = maplist[count]
+	    
+	    if layer:
+		mylayer = layerlist[count]
+		mapid = dummy.build_id(mapname, mapset, mylayer)
+	    else:
+		mapid = dummy.build_id(mapname, mapset)
+		
+            maplist[count] = mapid
+            
     # Read the map list from file
     # Read the map list from file
     if file:
     if file:
         fd = open(file, "r")
         fd = open(file, "r")
@@ -260,19 +325,21 @@ def unregister_maps_from_space_time_datasets(type, name, maps, file=None, dbif =
 
 
             line_list = line.split(fs)
             line_list = line.split(fs)
             mapname = line_list[0].strip()
             mapname = line_list[0].strip()
-            maplist.append(mapname)
     
     
+	    if layer_in_file:
+		mylayer = line_list[1].strip()
+		mapid = dummy.build_id(mapname, mapset, mylayer)
+	    else:
+		mapid = dummy.build_id(mapname, mapset)
+
+            maplist.append(mapid)
+            
     num_maps = len(maplist)
     num_maps = len(maplist)
     count = 0
     count = 0
-    for mapname in maplist:
+    for mapid in maplist:
 	core.percent(count, num_maps, 1)
 	core.percent(count, num_maps, 1)
-        mapname = mapname.strip()
-        # Check if the map name contains the mapset as well
-        if mapname.find("@") < 0:
-            mapid = mapname + "@" + mapset
-        else:
-            mapid = mapname
             
             
+        print mapid
         map = dataset_factory(type, mapid)
         map = dataset_factory(type, mapid)
 
 
         # Unregister map if in database
         # Unregister map if in database
@@ -497,8 +564,11 @@ def assign_valid_time_to_map(ttype, map, start, end, unit, increment=None, mult=
             start_time = increment_datetime_by_string(start_time, increment, mult)
             start_time = increment_datetime_by_string(start_time, increment, mult)
             if interval:
             if interval:
                 end_time = increment_datetime_by_string(start_time, increment, 1)
                 end_time = increment_datetime_by_string(start_time, increment, 1)
-
-        core.verbose(_("Set absolute valid time for map <%s> to %s - %s") % (map.get_id(), str(start_time), str(end_time)))
+	if map.get_layer():
+	    core.verbose(_("Set absolute valid time for map <%s> with layer %s to %s - %s") % (map.get_map_id(), map.get_layer(), str(start_time), str(end_time)))
+        else:
+	    core.verbose(_("Set absolute valid time for map <%s> to %s - %s") % (map.get_map_id(), str(start_time), str(end_time)))
+        
         map.update_absolute_time(start_time, end_time, None, dbif)
         map.update_absolute_time(start_time, end_time, None, dbif)
     else:
     else:
         start_time = int(start)
         start_time = int(start)
@@ -512,7 +582,11 @@ def assign_valid_time_to_map(ttype, map, start, end, unit, increment=None, mult=
             if interval:
             if interval:
                 end_time = start_time + int(increment)
                 end_time = start_time + int(increment)
 
 
-        core.verbose(_("Set relative valid time for map <%s> to %i - %s with unit %s") % (map.get_id(), start_time,  str(end_time), unit))
+	if map.get_layer():
+	    core.verbose(_("Set relative valid time for map <%s> with layer %s to %i - %s with unit %s") % (map.get_map_id(), map.get_layer(), start_time,  str(end_time), unit))
+        else:
+	    core.verbose(_("Set relative valid time for map <%s> to %i - %s with unit %s") % (map.get_map_id(), start_time,  str(end_time), unit))
+	    
         map.update_relative_time(start_time, end_time, unit, dbif)
         map.update_relative_time(start_time, end_time, unit, dbif)
 
 
     if connect == True:
     if connect == True:
@@ -552,14 +626,14 @@ def list_maps_of_stds(type, input, columns, order, where, separator, method, hea
         @param type: The type of the maps raster, raster3d or vector
         @param type: The type of the maps raster, raster3d or vector
         @param input: Name of a space time raster dataset
         @param input: Name of a space time raster dataset
         @param columns: A comma separated list of columns to be printed to stdout 
         @param columns: A comma separated list of columns to be printed to stdout 
-        @param order: A comma seoarated list of columns to order the space time dataset by category 
+        @param order: A comma separated list of columns to order the space time dataset by category 
         @param where: A where statement for selected listing without "WHERE" e.g: start_time < "2001-01-01" and end_time > "2001-01-01"
         @param where: A where statement for selected listing without "WHERE" e.g: start_time < "2001-01-01" and end_time > "2001-01-01"
         @param separator: The field separator character between the columns
         @param separator: The field separator character between the columns
         @param method: String identifier to select a method out of cols,comma,delta or deltagaps
         @param method: String identifier to select a method out of cols,comma,delta or deltagaps
             * "cols": Print preselected columns specified by columns
             * "cols": Print preselected columns specified by columns
             * "comma": Print the map ids (name@mapset) as comma separated string
             * "comma": Print the map ids (name@mapset) as comma separated string
             * "delta": Print the map ids (name@mapset) with start time, end time, relative length of intervals and the relative distance to the begin
             * "delta": Print the map ids (name@mapset) with start time, end time, relative length of intervals and the relative distance to the begin
-            * "deltagaps": Same as "delta" with addtitionakl listing of gaps. Gaps can be simply identified as the id is "None"
+            * "deltagaps": Same as "delta" with additional listing of gaps. Gaps can be simply identified as the id is "None"
             * "gran": List map using the granularity of the space time dataset, columns are identical to deltagaps 
             * "gran": List map using the granularity of the space time dataset, columns are identical to deltagaps 
         @param header: Set True to print column names 
         @param header: Set True to print column names 
     """
     """
@@ -582,7 +656,10 @@ def list_maps_of_stds(type, input, columns, order, where, separator, method, hea
            
            
     # This method expects a list of objects for gap detection
     # This method expects a list of objects for gap detection
     if method == "delta" or method == "deltagaps" or method == "gran":
     if method == "delta" or method == "deltagaps" or method == "gran":
-        columns = "id,start_time,end_time"
+	if type == "stvds":
+	    columns = "id,name,layer,mapset,start_time,end_time"
+	else:
+	    columns = "id,name,mapset,start_time,end_time"
         if method == "deltagaps":
         if method == "deltagaps":
             maps = sp.get_registered_maps_as_objects_with_gaps(where, None)
             maps = sp.get_registered_maps_as_objects_with_gaps(where, None)
         elif method == "delta":
         elif method == "delta":
@@ -592,7 +669,11 @@ def list_maps_of_stds(type, input, columns, order, where, separator, method, hea
 
 
         if header:
         if header:
             string = ""
             string = ""
-            string += "%s%s" % ("id", separator)
+	    string += "%s%s" % ("id", separator)
+	    string += "%s%s" % ("name", separator)
+            if type == "stvds":
+		string += "%s%s" % ("layer", separator)
+	    string += "%s%s" % ("mapset", separator)
             string += "%s%s" % ("start_time", separator)
             string += "%s%s" % ("start_time", separator)
             string += "%s%s" % ("end_time", separator)
             string += "%s%s" % ("end_time", separator)
             string += "%s%s" % ("interval_length", separator)
             string += "%s%s" % ("interval_length", separator)
@@ -627,6 +708,10 @@ def list_maps_of_stds(type, input, columns, order, where, separator, method, hea
 
 
                 string = ""
                 string = ""
                 string += "%s%s" % (map.get_id(), separator)
                 string += "%s%s" % (map.get_id(), separator)
+                string += "%s%s" % (map.get_name(), separator)
+		if type == "stvds":
+		    string += "%s%s" % (map.get_layer(), separator)
+                string += "%s%s" % (map.get_mapset(), separator)
                 string += "%s%s" % (start, separator)
                 string += "%s%s" % (start, separator)
                 string += "%s%s" % (end, separator)
                 string += "%s%s" % (end, separator)
                 string += "%s%s" % (delta, separator)
                 string += "%s%s" % (delta, separator)
@@ -686,6 +771,8 @@ def sample_stds_by_stds_topology(intype, sampletype, input, sampler, header, sep
     """ Sample the input space time dataset with a sample space time dataset and print the result to stdout
     """ Sample the input space time dataset with a sample space time dataset and print the result to stdout
 
 
         In case multiple maps are located in the current granule, the map names are separated by comma.
         In case multiple maps are located in the current granule, the map names are separated by comma.
+        
+        In case a layer is present, the names map ids are extended in this form: name:layer@mapset 
 
 
         Attention: Do not use the comma as separator
         Attention: Do not use the comma as separator
 
 

+ 1 - 1
lib/python/temporal/spatial_extent.py

@@ -122,7 +122,7 @@ class spatial_extent(sql_database_interface):
 	self.D["north"] = north
 	self.D["north"] = north
 
 
     def set_south(self, sourth):
     def set_south(self, sourth):
-	"""Set the sourthern edge of the map"""
+	"""Set the southern edge of the map"""
 	self.D["south"] = sourth
 	self.D["south"] = sourth
 
 
     def set_west(self, west):
     def set_west(self, west):

+ 4 - 4
lib/python/temporal/temporal_extent.py

@@ -103,7 +103,7 @@ class abstract_temporal_extent(sql_database_interface):
 	    return False
 	    return False
 
 
     def before(self, map):
     def before(self, map):
-	"""Return True if this time object is temporal located bevor the provided time object
+	"""Return True if this time object is temporal located before the provided time object
 	   A  |---------|
 	   A  |---------|
 	   B             |---------|
 	   B             |---------|
 	"""
 	"""
@@ -235,7 +235,7 @@ class abstract_temporal_extent(sql_database_interface):
 	    return False
 	    return False
 
 
     def overlapped(self, map):
     def overlapped(self, map):
-	"""Return True if this time object is temporal overlaped by the provided time object
+	"""Return True if this time object is temporal overlapped by the provided time object
 	   A    |---------|
 	   A    |---------|
            B  |---------|
            B  |---------|
 	"""
 	"""
@@ -250,7 +250,7 @@ class abstract_temporal_extent(sql_database_interface):
 
 
     def temporal_relation(self, map):
     def temporal_relation(self, map):
 	"""Returns the temporal relation between temporal objects
 	"""Returns the temporal relation between temporal objects
-	   Temporal relationsships are implemented after [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic]
+	   Temporal relationships are implemented after [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic]
 	"""
 	"""
         
         
         # First check for correct time
         # First check for correct time
@@ -505,7 +505,7 @@ class relative_temporal_extent(abstract_temporal_extent):
 
 
     def temporal_relation(self, map):
     def temporal_relation(self, map):
 	"""Returns the temporal relation between temporal objects
 	"""Returns the temporal relation between temporal objects
-	   Temporal relationsships are implemented after [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic]
+	   Temporal relationships are implemented after [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic]
 	"""
 	"""
         
         
         # Check units for relative time
         # Check units for relative time

+ 1 - 1
lib/python/temporal/temporal_granularity.py

@@ -28,7 +28,7 @@ from datetime_math import *
 def compute_relative_time_granularity(maps):            
 def compute_relative_time_granularity(maps):            
     """ Compute the relative granularity"""
     """ Compute the relative granularity"""
 
 
-    # The intervaltime must be scaled to days resoltuion
+    # The interval time must be scaled to days resolution
     granularity = None
     granularity = None
 
 
     delta = []
     delta = []