Selaa lähdekoodia

Default temporal database will now be created in tgis/sqlite.db.
The temporal topology computation has been updated to use the
GRASS RTree implementation.
The command history will now saved for space time datasets.
The "command" column has been added to the stds metadata tables.


git-svn-id: https://svn.osgeo.org/grass/grass/trunk@55711 15284696-431f-4ddb-bdfa-cd5b030d7da7

Soeren Gebbert 12 vuotta sitten
vanhempi
commit
ff157b2174

+ 1 - 1
lib/python/temporal/Makefile

@@ -8,7 +8,7 @@ PYDIR = $(ETC)/python
 GDIR = $(PYDIR)/grass
 DSTDIR = $(GDIR)/temporal
 
-MODULES = base core abstract_dataset abstract_map_dataset abstract_space_time_dataset space_time_datasets space_time_datasets_tools metadata spatial_extent temporal_extent datetime_math temporal_granularity temporal_relationships unit_tests aggregation stds_export stds_import extract mapcalc univar_statistics
+MODULES = base core abstract_dataset abstract_temporal_dataset abstract_map_dataset abstract_space_time_dataset space_time_datasets space_time_datasets_tools metadata spatial_extent temporal_extent datetime_math temporal_granularity temporal_relationships unit_tests aggregation stds_export stds_import extract mapcalc univar_statistics
 
 PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
 PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)

+ 103 - 3
lib/python/temporal/abstract_dataset.py

@@ -46,6 +46,8 @@ class ImplementationError(Exception):
     def __str__(self):
         return repr(self.msg)
     
+###############################################################################
+
 class AbstractDataset(object):
     """!This is the base class for all datasets 
        (raster, vector, raster3d, strds, stvds, str3ds)"""
@@ -114,8 +116,10 @@ class AbstractDataset(object):
         return self.base.get_mapset()
 
     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 valid start and end time
+        
+           Start and end time can be either of type datetime or of type double
+           depending on the temporal type
            @return A tuple of (start_time, end_time)
         """
 
@@ -145,7 +149,7 @@ class AbstractDataset(object):
         return (start, end, tz)
 
     def get_relative_time(self):
-        """!Returns the relative time interval (start_time, end_time, unit) 
+        """!Returns the valid relative time interval (start_time, end_time, unit) 
            or None if not present"""
 
         start = self.relative_time.get_start_time()
@@ -352,6 +356,102 @@ class AbstractDataset(object):
 
 ###############################################################################
 
+class AbstractDatasetComparisonKeyStartTime(object):
+    """!This comparison key can be used to sort lists of abstract datasets 
+       by start time
+
+        Example:
+
+        # Return all maps in a space time raster dataset as map objects
+        map_list = strds.get_registered_maps_as_objects()
+
+        # Sort the maps in the list by start time
+        sorted_map_list = sorted(
+            map_list, key=AbstractDatasetComparisonKeyStartTime)
+    """
+    def __init__(self, obj, *args):
+        self.obj = obj
+
+    def __lt__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA < startB
+
+    def __gt__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA > startB
+
+    def __eq__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA == startB
+
+    def __le__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA <= startB
+
+    def __ge__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA >= startB
+
+    def __ne__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return startA != startB
+
+###############################################################################
+
+class AbstractDatasetComparisonKeyEndTime(object):
+    """!This comparison key can be used to sort lists of abstract datasets 
+       by end time
+
+        Example:
+
+        # Return all maps in a space time raster dataset as map objects
+        map_list = strds.get_registered_maps_as_objects()
+
+        # Sort the maps in the list by end time
+        sorted_map_list = sorted(
+            map_list, key=AbstractDatasetComparisonKeyEndTime)
+    """
+    def __init__(self, obj, *args):
+        self.obj = obj
+
+    def __lt__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA < endB
+
+    def __gt__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA > endB
+
+    def __eq__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA == endB
+
+    def __le__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA <= endB
+
+    def __ge__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA >= endB
+
+    def __ne__(self, other):
+        startA, endA = self.obj.get_valid_time()
+        startB, endB = other.obj.get_valid_time()
+        return endA != endB
+
+###############################################################################
+        
 if __name__ == "__main__":
     import doctest
     doctest.testmod()

+ 7 - 364
lib/python/temporal/abstract_map_dataset.py

@@ -8,7 +8,6 @@ Temporal GIS related functions to be used in temporal GIS Python library package
 Usage:
 
 >>> import grass.temporal as tgis
->>> tmr = tgis.TemporalMapRelations()
 >>> amd = tgis.AbstractMapDataset()
 
 (C) 2008-2011 by the GRASS Development Team
