[GRASS-SVN] r57598 - grass/trunk/lib/python/temporal

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Sep 5 06:57:43 PDT 2013


Author: huhabla
Date: 2013-09-05 06:57:42 -0700 (Thu, 05 Sep 2013)
New Revision: 57598

Modified:
   grass/trunk/lib/python/temporal/abstract_space_time_dataset.py
   grass/trunk/lib/python/temporal/base.py
   grass/trunk/lib/python/temporal/core.py
   grass/trunk/lib/python/temporal/datetime_math.py
   grass/trunk/lib/python/temporal/sampling.py
   grass/trunk/lib/python/temporal/spatio_temporal_relationships.py
Log:
Enabled deepcopy of map and space time datasets.
Fixed some topology builder issues. Implemented a fast sample method 
that makes use of the topology builder.


Modified: grass/trunk/lib/python/temporal/abstract_space_time_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_space_time_dataset.py	2013-09-05 13:51:57 UTC (rev 57597)
+++ grass/trunk/lib/python/temporal/abstract_space_time_dataset.py	2013-09-05 13:57:42 UTC (rev 57598)
@@ -484,6 +484,219 @@
         """!Sample this space time dataset with the temporal topology
            of a second space time dataset
 
+           In case spatial is True, the spatial overlap between
+           temporal related maps is performed. Only
+           temporal related and spatial overlapping maps are returned.
+
+           Return all registered maps as ordered (by start_time) object list.
+           Each list entry is a list of map
+           objects which are potentially located in temporal relation to the
+           actual granule of the second space time dataset.
+
+           Each entry in the object list is a dict. The actual sampler
+           map and its temporal extent (the actual granule) and
+           the list of samples are stored:
+
+           @code
+           list = self.sample_by_dataset(stds=sampler, method=[
+               "during","overlap","contains","equal"])
+           for entry in list:
+               granule = entry["granule"]
+               maplist = entry["samples"]
+               for map in maplist:
+                   map.select()
+                   map.print_info()
+           @endcode
+
+           A valid temporal topology (no overlapping or inclusion allowed)
+           is needed to get correct results in case of gaps in the sample
+           dataset.
+
+           Gaps between maps are identified as unregistered maps with id==None.
+
+           The objects are initialized with their id's' and the spatio-temporal
+           extent (temporal type, start time, end time, west, east, south,
+           north, bottom and top).
+           In case more map information are needed, use the select()
+           method for each listed object.
+
+           @param stds The space time dataset to be used for temporal sampling
+           @param method This option specifies what sample method should be
+                         used. In case the registered maps are of temporal
+                         point type, only the start time is used for sampling.
+                         In case of mixed of interval data the user can chose
+                         between:
+
+                  - Example @code ["start", "during", "equals"] @endcode
+
+                  - start: Select maps of which the start time is
+                    located in the selection granule
+                    @verbatim
+                    map    :        s
+                    granule:  s-----------------e
+
+                    map    :        s--------------------e
+                    granule:  s-----------------e
+
+                    map    :        s--------e
+                    granule:  s-----------------e
+                    @endverbatim
+
+                  - contains: Select maps which are temporal
+                              during the selection granule
+                    @verbatim
+                    map    :     s-----------e
+                    granule:  s-----------------e
+                    @endverbatim
+
+                  - overlap: Select maps which temporal overlap
+                    the selection granule, this includes overlaps and overlapped
+                    @verbatim
+                    map    :     s-----------e
+                    granule:        s-----------------e
+
+                    map    :     s-----------e
+                    granule:  s----------e
+                    @endverbatim
+
+                  - during: Select maps which temporally contains
+                            the selection granule
+                    @verbatim
+                    map    :  s-----------------e
+                    granule:     s-----------e
+                    @endverbatim
+
+                  - equals: Select maps which temporally equal
+                    to the selection granule
+                    @verbatim
+                    map    :  s-----------e
+                    granule:  s-----------e
+                    @endverbatim
+
+                  - follows: Select maps which temporally follow
+                    the selection granule
+                    @verbatim
+                    map    :              s-----------e
+                    granule:  s-----------e
+                    @endverbatim
+
+                  - precedes: Select maps which temporally precedes
+                    the selection granule
+                    @verbatim
+                    map    :  s-----------e
+                    granule:              s-----------e
+                    @endverbatim
+
+                  All these methods can be combined. Method must be of
+                  type tuple including the identification strings.
+
+           @param spatial If set True additional the 2d spatial overlapping
+                          is used for selection -> spatio-temporal relation.
+                          The returned map objects will have temporal and
+                          spatial extents
+           @param dbif The database interface to be used
+
+           @return A list of lists of map objects or None in case nothing was
+                   found None
+        """
+
+        if self.get_temporal_type() != stds.get_temporal_type():
+            core.error(_("The space time datasets must be of "
+                         "the same temporal type"))
+            return None
+
+        if stds.get_map_time() != "interval":
+            core.error(_("The temporal map type of the sample "
+                         "dataset must be interval"))
+            return None
+
+        dbif, connected = init_dbif(dbif)
+        relations = copy.deepcopy(method)
+
+        # Tune the temporal relations
+        if "start" in relations:
+            if "overlapped" not in relations:
+                relations.append("overlapped")
+            if "starts" not in relations:
+                relations.append("starts")
+            if "started" not in relations:
+                relations.append("started")
+            if "finishes" not in relations:
+                relations.append("finishes")
+            if "contains" not in relations:
+                relations.append("contains")
+            if "equals" not in relations:
+                relations.append("equals")
+
+        if "overlap" in relations or "over" in relations:
+            if "overlapped" not in relations:
+                relations.append("overlapped")
+            if "overlaps" not in relations:
+                relations.append("overlaps")
+
+        if "contain" in relations:
+            if "contains" not in relations:
+                relations.append("contains")
+
+        # Remove start, equal, contain and overlap
+        relations = [relation.upper().strip() for relation in relations if relation \
+                    not in ["start", "overlap", "contain"]]
+
+        #print(relations)
+
+        tb = SpatioTemporalTopologyBuilder()
+        if spatial:
+            spatial = "2D"
+        else:
+            spatial = None
+
+        mapsA = self.get_registered_maps_as_objects(dbif=dbif)
+        mapsB = stds.get_registered_maps_as_objects_with_gaps(dbif=dbif)
+        tb.build(mapsB, mapsA, spatial)
+
+        obj_list = []
+        for map in mapsB:
+            result = {}
+            maplist = []
+            # Get map relations
+            map_relations = map.get_temporal_relations()
+            #print(map.get_temporal_extent_as_tuple())
+            #for key in map_relations.keys():
+            #    if key not in ["NEXT", "PREV"]:
+            #        print(key, map_relations[key][0].get_temporal_extent_as_tuple())
+
+            result["granule"] = map
+            # Append the maps that fullfill the relations
+            for relation in relations:
+                if relation in map_relations.keys():
+                    for sample_map in map_relations[relation]:
+                        if sample_map not in maplist:
+                            maplist.append(sample_map)
+
+            # Add an empty map if no map was found
+            if not maplist:
+                empty_map = self.get_new_map_instance(None)
+                empty_map.set_spatial_extent(map.get_spatial_extent())
+                empty_map.set_temporal_extent(map.get_temporal_extent())
+                maplist.append(empty_map)
+
+            result["samples"] = maplist
+
+            obj_list.append(result)
+
+        if connected:
+            dbif.close()
+
+        return obj_list
+
+
+    def sample_by_dataset_sql(self, stds, method=None, spatial=False, dbif=None):
+        """!Sample this space time dataset with the temporal topology
+           of a second space time dataset using SQL queries.
+
+           This function is very slow for huge large space time datasets
+           but can run several times in the same process without problems.
+
            The sample dataset must have "interval" as temporal map type,
            so all sample maps have valid interval time.
 
@@ -529,6 +742,7 @@
                          point type, only the start time is used for sampling.
                          In case of mixed of interval data the user can chose
                          between:
+                  - ["start", "during", "equals"]
 
                   - start: Select maps of which the start time is
                     located in the selection granule
@@ -543,15 +757,15 @@
                     granule:  s-----------------e
                     @endverbatim
 
-                  - during: Select maps which are temporal
-                    during the selection granule
+                  - contains: Select maps which are temporal
+                              during the selection granule
                     @verbatim
                     map    :     s-----------e
                     granule:  s-----------------e
                     @endverbatim
 
                   - overlap: Select maps which temporal overlap
-                    the selection granule
+                    the selection granule, this includes overlaps and overlapped
                     @verbatim
                     map    :     s-----------e
                     granule:        s-----------------e
@@ -560,14 +774,14 @@
                     granule:  s----------e
                     @endverbatim
 
-                  - contain: Select maps which temporally contain
-                    the selection granule
+                  - during: Select maps which temporally contains
+                            the selection granule
                     @verbatim
                     map    :  s-----------------e
                     granule:     s-----------e
                     @endverbatim
 
-                  - equal: Select maps which temporally equal
+                  - equals: Select maps which temporally equal
                     to the selection granule
                     @verbatim
                     map    :  s-----------e
@@ -591,7 +805,7 @@
                   All these methods can be combined. Method must be of
                   type tuple including the identification strings.
 
-           @param spatial If set True additional the spatial overlapping
+           @param spatial If set True additional the 2d spatial overlapping
                           is used for selection -> spatio-temporal relation.
                           The returned map objects will have temporal and
                           spatial extents
@@ -618,9 +832,9 @@
                     use_during = True
                 if name == "overlap":
                     use_overlap = True
-                if name == "contain":
+                if name == "contain" or name == "contains":
                     use_contain = True
-                if name == "equal":
+                if name == "equal" or name == "equals":
                     use_equal = True
                 if name == "follows":
                     use_follows = True
@@ -916,6 +1130,7 @@
                 next = start + gran
 
             map = first.get_new_instance(None)
+            map.set_spatial_extent_from_values(0,0,0,0,0,0)
             if first.is_time_absolute():
                 map.set_absolute_time(start, next, None)
             else:
@@ -1009,6 +1224,7 @@
                         elif self.is_time_relative():
                             map.set_relative_time(start, end,
                                                  self.get_relative_time_unit())
+                        map.set_spatial_extent_from_values(0,0,0,0,0,0)
                         obj_list.append(copy.copy(map))
 
         if connected:
@@ -1076,24 +1292,25 @@
         # Older temporal databases have no bottom and top columns
         # in their views so we need a work around to set the full
         # spatial extent as well
-        has_bt_columns = True
-        try:
-            rows = self.get_registered_maps(
-                "id,start_time,end_time, west,east,south,north,bottom,top",
-                where, order, dbif)
-        except:
-            try:
-                dbif.rollback()
-                rows = self.get_registered_maps("id,start_time,end_time",
-                                                where, order, dbif)
-                has_bt_columns = False
-                core.warning(_("Old temporal database format detected. "
-                               "The top and "
-                               "bottom column is missing in the views, using"
-                               "a work around."))
-            except:
-                raise
 
+        rows = get_tgis_metadata(dbif)
+        db_version = 0
+
+        if rows:
+            for row in rows:
+                if row["key"] == "tgis_db_version":
+                    db_version = int(row["value"])
+
+        if db_version >= 1:
+            has_bt_columns = True
+            columns = "id,start_time,end_time, west,east,south,north,bottom,top"
+        else:
+            has_bt_columns = False
+            columns = "id,start_time,end_time, west,east,south,north"
+
+        rows = self.get_registered_maps(columns, where, order, dbif)
+
+
         if rows is not None:
             for row in rows:
                 map = self.get_new_map_instance(row["id"])

Modified: grass/trunk/lib/python/temporal/base.py
===================================================================
--- grass/trunk/lib/python/temporal/base.py	2013-09-05 13:51:57 UTC (rev 57597)
+++ grass/trunk/lib/python/temporal/base.py	2013-09-05 13:57:42 UTC (rev 57598)
@@ -5,8 +5,8 @@
 Temporal GIS base classes to be used in other
 Python temporal gis packages.
 
-This packages includes all base classes to store basic information 
-like id, name, mapset creation and modification time as well as sql 
+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.
 
 Usage:
@@ -41,15 +41,14 @@
 class DictSQLSerializer(object):
     def __init__(self):
         self.D = {}
-        self.dbif =  SQLDatabaseInterfaceConnection()
 
     def serialize(self, type, table, where=None):
-        """!Convert the internal dictionary into a string of semicolon 
-            separated SQL statements The keys are the column names and 
+        """!Convert the internal dictionary into a string of semicolon
+            separated SQL statements The keys are the column names and
             the values are the row entries
-            
+
             Usage:
-            
+
             \code
             >>> init()
             >>> t = DictSQLSerializer()
@@ -67,15 +66,17 @@
             ('UPDATE raster_base SET  name = ?  ,creator = ?  ,creation_time = ?  ,modification_time = ?  ,mapset = ?  ,id = ? ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil at PERMANENT'))
             >>> t.serialize(type="UPDATE ALL", table="raster_base")
             ('UPDATE raster_base SET  name = ?  ,creator = ?  ,creation_time = ?  ,modification_time = ?  ,mapset = ?  ,id = ? ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil at PERMANENT'))
-            
+
             @param type must be SELECT. INSERT, UPDATE
             @param table The name of the table to select, insert or update
             @param where The optional where statement
             @return a tuple containing the SQL string and the arguments
-            
+
             \endcode
         """
 