@@ -18,371 +17,15 @@ for details.
 
 @author Soeren Gebbert
 """
-from abstract_dataset import *
+from abstract_temporal_dataset import *
 from datetime_math import *
 
-
-class TemporalMapRelations(AbstractDataset):
-    """!This class implements a temporal topology access structure
-
-       This object will be set up by temporal topology creation methods.
-
-       If correctly initialize the calls next() and prev() 
-       let the user walk temporally forward and backward in time.
-
-       The following temporal relations with access methods are supported:
-       * equal
-       * follows
-       * precedes
-       * overlaps
-       * overlapped
-       * during (including starts, finishes)
-       * contains (including started, finished)
-
-
-       @code:
-       # We have build the temporal topology and we know the first map
-       start = first
-       while start:
-
-           # Print all maps this map temporally contains
-           dlist = start.get_contains()
-           for map in dlist:
-               map.print_info()
-
-           start = start.next()
-         @endcode  
-        
-        Usage:
-        
-        @code
-        
-        >>> tmr = TemporalMapRelations()
-        >>> tmr.print_temporal_topology_info()
-         +-------------------- Temporal Topology -------------------------------------+
-        >>> tmr.print_temporal_topology_shell_info()
-        
-        @endcode
-    """
-
-    def __init__(self):
-        AbstractDataset.__init__(self)
-        self.reset_temporal_topology()
-
-    def reset_temporal_topology(self):
-        """!Reset any information about temporal topology"""
-        self._temporal_topology = {}
-        self._has_temporal_topology = False
-
-    def set_temporal_topology_build_true(self):
-        """!Same as name"""
-        self._has_temporal_topology = True
-
-    def set_temporal_topology_build_false(self):
-        """!Same as name"""
-        self._has_temporal_topology = False
-
-    def is_temporal_topology_build(self):
-        """!Check if the temporal topology was build"""
-        return self._has_temporal_topology
-
-    def set_temporal_next(self, map_):
-        """!Set the map that is temporally as closest located after this map.
-
-           Temporally located means that the start time of the "next" map is
-           temporally located AFTER the start time of this map, but temporally
-           near than other maps of the same dataset.
-
-           @param map_: This object should be of type AbstractMapDataset 
-                        or derived classes
-        """
-        self._temporal_topology["NEXT"] = map_
-
-    def set_temporal_prev(self, map_):
-        """!Set the map that is temporally as closest located before this map.
-
-           Temporally located means that the start time of the "previous" map is
-           temporally located BEFORE the start time of this map, but temporally
-           near than other maps of the same dataset.
-
-           @param map_: This object should be of type AbstractMapDataset 
-                        or derived classes
-        """
-        self._temporal_topology["PREV"] = map_
-
-    def temporal_next(self):
-        """!Return the map with a start time temporally located after
-           the start time of this map, but temporal closer than other maps
-
-           @return A map object or None
-        """
-        if "NEXT" not in self._temporal_topology:
-            return None
-        return self._temporal_topology["NEXT"]
-
-    def temporal_prev(self):
-        """!Return the map with a start time temporally located before
-           the start time of this map, but temporal closer than other maps
-
-           @return A map object or None
-        """
-        if "PREV" not in self._temporal_topology:
-            return None
-        return self._temporal_topology["PREV"]
-
-    def append_temporal_equivalent(self, map_):
-        """!Append a map with equivalent temporal extent as this map
-
-           @param map_: This object should be of type AbstractMapDataset 
-                        or derived classes
-        """
-        if "EQUAL" not in self._temporal_topology:
-            self._temporal_topology["EQUAL"] = []
-        self._temporal_topology["EQUAL"].append(map_)
-
-    def get_temporal_equivalent(self):
-        """!Return a list of map objects with equivalent temporal extent as this map
-
-           @return A list of map objects or None
-        """
-        if "EQUAL" not in self._temporal_topology:
-            return None
-        return self._temporal_topology["EQUAL"]
-
-    def append_temporal_overlaps(self, map_):
-        """!Append a map that this map temporally overlaps
-
-           @param map_: This object should be of type AbstractMapDataset 
-                        or derived classes
-        """
-        if "OVERLAPS" not in self._temporal_topology:
-            self._temporal_topology["OVERLAPS"] = []
-        self._temporal_topology["OVERLAPS"].append(map_)
-
-    def get_temporal_overlaps(self):
-        """!Return a list of map objects that this map temporally overlaps
-
-           @return A list of map objects or None
-        """
-        if "OVERLAPS" not in self._temporal_topology:
-            return None
-        return self._temporal_topology["OVERLAPS"]
-
-    def append_temporal_overlapped(self, map_):
-        """!Append a map that this map temporally overlapped
-
-           @param map_: This object should be of type AbstractMapDataset 
-                        or derived classes
-        """
-        if "OVERLAPPED" not in self._temporal_topology:
-            self._temporal_topology["OVERLAPPED"] = []
-        self._temporal_topology["OVERLAPPED"].append(map_)
-
-    def get_temporal_overlapped(self):
-        """!Return a list of map objects that this map temporally overlapped
-
-           @return A list of map objects or None
-        """
-        if "OVERLAPPED" not in self._temporal_topology:
-            return None
-        return self._temporal_topology["OVERLAPPED"]
-
-    def append_temporal_follows(self, map_):
-        """!Append a map that this map temporally follows
-
-           @param map_: This object should be of type AbstractMapDataset 
-                        or derived classes
-        """
-        if "FOLLOWS" not in self._temporal_topology:
-            self._temporal_topology["FOLLOWS"] = []
-        self._temporal_topology["FOLLOWS"].append(map_)
-
-    def get_temporal_follows(self):
-        """!Return a list of map objects that this map temporally follows
-
-           @return A list of map objects or None
-        """
-        if "FOLLOWS" not in self._temporal_topology:
-            return None
-        return self._temporal_topology["FOLLOWS"]
-
-    def append_temporal_precedes(self, map_):
-        """!Append a map that this map temporally precedes
-
-           @param map_: This object should be of type AbstractMapDataset 
-                        or derived classes
-        """
-        if "PRECEDES" not in self._temporal_topology:
-            self._temporal_topology["PRECEDES"] = []
-        self._temporal_topology["PRECEDES"].append(map_)
-
-    def get_temporal_precedes(self):
-        """!Return a list of map objects that this map temporally precedes
-
-           @return A list of map objects or None
-        """
-        if "PRECEDES" not in self._temporal_topology:
-            return None
-        return self._temporal_topology["PRECEDES"]
-
-    def append_temporal_during(self, map_):
-        """!Append a map that this map is temporally located during
-           This includes temporal relationships starts and finishes
-
-           @param map_: This object should be of type 
-                        AbstractMapDataset or derived classes
-        """
-        if "DURING" not in self._temporal_topology:
-            self._temporal_topology["DURING"] = []
-        self._temporal_topology["DURING"].append(map_)
-
-    def get_temporal_during(self):
-        """!Return a list of map objects that this map is temporally located during
-           This includes temporally relationships starts and finishes
-
-           @return A list of map objects or None
-        """
-        if "DURING" not in self._temporal_topology:
-            return None
-        return self._temporal_topology["DURING"]
-
-    def append_temporal_contains(self, map_):
-        """!Append a map that this map temporally contains
-           This includes temporal relationships started and finished
-
-           @param map_: This object should be of type AbstractMapDataset 
-                        or derived classes
-        """
-        if "CONTAINS" not in self._temporal_topology:
-            self._temporal_topology["CONTAINS"] = []
-        self._temporal_topology["CONTAINS"].append(map_)
-
-    def get_temporal_contains(self):
-        """!Return a list of map objects that this map temporally contains
-           This includes temporal relationships started and finished
-
-           @return A list of map objects or None
-        """
-        if "CONTAINS" not in self._temporal_topology:
-            return None
-        return self._temporal_topology["CONTAINS"]
-
-    def _generate_map_list_string(self, map_list, line_wrap=True):
-        count = 0
-        string = ""
-        for map_ in map_list:
-            if line_wrap and count > 0 and count % 3 == 0:
-                string += "\n | ............................ "
-                count = 0
-            if count == 0:
-                string += map_.get_id()
-            else:
-                string += ",%s" % map_.get_id()
-            count += 1
-
-        return string
-    
-    # Set the properties
-    temporal_equivalent = property(fget=get_temporal_equivalent, 
-                                       fset=append_temporal_equivalent)
-    temporal_follows = property(fget=get_temporal_follows, 
-                                    fset=append_temporal_follows)
-    temporal_precedes = property(fget=get_temporal_precedes, 
-                                     fset=append_temporal_precedes)
-    temporal_overlaps = property(fget=get_temporal_overlaps, 
-                                     fset=append_temporal_overlaps)
-    temporal_overlapped = property(fget=get_temporal_overlapped, 
-                                       fset=append_temporal_overlapped)
-    temporal_during = property(fget=get_temporal_during, 
-                                   fset=append_temporal_during)
-    temporal_contains = property(fget=get_temporal_contains, 
-                                     fset=append_temporal_contains)
-
-    def print_temporal_topology_info(self):
-        """!Print information about this class in human readable style"""
-        _next = self.temporal_next()
-        _prev = self.temporal_prev()
-        _equal = self.get_temporal_equivalent()
-        _follows = self.get_temporal_follows()
-        _precedes = self.get_temporal_precedes()
-        _overlaps = self.get_temporal_overlaps()
-        _overlapped = self.get_temporal_overlapped()
-        _during = self.get_temporal_during()
-        _contains = self.get_temporal_contains()
-
-        print " +-------------------- Temporal Topology -------------------------------------+"
-        #          0123456789012345678901234567890
-        if _next is not None:
-            print " | Next: ...................... " + str(_next.get_id())
-        if _prev is not None:
-            print " | Previous: .................. " + str(_prev.get_id())
-        if _equal is not None:
-            print " | Equivalent: ................ " + \
-                self._generate_map_list_string(_equal)
-        if _follows is not None:
-            print " | Follows: ................... " + \
-                self._generate_map_list_string(_follows)
-        if _precedes is not None:
-            print " | Precedes: .................. " + \
-                self._generate_map_list_string(_precedes)
-        if _overlaps is not None:
-            print " | Overlaps: .................. " + \
-                self._generate_map_list_string(_overlaps)
-        if _overlapped is not None:
-            print " | Overlapped: ................ " + \
-                self._generate_map_list_string(_overlapped)
-        if _during is not None:
-            print " | During: .................... " + \
-                self._generate_map_list_string(_during)
-        if _contains is not None:
-            print " | Contains: .................. " + \
-                self._generate_map_list_string(_contains)
-
-    def print_temporal_topology_shell_info(self):
-        """!Print information about this class in shell style"""
-
-        _next = self.temporal_next()
-        _prev = self.temporal_prev()
-        _equal = self.get_temporal_equivalent()
-        _follows = self.get_temporal_follows()
-        _precedes = self.get_temporal_precedes()
-        _overlaps = self.get_temporal_overlaps()
-        _overlapped = self.get_temporal_overlapped()
-        _during = self.get_temporal_during()
-        _contains = self.get_temporal_contains()
-
-        if _next is not None:
-            print "next=" + _next.get_id()
-        if _prev is not None:
-            print "prev=" + _prev.get_id()
-        if _equal is not None:
-            print "equivalent=" + self._generate_map_list_string(_equal, False)
-        if _follows is not None:
-            print "follows=" + self._generate_map_list_string(_follows, False)
-        if _precedes is not None:
-            print "precedes=" + self._generate_map_list_string(
-                _precedes, False)
-        if _overlaps is not None:
-            print "overlaps=" + self._generate_map_list_string(
-                _overlaps, False)
-        if _overlapped is not None:
-            print "overlapped=" + \
-                self._generate_map_list_string(_overlapped, False)
-        if _during is not None:
-            print "during=" + self._generate_map_list_string(_during, False)
-        if _contains is not None:
-            print "contains=" + self._generate_map_list_string(
-                _contains, False)
-
-###############################################################################
-
-
-class AbstractMapDataset(TemporalMapRelations):
+class AbstractMapDataset(AbstractTemporalDataset):
     """!This is the base class for all maps (raster, vector, raster3d)
        providing additional function to set the valid time and the spatial extent.
     """
     def __init__(self):
-        TemporalMapRelations.__init__(self)
+        AbstractTemporalDataset.__init__(self)
 
     def get_new_stds_instance(self, ident):
         """!Return a new space time dataset instance in which maps
@@ -552,6 +195,8 @@ class AbstractMapDataset(TemporalMapRelations):
             self.absolute_time.print_info()
         if self.is_time_relative():
             self.relative_time.print_info()
+        if self.is_topology_build():
+            self.print_topology_info()
         self.spatial_extent.print_info()
         self.metadata.print_info()
         datasets = self.get_registered_datasets()
@@ -568,8 +213,6 @@ class AbstractMapDataset(TemporalMapRelations):
                     string += ",%s" % ds["id"]
                 count += 1
         print " | Registered datasets ........ " + string
-        if self.is_temporal_topology_build():
-            self.print_temporal_topology_info()
         print " +----------------------------------------------------------------------------+"
 
     def print_shell_info(self):
@@ -593,8 +236,8 @@ class AbstractMapDataset(TemporalMapRelations):
                 count += 1
             print "registered_datasets=" + string
 
-        if self.is_temporal_topology_build():
-            self.print_temporal_topology_shell_info()
+        if self.is_topology_build():
+            self.print_topology_shell_info()
 
     def insert(self, dbif=None, execute=True):
         """!Insert temporal dataset entry into database from the internal structure

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 83 - 228
lib/python/temporal/abstract_space_time_dataset.py


+ 574 - 0
lib/python/temporal/abstract_temporal_dataset.py

@@ -0,0 +1,574 @@
+# -*- coding: utf-8 -*-
+"""!@package grass.temporal
+
+@brief GRASS Python scripting module (temporal GIS functions)
+
+Temporal GIS related functions to be used in temporal GIS Python library package.
+
+Usage:
+
+>>> import grass.temporal as tgis
+>>> tmr = tgis.AbstractTemporalDataset()
+
+(C) 2008-2011 by the GRASS Development Team
+This program is free software under the GNU General Public
+License (>=v2). Read the file COPYING that comes with GRASS
+for details.
+
+@author Soeren Gebbert
+"""
+from abstract_dataset import *
+from datetime_math import *
+
+
+class AbstractTemporalDataset(AbstractDataset):
+    """!This class implements a temporal topology access structure for an abstract dataset
+
+       This object will be set up by temporal topology creation method provided by the 
+       TemporallyTopologyBuilder.
+
+       If correctly initialize the calls next() and prev() 
+       let the user walk temporally forward and backward in time.
+
+       The following temporal relations with access methods are supported:
+       * equal
+       * follows
+       * precedes
+       * overlaps
+       * overlapped
+       * during (including starts, finishes)
+       * contains (including started, finished)
+       * starts
+       * started
+       * finishes
+       * finished
+
+
+       @code:
+       # We have build the temporal topology and we know the first map
+       start = first
+       while start:
+
+           # Print all maps this map temporally contains
+           dlist = start.get_contains()
+           for map in dlist:
+               map.print_info()
+
+           start = start.next()
+         @endcode  
+        
+        Usage:
+        
+        @code
+        
+        >>> tmr = AbstractTemporalDataset()
+        >>> tmr.print_topology_info()
+         +-------------------- Temporal Topology -------------------------------------+
+        >>> tmr.print_topology_shell_info()
+        
+        @endcode
+    """
+
+    def __init__(self):
+        AbstractDataset.__init__(self)
+        self.reset_topology()
+
+    def reset_topology(self):
+        """!Reset any information about temporal topology"""
+        self._topology = {}
+        self._has_topology = False
+        
+    def get_number_of_relations(self):      
+        """! Return a dictionary in which the keys are the relation names and the value
+        are the number of relations.
+        
+        The following relations are available:
+        * equal
+        * follows
+        * precedes
+        * overlaps
+        * overlapped
+        * during (including starts, finishes)
+        * contains (including started, finished)
+        * starts
+        * started
+        * finishes
+        * finished
+        
+        To access topological information the temporal topology must be build first
+        using the TemporalTopologyBuilder.
+        
+        @return the dictionary with relations as keys and number as values or None in case the topology wasn't build
+        """
+        if self._has_topology == False:
+            return None
+    
+        relations = {}
+        try:
+            relations["equal"] = len(self._topology["EQUAL"]) 
+        except:
+            relations["equal"] = 0
+        try: 
+            relations["follows"] = len(self._topology["FOLLOWS"]) 
+        except: 
+            relations["follows"] = 0
+        try: 
+            relations["precedes"] = len(self._topology["PRECEDES"])
+        except: 
+            relations["precedes"] = 0
+        try: 
+            relations["overlaps"] = len(self._topology["OVERLAPS"])
+        except: 
+            relations["overlaps"] = 0
+        try: 
+            relations["overlapped"] = len(self._topology["OVERLAPPED"])
+        except: 
+            relations["overlapped"] = 0
+        try: 
+            relations["during"] = len(self._topology["DURING"])
+        except: 
+            relations["during"] = 0
+        try: 
+            relations["contains"] = len(self._topology["CONTAINS"])
+        except: 
+            relations["contains"] = 0
+        try: 
+            relations["starts"] = len(self._topology["STARTS"])
+        except: 
+            relations["starts"] = 0
+        try:    
+            relations["started"] = len(self._topology["STARTED"])
+        except: 
+            relations["started"] = 0
+        try: 
+            relations["finishes"] = len(self._topology["FINISHES"])
+        except: 
+            relations["finishes"] = 0
+        try: 
+            relations["finished"] = len(self._topology["FINISHED"])
+        except: 
+            relations["finished"] = 0
+            
+        return relations
+
+    def set_topology_build_true(self):
+        """!Same as name"""
+        self._has_topology = True
+
+    def set_topology_build_false(self):
+        """!Same as name"""
+        self._has_topology = False
+
+    def is_topology_build(self):
+        """!Check if the temporal topology was build"""
+        return self._has_topology
+
+    def set_next(self, map_):
+        """!Set the map that is temporally as closest located after this map.
+
+           Temporally located means that the start time of the "next" map is
+           temporally located AFTER the start time of this map, but temporally
+           near than other maps of the same dataset.
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        self._topology["NEXT"] = map_
+
+    def set_prev(self, map_):
+        """!Set the map that is temporally as closest located before this map.
+
+           Temporally located means that the start time of the "previous" map is
+           temporally located BEFORE the start time of this map, but temporally
+           near than other maps of the same dataset.
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        self._topology["PREV"] = map_
+
+    def next(self):
+        """!Return the map with a start time temporally located after
+           the start time of this map, but temporal closer than other maps
+
+           @return A map object or None
+        """
+        if "NEXT" not in self._topology:
+            return None
+        return self._topology["NEXT"]
+
+    def prev(self):
+        """!Return the map with a start time temporally located before
+           the start time of this map, but temporal closer than other maps
+
+           @return A map object or None
+        """
+        if "PREV" not in self._topology:
+            return None
+        return self._topology["PREV"]
+
+    def append_equivalent(self, map_):
+        """!Append a map with equivalent temporal extent as this map
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "EQUAL" not in self._topology:
+            self._topology["EQUAL"] = []
+        self._topology["EQUAL"].append(map_)
+
+    def get_equivalent(self):
+        """!Return a list of map objects with equivalent temporal extent as this map
+
+           @return A list of map objects or None
+        """
+        if "EQUAL" not in self._topology:
+            return None
+        return self._topology["EQUAL"]
+
+    def append_starts(self, map_):
+        """!Append a map that this map temporally starts with
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "STARTS" not in self._topology:
+            self._topology["STARTS"] = []
+        self._topology["STARTS"].append(map_)
+
+    def get_starts(self):
+        """!Return a list of map objects that this map temporally starts with
+
+           @return A list of map objects or None
+        """
+        if "STARTS" not in self._topology:
+            return None
+        return self._topology["STARTS"]
+
+    def append_started(self, map_):
+        """!Append a map that this map temporally started with
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "STARTED" not in self._topology:
+            self._topology["STARTED"] = []
+        self._topology["STARTED"].append(map_)
+
+    def get_started(self):
+        """!Return a list of map objects that this map temporally started with
+
+           @return A list of map objects or None
+        """
+        if "STARTED" not in self._topology:
+            return None
+        return self._topology["STARTED"]
+
+    def append_finishes(self, map_):
+        """!Append a map that this map temporally finishes with
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "FINISHES" not in self._topology:
+            self._topology["FINISHES"] = []
+        self._topology["FINISHES"].append(map_)
+
+    def get_finishes(self):
+        """!Return a list of map objects that this map temporally finishes with
+
+           @return A list of map objects or None
+        """
+        if "FINISHES" not in self._topology:
+            return None
+        return self._topology["FINISHES"]
+
+    def append_finished(self, map_):
+        """!Append a map that this map temporally finished with
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "FINISHED" not in self._topology:
+            self._topology["FINISHED"] = []
+        self._topology["FINISHED"].append(map_)
+
+    def get_finished(self):
+        """!Return a list of map objects that this map temporally finished with
+
+           @return A list of map objects or None
+        """
+        if "FINISHED" not in self._topology:
+            return None
+        return self._topology["FINISHED"]
+
+    def append_overlaps(self, map_):
+        """!Append a map that this map temporally overlaps
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "OVERLAPS" not in self._topology:
+            self._topology["OVERLAPS"] = []
+        self._topology["OVERLAPS"].append(map_)
+
+    def get_overlaps(self):
+        """!Return a list of map objects that this map temporally overlaps
+
+           @return A list of map objects or None
+        """
+        if "OVERLAPS" not in self._topology:
+            return None
+        return self._topology["OVERLAPS"]
+
+    def append_overlapped(self, map_):
+        """!Append a map that this map temporally overlapped
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "OVERLAPPED" not in self._topology:
+            self._topology["OVERLAPPED"] = []
+        self._topology["OVERLAPPED"].append(map_)
+
+    def get_overlapped(self):
+        """!Return a list of map objects that this map temporally overlapped
+
+           @return A list of map objects or None
+        """
+        if "OVERLAPPED" not in self._topology:
+            return None
+        return self._topology["OVERLAPPED"]
+
+    def append_follows(self, map_):
+        """!Append a map that this map temporally follows
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "FOLLOWS" not in self._topology:
+            self._topology["FOLLOWS"] = []
+        self._topology["FOLLOWS"].append(map_)
+
+    def get_follows(self):
+        """!Return a list of map objects that this map temporally follows
+
+           @return A list of map objects or None
+        """
+        if "FOLLOWS" not in self._topology:
+            return None
+        return self._topology["FOLLOWS"]
+
+    def append_precedes(self, map_):
+        """!Append a map that this map temporally precedes
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "PRECEDES" not in self._topology:
+            self._topology["PRECEDES"] = []
+        self._topology["PRECEDES"].append(map_)
+
+    def get_precedes(self):
+        """!Return a list of map objects that this map temporally precedes
+
+           @return A list of map objects or None
+        """
+        if "PRECEDES" not in self._topology:
+            return None
+        return self._topology["PRECEDES"]
+
+    def append_during(self, map_):
+        """!Append a map that this map is temporally located during
+           This includes temporal relationships starts and finishes
+
+           @param map_: This object should be of type 
+                        AbstractMapDataset or derived classes
+        """
+        if "DURING" not in self._topology:
+            self._topology["DURING"] = []
+        self._topology["DURING"].append(map_)
+
+    def get_during(self):
+        """!Return a list of map objects that this map is temporally located during
+           This includes temporally relationships starts and finishes
+
+           @return A list of map objects or None
+        """
+        if "DURING" not in self._topology:
+            return None
+        return self._topology["DURING"]
+
+    def append_contains(self, map_):
+        """!Append a map that this map temporally contains
+           This includes temporal relationships started and finished
+
+           @param map_: This object should be of type AbstractMapDataset 
+                        or derived classes
+        """
+        if "CONTAINS" not in self._topology:
+            self._topology["CONTAINS"] = []
+        self._topology["CONTAINS"].append(map_)
+
+    def get_contains(self):
+        """!Return a list of map objects that this map temporally contains
+           This includes temporal relationships started and finished
+
+           @return A list of map objects or None
+        """
+        if "CONTAINS" not in self._topology:
+            return None
+        return self._topology["CONTAINS"]
+
+    def _generate_map_list_string(self, map_list, line_wrap=True):
+        count = 0
+        string = ""
+        for map_ in map_list:
+            if line_wrap and count > 0 and count % 3 == 0:
+                string += "\n | ............................ "
+                count = 0
+            if count == 0:
+                string += map_.get_id()
+            else:
+                string += ",%s" % map_.get_id()
+            count += 1
+
+        return string
+    
+    # Set the properties
+    equivalent = property(fget=get_equivalent, 
+                                       fset=append_equivalent)
+    follows = property(fget=get_follows, 
+                                    fset=append_follows)
+    precedes = property(fget=get_precedes, 
+                                     fset=append_precedes)
+    overlaps = property(fget=get_overlaps, 
+                                     fset=append_overlaps)
+    overlapped = property(fget=get_overlapped, 
+                                       fset=append_overlapped)
+    during = property(fget=get_during, 
+                                   fset=append_during)
+    contains = property(fget=get_contains, 
+                                     fset=append_contains)
+    starts = property(fget=get_starts, 
+                                     fset=append_starts)
+    started = property(fget=get_started, 
+                                     fset=append_started)
+    finishes = property(fget=get_finishes, 
+                                     fset=append_finishes)
+    finished = property(fget=get_finished, 
+                                     fset=append_finished)
+
+    def print_topology_info(self):
+        """!Print information about this class in human readable style"""
+        _next = self.next()
+        _prev = self.prev()
+        _equal = self.get_equivalent()
+        _follows = self.get_follows()
+        _precedes = self.get_precedes()
+        _overlaps = self.get_overlaps()
+        _overlapped = self.get_overlapped()
+        _during = self.get_during()
+        _contains = self.get_contains()
+        _starts = self.get_starts()
+        _started = self.get_started()
+        _finishes = self.get_finishes()
+        _finished = self.get_finished()
+        
+        print " +-------------------- Temporal Topology -------------------------------------+"
+        #          0123456789012345678901234567890
+        if _next is not None:
+            print " | Next: ...................... " + str(_next.get_id())
+        if _prev is not None:
+            print " | Previous: .................. " + str(_prev.get_id())
+        if _equal is not None:
+            print " | Equivalent: ................ " + \
+                self._generate_map_list_string(_equal)
+        if _follows is not None:
+            print " | Follows: ................... " + \
+                self._generate_map_list_string(_follows)
+        if _precedes is not None:
+            print " | Precedes: .................. " + \
+                self._generate_map_list_string(_precedes)
+        if _overlaps is not None:
+            print " | Overlaps: .................. " + \
+                self._generate_map_list_string(_overlaps)
+        if _overlapped is not None:
+            print " | Overlapped: ................ " + \
+                self._generate_map_list_string(_overlapped)
+        if _during is not None:
+            print " | During: .................... " + \
+                self._generate_map_list_string(_during)
+        if _contains is not None:
+            print " | Contains: .................. " + \
+                self._generate_map_list_string(_contains)
+        if _starts is not None:
+            print " | Starts:.. .................. " + \
+                self._generate_map_list_string(_starts)
+        if _started is not None:
+            print " | Started:. .................. " + \
+                self._generate_map_list_string(_started)
+        if _finishes is not None:
+            print " | Finishes:................... " + \
+                self._generate_map_list_string(_finishes)
+        if _finished is not None:
+            print " | Finished:................... " + \
+                self._generate_map_list_string(_finished)
+
+    def print_topology_shell_info(self):
+        """!Print information about this class in shell style"""
+
+        _next = self.next()
+        _prev = self.prev()
+        _equal = self.get_equivalent()
+        _follows = self.get_follows()
+        _precedes = self.get_precedes()
+        _overlaps = self.get_overlaps()
+        _overlapped = self.get_overlapped()
+        _during = self.get_during()
+        _contains = self.get_contains()
+        _starts = self.get_starts()
+        _started = self.get_started()
+        _finishes = self.get_finishes()
+        _finished = self.get_finished()
+        
+        if _next is not None:
+            print "next=" + _next.get_id()
+        if _prev is not None:
+            print "prev=" + _prev.get_id()
+        if _equal is not None:
+            print "equivalent=" + self._generate_map_list_string(_equal, False)
+        if _follows is not None:
+            print "follows=" + self._generate_map_list_string(_follows, False)
+        if _precedes is not None:
+            print "precedes=" + self._generate_map_list_string(
+                _precedes, False)
+        if _overlaps is not None:
+            print "overlaps=" + self._generate_map_list_string(
+                _overlaps, False)
+        if _overlapped is not None:
+            print "overlapped=" + \
+                self._generate_map_list_string(_overlapped, False)
+        if _during is not None:
+            print "during=" + self._generate_map_list_string(_during, False)
+        if _contains is not None:
+            print "contains=" + self._generate_map_list_string(
+                _contains, False)
+        if _starts is not None:
+            print "starts=" + \
+                self._generate_map_list_string(_starts)
+        if _started is not None:
+            print "started=" + \
+                self._generate_map_list_string(_started)
+        if _finishes is not None:
+            print "finishes=" + \
+                self._generate_map_list_string(_finishes)
+        if _finished is not None:
+            print "finished=" + \
+                self._generate_map_list_string(_finished)
+
+###############################################################################
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()