+        dbif =  SQLDatabaseInterfaceConnection()
+
         sql = ""
         args = []
 
@@ -109,12 +110,12 @@
             sql += ') VALUES ('
             for key in self.D.keys():
                 if count == 0:
-                    if self.dbif.dbmi.paramstyle == "qmark":
+                    if dbif.dbmi.paramstyle == "qmark":
                         sql += '?'
                     else:
                         sql += '%s'
                 else:
-                    if self.dbif.dbmi.paramstyle == "qmark":
+                    if dbif.dbmi.paramstyle == "qmark":
                         sql += ' ,?'
                     else:
                         sql += ' ,%s'
@@ -134,13 +135,13 @@
                 # Update only entries which are not None
                 if self.D[key] is not None:
                     if count == 0:
-                        if self.dbif.dbmi.paramstyle == "qmark":
+                        if dbif.dbmi.paramstyle == "qmark":
                             sql += ' %s = ? ' % key
                         else:
                             sql += ' %s ' % key
                             sql += '= %s '
                     else:
-                        if self.dbif.dbmi.paramstyle == "qmark":
+                        if dbif.dbmi.paramstyle == "qmark":
                             sql += ' ,%s = ? ' % key
                         else:
                             sql += ' ,%s ' % key
@@ -157,13 +158,13 @@
             sql += 'UPDATE ' + table + ' SET '
             for key in self.D.keys():
                 if count == 0:
-                    if self.dbif.dbmi.paramstyle == "qmark":
+                    if dbif.dbmi.paramstyle == "qmark":
                         sql += ' %s = ? ' % key
                     else:
                         sql += ' %s ' % key
                         sql += '= %s '
                 else:
-                    if self.dbif.dbmi.paramstyle == "qmark":
+                    if dbif.dbmi.paramstyle == "qmark":
                         sql += ' ,%s = ? ' % key
                     else:
                         sql += ' ,%s ' % key
@@ -177,7 +178,7 @@
         return sql, tuple(args)
 
     def deserialize(self, row):
-        """!Convert the content of the dbmi dictionary like row into the 
+        """!Convert the content of the dbmi dictionary like row into the
            internal dictionary
 
            @param row The dictionary like row to store in the internal dict
@@ -200,19 +201,19 @@
 class SQLDatabaseInterface(DictSQLSerializer):
     """!This class represents the SQL database interface
 
-       Functions to insert, select and update the internal 
+       Functions to insert, select and update the internal
        structure of this class in the temporal database are implemented.
-       This is the base class for raster, raster3d, vector and 
+       This is the base class for raster, raster3d, vector and
        space time datasets data management classes:
        - Identification information (base)
        - Spatial extent
        - Temporal extent
        - Metadata
-       
+
        Usage:
-       
+
        \code
-       
+
         >>> init()
         >>> t = SQLDatabaseInterface("raster", "soil at PERMANENT")
         >>> t.D["name"] = "soil"
@@ -239,14 +240,14 @@
         ("UPDATE raster SET  creation_time = ?  ,mapset = ?  ,name = ?  ,creator = ? WHERE id = 'soil at PERMANENT';\\n", (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren'))
         >>> t.get_update_all_statement_mogrified()
         "UPDATE raster SET  creation_time = '2001-01-01 00:00:00'  ,mapset = 'PERMANENT'  ,name = 'soil'  ,creator = 'soeren' WHERE id = 'soil at PERMANENT';\\n"
-        
+
         \endcode
     """
     def __init__(self, table=None, ident=None):
         """!Constructor of this class
 
            @param table The name of the table
-           @param ident The identifier (primary key) of this 
+           @param ident The identifier (primary key) of this
                          object in the database table
         """
         DictSQLSerializer.__init__(self)