+ 46 - 5
lib/python/temporal/core.py

@@ -110,7 +110,7 @@ def set_use_ctypes_map_access(use_ctype = True):
 
 ###############################################################################
 
-def get_use_ctypes_map_access(use_ctype = True):
+def get_use_ctypes_map_access():
     """!Return true if ctypes is used for map access """
     global use_ctypes_map_access
     return use_ctypes_map_access
@@ -135,6 +135,7 @@ def init():
     """
     # We need to set the correct database backend from the environment variables
     global tgis_backed
+    global has_command_column
     
 
     core.run_command("t.connect", flags="c")
@@ -182,8 +183,24 @@ def init():
             name = cursor.fetchone()[0]
             if name == "raster_base":
                 db_exists = True
+            
+                # Try to add the command column to the space time dataset metadata tables
+                try:
+                    c.execute('ALTER TABLE strds_metadata ADD COLUMN command VARCHAR;')
+                except:
+                    pass
+                try:
+                    c.execute('ALTER TABLE str3ds_metadata ADD COLUMN command VARCHAR;')
+                except:
+                    pass
+                try:
+                    c.execute('ALTER TABLE stvds_metadata ADD COLUMN command VARCHAR;')
+                except:
+                    pass
+                
             connection.commit()
             cursor.close()
+            
     elif tgis_backed == "pg":
         # Connect to database
         connection = dbmi.connect(database)
@@ -192,6 +209,22 @@ def init():
         cursor.execute("SELECT EXISTS(SELECT * FROM information_schema.tables "
                        "WHERE table_name=%s)", ('raster_base',))
         db_exists = cursor.fetchone()[0]
+    
+        if db_exists:
+            # Try to add the command column to the space time dataset metadata tables
+            try:
+                c.execute('ALTER TABLE strds_metadata ADD COLUMN command VARCHAR;')
+            except:
+                pass
+            try:
+                c.execute('ALTER TABLE str3ds_metadata ADD COLUMN command VARCHAR;')
+            except:
+                pass
+            try:
+                c.execute('ALTER TABLE stvds_metadata ADD COLUMN command VARCHAR;')
+            except:
+                pass
+        
         connection.commit()
         cursor.close()
 
@@ -229,11 +262,17 @@ def init():
     stvds_tables_sql = stds_tables_template_sql.replace("STDS", "stvds")
     str3ds_tables_sql = stds_tables_template_sql.replace("STDS", "str3ds")
 
-    # Connect to database
-    connection = dbmi.connect(database)
-    cursor = connection.cursor()
 
     if tgis_backed == "sqlite":
+        
+        # We need to create the sqlite3 database path if it does not exists
+        tgis_dir = os.path.dirname(database)
+        if not os.path.exists(tgis_dir):
+            os.makedirs(tgis_dir)
+            
+        # Connect to database
+        connection = dbmi.connect(database)
+        cursor = connection.cursor()
 
         sqlite3_delete_trigger_sql = open(os.path.join(get_sql_template_path(
         ), "sqlite3_delete_trigger.sql"), 'r').read()
@@ -255,6 +294,9 @@ def init():
         cursor.executescript(str3ds_metadata_sql)
         cursor.executescript(sqlite3_delete_trigger_sql)
     elif tgis_backed == "pg":
+        # Connect to database
+        connection = dbmi.connect(database)
+        cursor = connection.cursor()
         # Execute the SQL statements for postgresql
         # Create the global tables for the native grass datatypes
         cursor.execute(raster_tables_sql)
@@ -276,7 +318,6 @@ def init():
 
 ###############################################################################
 
-
 class SQLDatabaseInterfaceConnection():
     """!This class represents the database interface connection
 

+ 19 - 1
lib/python/temporal/metadata.py

@@ -891,13 +891,14 @@ class STDSMetadataBase(SQLDatabaseInterface):
         
         @endcode
     """
-    def __init__(self, table=None, ident=None, title=None, description=None):
+    def __init__(self, table=None, ident=None, title=None, description=None, command=None):
 
         SQLDatabaseInterface.__init__(self, table, ident)
 
         self.set_id(ident)
         self.set_title(title)
         self.set_description(description)
+        self.set_command(command)
         # No setter for this
         self.D["number_of_maps"] = None
 
@@ -914,6 +915,10 @@ class STDSMetadataBase(SQLDatabaseInterface):
         """!Set the number of cols"""
         self.D["description"] = description
 
+    def set_command(self, command):
+        """!Set the number of cols"""
+        self.D["command"] = command
+        
     def get_id(self):
         """!Convenient method to get the unique identifier (primary key)
            @return None if not found
@@ -939,6 +944,14 @@ class STDSMetadataBase(SQLDatabaseInterface):
         else:
             return None
 
+    def get_command(self):
+        """!Get command
+           @return None if not found"""
+        if "command" in self.D:
+            return self.D["command"]
+        else:
+            return None
+            
     def get_number_of_maps(self):
         """!Get the number of registered maps, 
            this value is set in the database
@@ -963,6 +976,11 @@ class STDSMetadataBase(SQLDatabaseInterface):
         print " | " + str(self.get_title())
         print " | Description:"
         print " | " + str(self.get_description())
+        print " | Command of creation:"
+        command = self.get_command()
+        if command:
+            for token in command.split("\n"):
+                print " | " + str(token)
 
     def print_shell_info(self):
         """!Print information about this class in shell style"""

+ 0 - 98
lib/python/temporal/space_time_datasets.py

@@ -968,104 +968,6 @@ class SpaceTimeVectorDataset(AbstractSpaceTimeDataset):
 
 ###############################################################################
 
-
-class AbstractDatasetComparisonKeyStartTime(object):
-    """!This comparison key can be used to sort lists of abstract datasets 
-       by start time
-
-        Example:
-
-        # Return all maps in a space time raster dataset as map objects
-        map_list = strds.get_registered_maps_as_objects()
-
-        # Sort the maps in the list by start time
-        sorted_map_list = sorted(
-            map_list, key=AbstractDatasetComparisonKeyStartTime)
-    """
-    def __init__(self, obj, *args):
-        self.obj = obj
-
-    def __lt__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return startA < startB
-
-    def __gt__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return startA > startB
-
-    def __eq__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return startA == startB
-
-    def __le__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return startA <= startB
-
-    def __ge__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return startA >= startB
-
-    def __ne__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return startA != startB
-
-###############################################################################
-
-
-class AbstractDatasetComparisonKeyEndTime(object):
-    """!This comparison key can be used to sort lists of abstract datasets 
-       by end time
-
-        Example:
-
-        # Return all maps in a space time raster dataset as map objects
-        map_list = strds.get_registered_maps_as_objects()
-
-        # Sort the maps in the list by end time
-        sorted_map_list = sorted(
-            map_list, key=AbstractDatasetComparisonKeyEndTime)
-    """
-    def __init__(self, obj, *args):
-        self.obj = obj
-
-    def __lt__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return endA < endB
-
-    def __gt__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return endA > endB
-
-    def __eq__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return endA == endB
-
-    def __le__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return endA <= endB
-
-    def __ge__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return endA >= endB
-
-    def __ne__(self, other):
-        startA, endA = self.obj.get_valid_time()
-        startB, endB = other.obj.get_valid_time()
-        return endA != endB
-
-###############################################################################
-
 if __name__ == "__main__":
     import doctest
     doctest.testmod()

+ 5 - 0
lib/python/temporal/temporal_granularity.py

@@ -34,6 +34,7 @@ def compute_relative_time_granularity(maps):
         Hence a correct temporal topology is required for computation.
 
         @param maps: a ordered by start_time list of map objects
+        @return An integer
     """
 
     # The interval time must be scaled to days resolution