@@ -255,7 +256,7 @@
         self.ident = ident
 
     def get_table_name(self):
-        """!Return the name of the table in which the internal 
+        """!Return the name of the table in which the internal
            data are inserted, updated or selected
            @return The name of the table
            """
@@ -271,7 +272,7 @@
     def delete(self, dbif=None):
         """!Delete the entry of this object from the temporal database
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
         """
         sql = self.get_delete_statement()
@@ -296,7 +297,7 @@
     def is_in_db(self, dbif=None):
         """!Check if this object is present in the temporal database
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
            @return True if this object is present in the temporal database, False otherwise
         """
@@ -321,17 +322,17 @@
         return True
 
     def get_select_statement(self):
-        """!Return the sql statement and the argument list in 
+        """!Return the sql statement and the argument list in
            database specific style
            @return The SELECT string
         """
-        return self.serialize("SELECT", self.get_table_name(), 
+        return self.serialize("SELECT", self.get_table_name(),
                               "WHERE id = \'" + str(self.ident) + "\'")
 
     def get_select_statement_mogrified(self, dbif=None):
         """!Return the select statement as mogrified string
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
            @return The SELECT string
         """
@@ -344,7 +345,7 @@
         """!Select the content from the temporal database and store it
            in the internal dictionary structure
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
         """
         sql, args = self.get_select_statement()
@@ -380,7 +381,7 @@
         return True
 
     def get_insert_statement(self):
-        """!Return the sql statement and the argument 
+        """!Return the sql statement and the argument
            list in database specific style
            @return The INSERT string"""
         return self.serialize("INSERT", self.get_table_name())
@@ -388,7 +389,7 @@
     def get_insert_statement_mogrified(self, dbif=None):
         """!Return the insert statement as mogrified string
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
            @return The INSERT string
         """
@@ -401,7 +402,7 @@
         """!Serialize the content of this object and store it in the temporal
            database using the internal identifier
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
         """
         sql, args = self.get_insert_statement()
@@ -417,24 +418,24 @@
             dbif.close()
 
     def get_update_statement(self, ident=None):
-        """!Return the sql statement and the argument list 
+        """!Return the sql statement and the argument list
            in database specific style
-           
+
            @param ident The identifier to be updated, useful for renaming
            @return The UPDATE string
-           
+
            """
         if ident:
-            return self.serialize("UPDATE", self.get_table_name(), 
+            return self.serialize("UPDATE", self.get_table_name(),
                               "WHERE id = \'" + str(ident) + "\'")
         else:
-            return self.serialize("UPDATE", self.get_table_name(), 
+            return self.serialize("UPDATE", self.get_table_name(),
                               "WHERE id = \'" + str(self.ident) + "\'")
 
     def get_update_statement_mogrified(self, dbif=None, ident=None):
         """!Return the update statement as mogrified string
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
            @param ident The identifier to be updated, useful for renaming
            @return The UPDATE string
@@ -450,7 +451,7 @@
 
            Only object entries which are exists (not None) are updated
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
            @param ident The identifier to be updated, useful for renaming
         """
@@ -470,23 +471,23 @@
             dbif.close()
 
     def get_update_all_statement(self, ident=None):
-        """!Return the sql statement and the argument 
+        """!Return the sql statement and the argument
            list in database specific style
-           
+
            @param ident The identifier to be updated, useful for renaming
            @return The UPDATE string
            """
         if ident:
-            return self.serialize("UPDATE ALL", self.get_table_name(), 
+            return self.serialize("UPDATE ALL", self.get_table_name(),
                               "WHERE id = \'" + str(ident) + "\'")
         else:
-            return self.serialize("UPDATE ALL", self.get_table_name(), 
+            return self.serialize("UPDATE ALL", self.get_table_name(),
                               "WHERE id = \'" + str(self.ident) + "\'")
 
     def get_update_all_statement_mogrified(self, dbif=None, ident=None):
         """!Return the update all statement as mogrified string
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
            @param ident The identifier to be updated, useful for renaming
            @return The UPDATE string
@@ -497,10 +498,10 @@
         return dbif.mogrify_sql_statement(self.get_update_all_statement(ident))
 
     def update_all(self, dbif=None, ident=None):
-        """!Serialize the content of this object, including None objects, 
+        """!Serialize the content of this object, including None objects,
         and update it in the temporal database using the internal identifier
 
-           @param dbif The database interface to be used, 
+           @param dbif The database interface to be used,
                         if None a temporary connection will be established
            @param ident The identifier to be updated, useful for renaming
         """
@@ -523,11 +524,11 @@
 
 
 class DatasetBase(SQLDatabaseInterface):
-    """!This is the base class for all maps and spacetime datasets storing 
+    """!This is the base class for all maps and spacetime datasets storing
         basic identification information
-        
+
         Usage:
-        
+
         \code
 
         >>> init()
@@ -559,22 +560,22 @@
         creator=soeren
         creation_time=2001-01-01 00:00:00
         temporal_type=absolute
-        
+
         \endcode
     """
-    
-    def __init__(self, table=None, ident=None, name=None, mapset=None, 
+
+    def __init__(self, table=None, ident=None, name=None, mapset=None,
                  creator=None, ctime=None,ttype=None):
         """!Constructor
-        
-            @param table The name of the temporal database table 
+
+            @param table The name of the temporal database table
                           that should be used to store the values
-            @param ident The unique identifier must be a combination of 
-                          the dataset name, layer name and the mapset 
+            @param ident The unique identifier must be a combination of
+                          the dataset name, layer name and the mapset
                           "name at mapset" or "name:layer at mapset"
                           used as as primary key in the temporal database
             @param name The name of the map or dataset
-            @param mapset The name of the mapset 
+            @param mapset The name of the mapset
             @param creator The name of the creator
             @param ctime The creation datetime object
             @param ttype The temporal type
@@ -602,8 +603,8 @@
     def set_id(self, ident):
         """!Convenient method to set the unique identifier (primary key)
 
-           @param ident The unique identifier must be a combination 
-                         of the dataset name, layer name and the mapset 
+           @param ident The unique identifier must be a combination
+                         of the dataset name, layer name and the mapset
                          "name at mapset" or "name:layer at mapset"
         """
         self.ident = ident
@@ -653,7 +654,7 @@
         self.D["creator"] = creator
 
     def set_ctime(self, ctime=None):
-        """!Set the creation time of the dataset, 
+        """!Set the creation time of the dataset,
            if nothing set the current time is used
 
            @param ctime The current time of type datetime
@@ -664,7 +665,7 @@
             self.D["creation_time"] = ctime
 
     def set_ttype(self, ttype):
-        """!Set the temporal type of the dataset: absolute or relative, 
+        """!Set the temporal type of the dataset: absolute or relative,
            if nothing set absolute time will assumed
 
            @param ttype The temporal type of the dataset "absolute or relative"
@@ -696,7 +697,7 @@
             return None
 
     def get_map_id(self):
-        """!Convenient method to get the unique map identifier 
+        """!Convenient method to get the unique map identifier
            without layer information
 
            @return the name of the vector map as "name at mapset"
@@ -822,24 +823,24 @@
 
 class RasterBase(DatasetBase):
     """!Time stamped raster map base information class"""
-    def __init__(self, ident=None, name=None, mapset=None, creator=None, 
+    def __init__(self, ident=None, name=None, mapset=None, creator=None,
                  creation_time=None, temporal_type=None):
-        DatasetBase.__init__(self, "raster_base", ident, name, mapset, 
+        DatasetBase.__init__(self, "raster_base", ident, name, mapset,
                               creator, creation_time, temporal_type)
 
 
 class Raster3DBase(DatasetBase):
     """!Time stamped 3D raster map base information class"""
-    def __init__(self, ident=None, name=None, mapset=None, creator=None, 
+    def __init__(self, ident=None, name=None, mapset=None, creator=None,
                  creation_time=None, temporal_type=None,):
-        DatasetBase.__init__(self, "raster3d_base", ident, name, 
-                              mapset, creator, creation_time, 
+        DatasetBase.__init__(self, "raster3d_base", ident, name,
+                              mapset, creator, creation_time,
                               temporal_type)
 
 
 class VectorBase(DatasetBase):
     """!Time stamped vector map base information class"""
-    def __init__(self, ident=None, name=None, mapset=None, layer=None, 
+    def __init__(self, ident=None, name=None, mapset=None, layer=None,
                  creator=None, creation_time=None, temporal_type=None):
         DatasetBase.__init__(self, "vector_base", ident, name, mapset,
                               creator, creation_time, temporal_type)
@@ -861,14 +862,14 @@
 
 class STDSBase(DatasetBase):
     """!Base class for space time datasets
-    
-       This class adds the semantic type member variable to the dataset 
+
+       This class adds the semantic type member variable to the dataset
        base class.
-       
+
     Usage:
 
     \code
-    
+
     >>> init()
     >>> t = STDSBase("stds", "soil at PERMANENT", semantic_type="average", creator="soeren", ctime=datetime(2001,1,1), ttype="absolute")
     >>> t.semantic_type
@@ -890,10 +891,10 @@
     creation_time=2001-01-01 00:00:00
     temporal_type=absolute
     semantic_type=average
-    
+
     \endcode
     """
-    def __init__(self, table=None, ident=None, name=None, mapset=None, 
+    def __init__(self, table=None, ident=None, name=None, mapset=None,
                  semantic_type=None, creator=None, ctime=None,
                  ttype=None):
         DatasetBase.__init__(self, table, ident, name, mapset, creator,
@@ -914,7 +915,7 @@
             return None
 
     semantic_type = property(fget=get_semantic_type, fset=set_semantic_type)
-    
+
     def print_info(self):
         """!Print information about this class in human readable style"""
         DatasetBase.print_info(self)
@@ -932,30 +933,30 @@
 
 class STRDSBase(STDSBase):
     """!Space time raster dataset base information class"""
-    def __init__(self, ident=None, name=None, mapset=None, 
+    def __init__(self, ident=None, name=None, mapset=None,
                  semantic_type=None, creator=None, ctime=None,
                  ttype=None):
-        STDSBase.__init__(self, "strds_base", ident, name, mapset, 
+        STDSBase.__init__(self, "strds_base", ident, name, mapset,
                            semantic_type, creator, ctime,
                            ttype)
 
 
 class STR3DSBase(STDSBase):
     """!Space time 3D raster dataset base information class"""
-    def __init__(self, ident=None, name=None, mapset=None, 
+    def __init__(self, ident=None, name=None, mapset=None,
                  semantic_type=None, creator=None, ctime=None,
                  ttype=None):
-        STDSBase.__init__(self, "str3ds_base", ident, name, mapset, 
+        STDSBase.__init__(self, "str3ds_base", ident, name, mapset,
                            semantic_type, creator, ctime,
                            ttype)
 
 
 class STVDSBase(STDSBase):
     """!Space time vector dataset base information class"""
-    def __init__(self, ident=None, name=None, mapset=None, 
+    def __init__(self, ident=None, name=None, mapset=None,
                  semantic_type=None, creator=None, ctime=None,
                  ttype=None):
-        STDSBase.__init__(self, "stvds_base", ident, name, mapset, 
+        STDSBase.__init__(self, "stvds_base", ident, name, mapset,
                            semantic_type, creator, ctime,
                            ttype)
 

Modified: grass/trunk/lib/python/temporal/core.py
===================================================================
--- grass/trunk/lib/python/temporal/core.py	2013-09-05 13:51:57 UTC (rev 57597)
+++ grass/trunk/lib/python/temporal/core.py	2013-09-05 13:57:42 UTC (rev 57598)
@@ -408,6 +408,7 @@
 
 class SQLDatabaseInterfaceConnection():
     """!This class represents the database interface connection
+       and provides access to the chisen backend modules.
 
        The following DBMS are supported:
          - sqlite via the sqlite3 standard library

Modified: grass/trunk/lib/python/temporal/datetime_math.py
===================================================================
--- grass/trunk/lib/python/temporal/datetime_math.py	2013-09-05 13:51:57 UTC (rev 57597)
+++ grass/trunk/lib/python/temporal/datetime_math.py	2013-09-05 13:57:42 UTC (rev 57598)
@@ -20,7 +20,6 @@
 
 ###############################################################################
 
-
 def relative_time_to_time_delta(value):
     """!Convert the double value representing days
        into a timedelta object.

Modified: grass/trunk/lib/python/temporal/sampling.py
===================================================================
--- grass/trunk/lib/python/temporal/sampling.py	2013-09-05 13:51:57 UTC (rev 57597)
+++ grass/trunk/lib/python/temporal/sampling.py	2013-09-05 13:57:42 UTC (rev 57598)
@@ -25,19 +25,18 @@
 from space_time_datasets import *
 from factory import *
 
-###############################################################################
 
-def sample_stds_by_stds_topology(intype, sampletype, inputs, sampler, header, 
-                                 separator, method, spatial=False, 
+def sample_stds_by_stds_topology(intype, sampletype, inputs, sampler, header,
+                                 separator, method, spatial=False,
                                  print_only=True):
-    """!Sample the input space time datasets with a sample 
-       space time dataset, return the created map matrix and optionally 
+    """!Sample the input space time datasets with a sample
+       space time dataset, return the created map matrix and optionally
        print the result to stdout
 
-        In case multiple maps are located in the current granule, 
+        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 case a layer is present, the names map ids are extended
         in this form: "name:layer at mapset"
 
         Attention: Do not use the comma as separator for printing
@@ -48,13 +47,13 @@
         @param sampler Name of a space time dataset used for temporal sampling
         @param header Set True to print column names
         @param separator The field separator character between the columns
-        @param method The method to be used for temporal sampling 
+        @param method The method to be used for temporal sampling
                        (start,during,contain,overlap,equal)
         @param spatial Perform spatial overlapping check
-        @param print_only If set True (default) then the result of the sampling will be 
-                    printed to stdout, if set to False the resulting map matrix 
-                    will be returned. 
-                    
+        @param print_only If set True (default) then the result of the sampling will be
+                    printed to stdout, if set to False the resulting map matrix
+                    will be returned.
+
         @return The map matrix or None if nothing found
     """
     mapset = core.gisenv()["MAPSET"]
@@ -105,7 +104,7 @@
             mapmatrizes.append(mapmatrix)
 
     if len(mapmatrizes) > 0:
-        
+
         # Simply return the map matrix
         if not print_only:
             dbif.close()
@@ -166,5 +165,5 @@
     dbif.close()
     if len(mapmatrizes) > 0:
         return mapmatrizes
-    
+
     return None

Modified: grass/trunk/lib/python/temporal/spatio_temporal_relationships.py
===================================================================
--- grass/trunk/lib/python/temporal/spatio_temporal_relationships.py	2013-09-05 13:51:57 UTC (rev 57597)
+++ grass/trunk/lib/python/temporal/spatio_temporal_relationships.py	2013-09-05 13:57:42 UTC (rev 57598)
@@ -320,6 +320,42 @@
         ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
         ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)))
 
+        >>> mapsA = []
+        >>> for i in range(4):
+        ...     idA = "a%i at B"%(i)
+        ...     mapA = tgis.RasterDataset(idA)
+        ...     start = datetime.datetime(2000, 1, 1, 0, 0, i)
+        ...     end = datetime.datetime(2000, 1, 1, 0, 0, i + 2)
+        ...     check = mapA.set_absolute_time(start, end)
+        ...     mapsA.append(mapA)
+        >>> tb = SpatioTemporalTopologyBuilder()
+        >>> tb.build(mapsA)
+        >>> # Check relations of mapsA
+        >>> for map in mapsA:
+        ...     print(map.get_temporal_extent_as_tuple())
+        ...     m = map.get_temporal_relations()
+        ...     for key in m.keys():
+        ...         if key not in ["NEXT", "PREV"]:
+        ...             print(key, m[key][0].get_temporal_extent_as_tuple())
+        (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2))
+        ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
+        ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
+        ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2)))
+        (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))
+        ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
+        ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2)))
+        ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)))
+        ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
+        (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))
+        ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)))
+        ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
+        ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2)))
+        ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
+        (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))
+        ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
+        ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
+        ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)))
+
         @endcode
 
     """
@@ -494,7 +530,7 @@
 
         if mapsB == None:
             mapsB = mapsA
-            idetnical = True
+            identical = True
 
         for map_ in mapsA:
             map_.reset_topology()
@@ -505,15 +541,16 @@
 
         tree = self. _build_rtree(mapsA, spatial)
 
+        list_ = gis.G_new_ilist()
+
         for j in xrange(len(mapsB)):
 
-            list_ = gis.ilist()
             rect = self._map_to_rect(tree, mapsB[j], spatial)
-            vector.RTreeSearch2(tree, rect, byref(list_))
+            vector.RTreeSearch2(tree, rect, list_)
             vector.RTreeFreeRect(rect)
 
-            for k in xrange(list_.n_values):
-                i = list_.value[k] - 1
+            for k in xrange(list_.contents.n_values):
+                i = list_.contents.value[k] - 1
 
                 # Get the temporal relationship
                 relation = mapsB[j].temporal_relation(mapsA[i])
@@ -530,6 +567,8 @@
         if not identical and mapsB != None:
             self._build_iteratable(mapsB, spatial)
 
+        gis.G_free_ilist(list_)
+
         vector.RTreeDestroyTree(tree)
 
     def __iter__(self):
@@ -550,16 +589,15 @@
 ###############################################################################
 
 def set_temoral_relationship(A, B, relation):
-    if relation == "equal":
-        if B != A:
-            if not B.get_equal() or \
-            (B.get_equal() and \
-            A not in B.get_equal()):
-                B.append_equal(A)
-            if not A.get_equal() or \
-            (A.get_equal() and \
-            B not in A.get_equal()):
-                A.append_equal(B)
+    if relation == "equal" or relation == "equals":
+        if not B.get_equal() or \
+        (B.get_equal() and \
+        A not in B.get_equal()):
+            B.append_equal(A)
+        if not A.get_equal() or \
+        (A.get_equal() and \
+        B not in A.get_equal()):
+            A.append_equal(B)
     elif relation == "follows":
         if not B.get_follows() or \
             (B.get_follows() and \
@@ -658,15 +696,14 @@
 def set_spatial_relationship(A, B, relation):
 
     if relation == "equivalent":
-        if B != A:
-            if not B.get_equivalent() or \
-            (B.get_equivalent() and \
-            A not in B.get_equivalent()):
-                B.append_equivalent(A)
-            if not A.get_equivalent() or \
-            (A.get_equivalent() and \
-            B not in A.get_equivalent()):
-                A.append_equivalent(B)
+        if not B.get_equivalent() or \
+        (B.get_equivalent() and \
+        A not in B.get_equivalent()):
+            B.append_equivalent(A)
+        if not A.get_equivalent() or \
+        (A.get_equivalent() and \
+        B not in A.get_equivalent()):
+            A.append_equivalent(B)
     elif relation == "overlap":
         if not B.get_overlap() or \
             (B.get_overlap() and \



More information about the grass-commit mailing list