@@ -84,8 +85,12 @@ def compute_absolute_time_granularity(maps):
         Attention: The computation of the granularity 
         is only correct in case of not overlapping intervals. 
         Hence a correct temporal topology is required for computation.
+        
+        The computed granularity is returned as number of seconds or minutes or hours
+        or days or months or years. 
 
         @param maps: a ordered by start_time list of map objects
+        @return The temporal topology as string "integer unit"
     """
 
     has_seconds = False

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 445 - 201
lib/python/temporal/temporal_relationships.py


+ 27 - 31
lib/python/temporal/unit_tests.py

@@ -1626,19 +1626,18 @@ def test_1d_rtree():
 
     for i in xrange(10):
         
-        rect = vector.RTree_Rect()
-        # Allocate the boundary
-        vector.RTreeAllocBoundary(byref(rect), tree)
-        vector.RTreeSetRect1D(byref(rect), tree, float(i - 2), float(i + 2))
-        vector.RTreeInsertRect(byref(rect), i + 1, tree)
+        rect = vector.RTreeAllocRect(tree)
+        vector.RTreeSetRect1D(rect, tree, float(i - 2), float(i + 2))
+        vector.RTreeInsertRect(rect, i + 1, tree)
 
-    rect = vector.RTree_Rect()
-    vector.RTreeAllocBoundary(byref(rect), tree)
-    vector.RTreeSetRect1D(byref(rect), tree, 2.0, 7.0)
+    rect = vector.RTreeAllocRect(tree)
+    vector.RTreeSetRect1D(rect, tree, 2.0, 7.0)
 
     list_ = gis.ilist()
 
-    num = vector.RTreeSearch2(tree, byref(rect), byref(list_))
+    num = vector.RTreeSearch2(tree, rect, byref(list_))
+    
+    vector.RTreeFreeRect(rect)
 
     # print rectangle ids
     print "Number of overlapping rectangles", num
@@ -1656,22 +1655,21 @@ def test_2d_rtree():
 
     for i in xrange(10):
         
-        rect = vector.RTree_Rect()
-        # Allocate the boundary
-        vector.RTreeAllocBoundary(byref(rect), tree)
+        
+        rect = vector.RTreeAllocRect(tree)
 
-        vector.RTreeSetRect2D(byref(rect), tree, 
+        vector.RTreeSetRect2D(rect, tree, 
                               float(i - 2), float(i + 2), 
                               float(i - 2), float(i + 2))
-        vector.RTreeInsertRect(byref(rect), i + 1, tree)
-
-    rect = vector.RTree_Rect()
-    vector.RTreeAllocBoundary(byref(rect), tree)
-    vector.RTreeSetRect2D(byref(rect), tree, 2.0, 7.0, 2.0, 7.0)
+        vector.RTreeInsertRect(rect, i + 1, tree)
+    
+    rect = vector.RTreeAllocRect(tree)
+    vector.RTreeSetRect2D(rect, tree, 2.0, 7.0, 2.0, 7.0)
 
     list_ = gis.ilist()
 
-    num = vector.RTreeSearch2(tree, byref(rect), byref(list_))
+    num = vector.RTreeSearch2(tree, rect, byref(list_))
+    vector.RTreeFreeRect(rect)
 
     # print rectangle ids
     print "Number of overlapping rectangles", num
@@ -1689,26 +1687,24 @@ def test_3d_rtree():
 
     for i in xrange(10):
         
-        rect = vector.RTree_Rect()
-        # Allocate the boundary
-        vector.RTreeAllocBoundary(byref(rect), tree)
-        vector.RTreeSetRect3D(byref(rect), tree, 
+        rect = vector.RTreeAllocRect(tree)
+        vector.RTreeSetRect3D(rect, tree, 
                               float(i - 2), float(i + 2), 
                               float(i - 2), float(i + 2), 
                               float(i - 2), float(i + 2))
-        vector.RTreeInsertRect(byref(rect), i + 1, tree)
+        vector.RTreeInsertRect(rect, i + 1, tree)
         print i + 1
-        vector.RTreePrintRect(byref(rect), 1, tree)
+        vector.RTreePrintRect(rect, 1, tree)
 
-    rect = vector.RTree_Rect()
-    vector.RTreeAllocBoundary(byref(rect), tree)
-    vector.RTreeSetRect3D(byref(rect), tree, 2.0, 7.0, 2.0, 7.0, 2.0, 7.0)
+    rect = vector.RTreeAllocRect(tree)
+    vector.RTreeSetRect3D(rect, tree, 2.0, 7.0, 2.0, 7.0, 2.0, 7.0)
     print "Select"
-    vector.RTreePrintRect(byref(rect), 1, tree)
+    vector.RTreePrintRect(rect, 1, tree)
         
     list_ = gis.ilist()
 
-    num = vector.RTreeSearch2(tree, byref(rect), byref(list_))
+    num = vector.RTreeSearch2(tree, rect, byref(list_))
+    vector.RTreeFreeRect(rect)
 
     # print rectangle ids
     print "Number of overlapping rectangles", num
@@ -1758,7 +1754,7 @@ if __name__ == "__main__":
     test_increment_datetime_by_string()
     test_adjust_datetime_to_granularity()
     test_spatial_extent_intersection()
-    #test_compute_relative_time_granularity()
+    test_compute_relative_time_granularity()
     test_compute_absolute_time_granularity()
     test_compute_datetime_delta()
     test_spatial_extent_intersection()

+ 19 - 17
lib/temporal/SQL/str3ds_metadata_table.sql

@@ -1,5 +1,5 @@
 --#############################################################################
+-- This SQL script generates the space time 3D raster dataset metadata table,
 -- view and trigger
 --
 -- Author: Soeren Gebbert soerengebbert <at> googlemail <dot> com
@@ -8,21 +8,22 @@
 --PRAGMA foreign_keys = ON;
 
 CREATE TABLE  str3ds_metadata (
-  id VARCHAR NOT NULL,          -- Id of the space-time raster3d dataset, this is the primary foreign key
-  raster3d_register VARCHAR,    -- The id of the table in which the raster3d maps are registered for this dataset
-  number_of_maps INTEGER,       -- The number of registered raster3d maps
-  max_min DOUBLE PRECISION,     -- The minimal maximum of the registered raster3d maps
-  min_min DOUBLE PRECISION,     -- The minimal minimum of the registered raster3d maps
-  max_max DOUBLE PRECISION,     -- The maximal maximum of the registered raster3d maps
-  min_max DOUBLE PRECISION,     -- The maximal minimum of the registered raster3d maps
-  nsres_min DOUBLE PRECISION,   -- The lowest north-south resolution of the registered raster3d maps
-  nsres_max DOUBLE PRECISION,   -- The highest north-south resolution of the registered raster3d maps
-  ewres_min DOUBLE PRECISION,   -- The lowest east-west resolution of the registered raster3d maps
-  ewres_max DOUBLE PRECISION,   -- The highest east-west resolution of the registered raster3d maps
-  tbres_min DOUBLE PRECISION,   -- The lowest top-bottom resolution of the registered raster3d maps
-  tbres_max DOUBLE PRECISION,   -- The highest top-bottom resolution of the registered raster3d maps
-  title VARCHAR,                -- Title of the space-time raster3d dataset
-  description VARCHAR,          -- Detailed description of the space-time raster3d dataset
+  id VARCHAR NOT NULL,          -- Id of the space time 3D raster dataset, this is the primary foreign key
+  raster3d_register VARCHAR,    -- The id of the table in which the 3D raster maps are registered for this dataset
+  number_of_maps INTEGER,       -- The number of registered 3D raster maps
+  max_min DOUBLE PRECISION,     -- The minimal maximum of the registered 3D raster maps
+  min_min DOUBLE PRECISION,     -- The minimal minimum of the registered 3D raster maps
+  max_max DOUBLE PRECISION,     -- The maximal maximum of the registered 3D raster maps
+  min_max DOUBLE PRECISION,     -- The maximal minimum of the registered 3D raster maps
+  nsres_min DOUBLE PRECISION,   -- The lowest north-south resolution of the registered 3D raster maps
+  nsres_max DOUBLE PRECISION,   -- The highest north-south resolution of the registered 3D raster maps
+  ewres_min DOUBLE PRECISION,   -- The lowest east-west resolution of the registered 3D raster maps
+  ewres_max DOUBLE PRECISION,   -- The highest east-west resolution of the registered 3D raster maps
+  tbres_min DOUBLE PRECISION,   -- The lowest top-bottom resolution of the registered 3D raster maps
+  tbres_max DOUBLE PRECISION,   -- The highest top-bottom resolution of the registered 3D raster maps
+  title VARCHAR,                -- Title of the space time 3D raster dataset
+  description VARCHAR,          -- Detailed description of the space time 3D raster dataset
+  command VARCHAR,              -- The command that was used to create the space time 3D raster dataset
   PRIMARY KEY (id),  
   FOREIGN KEY (id) REFERENCES  str3ds_base (id) ON DELETE CASCADE
 );
@@ -44,7 +45,7 @@ CREATE VIEW str3ds_view_abs_time AS SELECT
             A4.tbres_min, A4.tbres_max, 
 	    A4.min_min, A4.min_max,
 	    A4.max_min, A4.max_max,
-            A4.title, A4.description	
+            A4.title, A4.description, A4.command
 	    FROM str3ds_base A1, str3ds_absolute_time A2,  
             str3ds_spatial_extent A3, str3ds_metadata A4 WHERE A1.id = A2.id AND 
 	    A1.id = A3.id AND A1.id = A4.id;
@@ -65,7 +66,7 @@ CREATE VIEW str3ds_view_rel_time AS SELECT
             A4.tbres_min, A4.tbres_max, 
 	    A4.min_min, A4.min_max,
 	    A4.max_min, A4.max_max,
-            A4.title, A4.description	
+            A4.title, A4.description, A4.command
 	    FROM str3ds_base A1, str3ds_relative_time A2,  
             str3ds_spatial_extent A3, str3ds_metadata A4 WHERE A1.id = A2.id AND 
 	    A1.id = A3.id AND A1.id = A4.id;

+ 3 - 2
lib/temporal/SQL/strds_metadata_table.sql

@@ -21,6 +21,7 @@ CREATE TABLE  strds_metadata (
   ewres_max DOUBLE PRECISION,   -- The highest east-west resolution of the registered raster maps
   title VARCHAR,                -- Title of the space-time raster dataset
   description VARCHAR,          -- Detailed description of the space-time raster dataset
+  command VARCHAR,              -- The command that was used to create the space time raster dataset
   PRIMARY KEY (id),  
   FOREIGN KEY (id) REFERENCES  strds_base (id) ON DELETE CASCADE
 );
@@ -41,7 +42,7 @@ CREATE VIEW strds_view_abs_time AS SELECT
             A4.nsres_max, A4.ewres_max, 
 	    A4.min_min, A4.min_max,
 	    A4.max_min, A4.max_max,
-            A4.title, A4.description	
+            A4.title, A4.description, A4.command	
 	    FROM strds_base A1, strds_absolute_time A2,  
             strds_spatial_extent A3, strds_metadata A4 WHERE A1.id = A2.id AND 
 	    A1.id = A3.id AND A1.id = A4.id;
@@ -61,7 +62,7 @@ CREATE VIEW strds_view_rel_time AS SELECT
             A4.nsres_max, A4.ewres_max, 
 	    A4.min_min, A4.min_max,
 	    A4.max_min, A4.max_max,
-            A4.title, A4.description	
+            A4.title, A4.description, A4.command
 	    FROM strds_base A1, strds_relative_time A2,  
             strds_spatial_extent A3, strds_metadata A4 WHERE A1.id = A2.id AND 
 	    A1.id = A3.id AND A1.id = A4.id;

+ 8 - 7
lib/temporal/SQL/stvds_metadata_table.sql

@@ -8,11 +8,12 @@
 --PRAGMA foreign_keys = ON;
 
 CREATE TABLE  stvds_metadata (
-  id VARCHAR NOT NULL,                -- Name of the space-time vector dataset, this is the primary foreign key
-  vector_register VARCHAR,                    -- The id of the table in which the vector maps are registered for this dataset
-  number_of_maps INTEGER,          -- The number of registered vector maps
-  title VARCHAR,                              -- Title of the space-time vector dataset
-  description VARCHAR,                        -- Detailed description of the space-time vector dataset
+  id VARCHAR NOT NULL,    -- Name of the space-time vector dataset, this is the primary foreign key
+  vector_register VARCHAR,-- The id of the table in which the vector maps are registered for this dataset
+  number_of_maps INTEGER, -- The number of registered vector maps
+  title VARCHAR,          -- Title of the space-time vector dataset
+  description VARCHAR,    -- Detailed description of the space-time vector dataset
+  command VARCHAR,        -- The command that was used to create the space time vector dataset
   points INTEGER,         -- The number of points accumulated from all registered maps
   lines INTEGER,          -- The number of lines accumulated from all registered maps
   boundaries INTEGER,     -- The number of boundaries accumulated from all registered maps
@@ -42,7 +43,7 @@ CREATE VIEW stvds_view_abs_time AS SELECT
 	    A3.north, A3.south, A3.east, A3.west, A3.proj,
 	    A4.vector_register,
 	    A4.number_of_maps, 
-            A4.title, A4.description, A4.points, A4.lines,
+            A4.title, A4.description, A4.command, A4.points, A4.lines,
             A4.boundaries, A4.centroids, A4.faces, A4.kernels,
             A4.primitives, A4.nodes, A4.areas, A4.islands,
             A4.holes, A4.volumes
@@ -61,7 +62,7 @@ CREATE VIEW stvds_view_rel_time AS SELECT
 	    A3.north, A3.south, A3.east, A3.west, A3.proj,
 	    A4.vector_register,
 	    A4.number_of_maps, 
-            A4.title, A4.description, A4.points, A4.lines,
+            A4.title, A4.description, A4.command, A4.points, A4.lines,
             A4.boundaries, A4.centroids, A4.faces, A4.kernels,
             A4.primitives, A4.nodes, A4.areas, A4.islands,
             A4.holes, A4.volumes

+ 1 - 1
lib/temporal/lib/default_name.c

@@ -66,7 +66,7 @@ int tgis_set_default_connection(void)
 
 	connection.driverName = "sqlite";
 	connection.databaseName =
-	    "$GISDBASE/$LOCATION_NAME/PERMANENT/tgis.db";
+	    "$GISDBASE/$LOCATION_NAME/PERMANENT/tgis/sqlite.db";
 	tgis_set_connection(&connection);
     }
     else

+ 36 - 35
temporal/t.topology/t.topology.py

@@ -94,16 +94,16 @@ def main():
         #      0123456789012345678901234567890
         print " | Temporal topology is: ...... invalid"
 
-    dict = sp.count_temporal_types(maps)
+    dict_ = sp.count_temporal_types(maps)
 
-    for key in dict.keys():
+    for key in dict_.keys():
         if key == "interval":
             #      0123456789012345678901234567890
-            print " | Number of intervals: ....... %s" % (dict[key])
+            print " | Number of intervals: ....... %s" % (dict_[key])
         if key == "point":
-            print " | Number of points: .......... %s" % (dict[key])
+            print " | Number of points: .......... %s" % (dict_[key])
         if key == "invalid":
-            print " | Invalid time stamps: ....... %s" % (dict[key])
+            print " | Invalid time stamps: ....... %s" % (dict_[key])
 
     #      0123456789012345678901234567890
     print " | Number of gaps: ............ %i" % sp.count_gaps(maps)
@@ -115,36 +115,37 @@ def main():
     print " | Granularity: ............... %s" % str(gran)
 
     print " +-------------------- Topological relations ---------------------------------+"
-    dict = sp.count_temporal_relations(maps)
-
-    for key in dict.keys():
-        if key == "equivalent":
-            #      0123456789012345678901234567890
-            print " | Equivalent: ................ %s" % (dict[key])
-        if key == "during":
-            print " | During: .................... %s" % (dict[key])
-        if key == "contains":
-            print " | Contains: .................. %s" % (dict[key])
-        if key == "overlaps":
-            print " | Overlaps: .................. %s" % (dict[key])
-        if key == "overlapped":
-            print " | Overlapped: ................ %s" % (dict[key])
-        if key == "after":
-            print " | After: ..................... %s" % (dict[key])
-        if key == "before":
-            print " | Before: .................... %s" % (dict[key])
-        if key == "starts":
-            print " | Starts: .................... %s" % (dict[key])
-        if key == "finishes":
-            print " | Finishes: .................. %s" % (dict[key])
-        if key == "started":
-            print " | Started: ................... %s" % (dict[key])
-        if key == "finished":
-            print " | Finished: .................. %s" % (dict[key])
-        if key == "follows":
-            print " | Follows: ................... %s" % (dict[key])
-        if key == "precedes":
-            print " | Precedes: .................. %s" % (dict[key])
+    dict_ = sp.count_temporal_relations(maps)
+
+    if dict_:
+        for key in dict_.keys():
+            if key == "equivalent":
+                #      0123456789012345678901234567890
+                print " | Equivalent: ................ %s" % (dict_[key])
+            if key == "during":
+                print " | During: .................... %s" % (dict_[key])
+            if key == "contains":
+                print " | Contains: .................. %s" % (dict_[key])
+            if key == "overlaps":
+                print " | Overlaps: .................. %s" % (dict_[key])
+            if key == "overlapped":
+                print " | Overlapped: ................ %s" % (dict_[key])
+            if key == "after":
+                print " | After: ..................... %s" % (dict_[key])
+            if key == "before":
+                print " | Before: .................... %s" % (dict_[key])
+            if key == "starts":
+                print " | Starts: .................... %s" % (dict_[key])
+            if key == "finishes":
+                print " | Finishes: .................. %s" % (dict_[key])
+            if key == "started":
+                print " | Started: ................... %s" % (dict_[key])
+            if key == "finished":
+                print " | Finished: .................. %s" % (dict_[key])
+            if key == "follows":
+                print " | Follows: ................... %s" % (dict_[key])
+            if key == "precedes":
+                print " | Precedes: .................. %s" % (dict_[key])
     print " +----------------------------------------------------------------------------+"
 
 if __name__ == "__main__":

+ 3 - 3
temporal/t.topology/test.t.topology.abstime.sh

@@ -1,5 +1,5 @@
 #!/bin/sh
-# Tests the temporaly topology module of space time datasets 
+# Tests the temporal topology module of space time datasets 
 
 # We need to set a specific region in the
 # @preprocess step of this test. 
@@ -44,10 +44,10 @@ EOF
 
 cat > "${n3}" << EOF
 prec_1|2001-01-01|2001-04-01
-prec_2|2001-05-01|2001-07-01
+prec_2|2001-05-01|2001-10-01
 prec_3|2001-08-01|2001-10-01
 prec_4|2001-11-01|2002-01-01
-prec_5|2002-02-01|2002-04-01
+prec_5|2001-11-01|2002-04-01
 prec_6|2002-05-01|2002-07-01
 EOF