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

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Mar 22 08:21:11 EDT 2012


Author: huhabla
Date: 2012-03-22 05:21:11 -0700 (Thu, 22 Mar 2012)
New Revision: 51142

Modified:
   grass/trunk/lib/python/temporal/Makefile
   grass/trunk/lib/python/temporal/__init__.py
   grass/trunk/lib/python/temporal/abstract_dataset.py
   grass/trunk/lib/python/temporal/abstract_space_time_dataset.py
   grass/trunk/lib/python/temporal/space_time_datasets.py
   grass/trunk/lib/python/temporal/space_time_datasets_tools.py
   grass/trunk/lib/python/temporal/spatial_extent.py
   grass/trunk/lib/python/temporal/temporal_extent.py
   grass/trunk/lib/python/temporal/temporal_granularity.py
   grass/trunk/lib/python/temporal/unit_tests.py
Log:
New spatial relationship computationi. Now spatio-temporal transition relations can be computed.
Implemented spatio-temporal sampling. Support for multiple input for spatio-temporal sampling. 


Modified: grass/trunk/lib/python/temporal/Makefile
===================================================================
--- grass/trunk/lib/python/temporal/Makefile	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/Makefile	2012-03-22 12:21:11 UTC (rev 51142)
@@ -8,7 +8,7 @@
 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 unit_tests aggregation
+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
 
 PYFILES := $(patsubst %,$(DSTDIR)/%.py,$(MODULES) __init__)
 PYCFILES := $(patsubst %,$(DSTDIR)/%.pyc,$(MODULES) __init__)

Modified: grass/trunk/lib/python/temporal/__init__.py
===================================================================
--- grass/trunk/lib/python/temporal/__init__.py	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/__init__.py	2012-03-22 12:21:11 UTC (rev 51142)
@@ -10,5 +10,6 @@
 from space_time_datasets_tools import *
 from datetime_math import *
 from temporal_granularity import *
+from temporal_relationships import *
 from unit_tests import *
 from aggregation import *

Modified: grass/trunk/lib/python/temporal/abstract_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_dataset.py	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/abstract_dataset.py	2012-03-22 12:21:11 UTC (rev 51142)
@@ -47,6 +47,11 @@
         """
         raise IOError("This method must be implemented in the subclasses")
 
+    def spatial_overlapping(self, dataset):
+        """Return True if the spatial extents are overlapping"""
+
+        raise IOError("This method must be implemented in the subclasses")
+
     def print_info(self):
         """Print information about this class in human readable style"""
 	raise IOError("This method must be implemented in the subclasses")
@@ -172,11 +177,6 @@
         
         return (north, south, east, west, top, bottom)
 
-    def spatial_overlap(self, dataset):
-        """Return True if the spatial extents overlap"""
-        
-        north = self.spatial_extent.overlap(dataset.spatial_extent)
-        
     def select(self, dbif=None):
 	"""Select temporal dataset entry from database and fill up the internal structure"""
 

Modified: grass/trunk/lib/python/temporal/abstract_space_time_dataset.py
===================================================================
--- grass/trunk/lib/python/temporal/abstract_space_time_dataset.py	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/abstract_space_time_dataset.py	2012-03-22 12:21:11 UTC (rev 51142)
@@ -22,6 +22,7 @@
 """
 from abstract_dataset import *
 from temporal_granularity import *
+from temporal_relationships import *
 
 ###############################################################################
 
@@ -194,67 +195,7 @@
 
         return map_time
 
-    def print_temporal_relation_matrix(self, maps):
-        """Print the temporal relation matrix of all registered maps to stdout
-
-           The temporal relation matrix includes the temporal relations between
-           all registered maps. The relations are strings stored in a list of lists.
-           
-           @param dbif: The database interface to be used
-        """
-
-        for i in range(len(maps)):
-            reltations = ""
-            count = 0
-            for j in range(i + 1, len(maps)):
-                relation = maps[j].temporal_relation(maps[i])
-
-                # print maps[j].base.get_name(), maps[i].base.get_name(), relation
-                if count == 0:
-                    relations = relation
-                else:
-                    relations += "," + str(relation)
-                count += 1
-                # Break if the the next map follows
-                if relation == "follows":
-                    break
-                # Break if the the next map is after
-                if relation == "after":
-                    break
-            if i < len(maps) - 1:    
-                print maps[i].base.get_name(), relations    
-            else:
-                print maps[i].base.get_name()
-
-    def get_temporal_relation_matrix(self, maps):
-        """Return the temporal relation matrix of all registered maps as list of lists
-
-           The map list must be ordered by start time
-
-           The temporal relation matrix includes the temporal relations between
-           all registered maps. The relations are strings stored in a list of lists.
-           
-           @param maps: a ordered by start_time list of map objects
-        """
-
-        matrix = []
-
-        # Create the temporal relation matrix
-        # Add the map names first
-        row = []
-        for map in maps:
-            row.append(map.get_id())
-        matrix.append(row)
-
-        for mapA in maps:
-            row = []
-            for mapB in maps:
-                row.append(mapA.temporal_relation(mapB))
-            matrix.append(row)
-
-        return matrix
-
-    def count_temporal_types(self, maps):
+    def count_temporal_types(self, maps=None, dbif=None):
         """Return the temporal type of the registered maps as dictionary
 
            The map list must be ordered by start time
@@ -265,8 +206,12 @@
            * invalid  -> No valid time point or interval found
 
            @param maps: A sorted (start_time) list of abstract_dataset objects
+           @param dbif: The database interface to be used
         """
 
+        if maps == None:
+            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
+            
         time_invalid = 0
         time_point = 0
         time_interval = 0
@@ -292,13 +237,17 @@
 
         return tcount
 
-    def count_gaps(self, maps):
+    def count_gaps(self, maps=None, dbif=None):
         """Count the number of gaps between temporal neighbors
         
            @param maps: A sorted (start_time) list of abstract_dataset objects
+           @param dbif: The database interface to be used
            @return The numbers of gaps between temporal neighbors
         """
 
+        if maps == None:
+            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
+            
         gaps = 0
 
         # Check for gaps
@@ -309,36 +258,54 @@
                     gaps += 1
 
         return gaps
+        
+    def print_temporal_relation_matrix(self, maps=None, dbif=None):
+        """Print the temporal relation matrix of all registered maps to stdout
 
-    def count_temporal_relations(self, maps):
-        """Count the temporal relations between the registered maps.
+           The temporal relation matrix includes the temporal relations between
+           all registered maps. The relations are strings stored in a list of lists.
+           
+           @param maps: a ordered by start_time list of map objects
+           @param dbif: The database interface to be used
+        """
+        
+        if maps == None:
+            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
+	    
+	print_temporal_relations(maps, maps)
 
+    def get_temporal_relation_matrix(self, maps=None, dbif=None):
+        """Return the temporal relation matrix of all registered maps as list of lists
+
            The map list must be ordered by start time
 
-           @param maps: A sorted (start_time) list of abstract_dataset objects
-           @return A dictionary with counted temporal relationships
+           The temporal relation matrix includes the temporal relations between
+           all registered maps. The relations are strings stored in a list of lists.
+           
+           @param maps: a ordered by start_time list of map objects
+           @param dbif: The database interface to be used
         """
+        if maps == None:
+            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
 
-        tcount = {}
-        for i in range(len(maps)):
-            # Check for point and interval data
-            for j in range(i + 1, len(maps)):
-                relation = maps[j].temporal_relation(maps[i])
+        return get_temporal_relation_matrix(maps, maps)
 
-                if tcount.has_key(relation):
-                    tcount[relation] = tcount[relation] + 1
-                else:
-                    tcount[relation] = 1
+    def count_temporal_relations(self, maps=None, dbif=None):
+        """Count the temporal relations between the registered maps.
 
-                # Break if the the next map follows
-                if relation == "follows":
-                    break
-                # Break if the the next map is after
-                if relation == "after":
-                    break
+           The map list must be ordered by start time. Temporal relations are counted 
+           by analysing the sparse upper right side temporal relationships matrix.
 
-        return tcount
+           @param maps: A sorted (start_time) list of abstract_dataset objects
+           @param dbif: The database interface to be used
+           @return A dictionary with counted temporal relationships
+        """
+        
+        if maps == None:
+            maps = get_registered_maps_as_objects(where=None, order="start_time", dbif=dbif)
 
+        return count_temporal_relations(maps, maps)
+
     def check_temporal_topology(self, maps=None, dbif=None):
         """Check the temporal topology
 
@@ -401,10 +368,13 @@
 
         return True
 
-    def sample_by_dataset_topology(self, stds, method=None, dbif=None):
+    def sample_by_dataset(self, stds, method=None, spatial=False, dbif=None):
         """Sample this space time dataset with the temporal topology of a second space time dataset
 
            The sample dataset must have "interval" as temporal map type, so all sample maps have valid interval time.
+
+           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 with 
            "gap" map objects (id==None). Each list entry is a list of map objects
@@ -413,7 +383,7 @@
            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:
 
-           list = self.sample_by_dataset_topology(stds=sampler, method=["during","overlap","contain","equal"])    
+           list = self.sample_by_dataset(stds=sampler, method=["during","overlap","contain","equal"])    
            for entry in list:
                granule = entry["granule"]
                maplist = entry["samples"]
@@ -462,6 +432,8 @@
                             granule:  s-----------e
 
                           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 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
 
            In case nothing found None is returned
@@ -519,31 +491,35 @@
         sample_maps = stds.get_registered_maps_as_objects_with_gaps(where=None, dbif=dbif)
         
         for granule in sample_maps:
+            # Read the spatial extent
+            if spatial == True:
+                granule.spatial_extent.select(dbif)
             start, end = granule.get_valid_time()
 
             where = create_temporal_relation_sql_where_statement(start, end, use_start, \
                     use_during, use_overlap, use_contain, use_equal)  
 
-            rows = self.get_registered_maps("id", where, "start_time", dbif)
+            maps = self.get_registered_maps_as_objects(where, "start_time", dbif)
 
             result = {}
             result["granule"] = granule
-            maplist = None
+            num_samples = 0
+            maplist = []
 
-            if rows:
-                maplist = []
-                for row in rows:
-                    map = self.get_new_map_instance(row["id"])
+            if maps:
+                for map in maps:
+                    # Read the spatial extent
+                    if spatial == True:
+                        map.spatial_extent.select(dbif)
+                        # Ignore spatial disjoint maps
+                        if not granule.spatial_overlapping(map):
+                            continue
 
-                    if self.is_time_absolute():
-                        map.set_absolute_time(start, end)
-                    elif self.is_time_relative():
-                        map.set_relative_time(start, end, self.get_relative_time_unit())
-
+                    num_samples += 1
                     maplist.append(copy.copy(map))
-                result["samples"] = maplist
-            else:
-                maplist = []
+
+            # Fill with empty map in case no spatio-temporal relations found
+            if not maps or num_samples == 0:
                 map = self.get_new_map_instance(None)
 
                 if self.is_time_absolute():
@@ -552,8 +528,9 @@
                     map.set_relative_time(start, end, self.get_relative_time_unit())
 
                 maplist.append(copy.copy(map))
-                result["samples"] = maplist
 
+            result["samples"] = maplist
+
             obj_list.append(copy.copy(result))
 
         if connect == True:

Modified: grass/trunk/lib/python/temporal/space_time_datasets.py
===================================================================
--- grass/trunk/lib/python/temporal/space_time_datasets.py	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/space_time_datasets.py	2012-03-22 12:21:11 UTC (rev 51142)
@@ -64,6 +64,11 @@
         """Return the name of the C-module to set the time stamp in the file system"""
         return "r.timestamp"
 
+    def spatial_overlapping(self, dataset):
+        """Return True if the spatial extents 2d overlap"""
+        
+        return self.spatial_extent.overlap_2d(dataset.spatial_extent)
+
     def reset(self, ident):
 	"""Reset the internal structure and set the identifier"""
 	self.ident = ident
@@ -142,6 +147,14 @@
         """Return the name of the C-module to set the time stamp in the file system"""
         return "r3.timestamp"
 
+    def spatial_overlapping(self, dataset):
+        """Return True if the spatial extents overlap"""
+        
+        if self.get_type() == dataset.get_type() or dataset.get_type() == "str3ds":
+            return self.spatial_extent.overlap(dataset.spatial_extent)
+        else:
+            return self.spatial_extent.overlap_2d(dataset.spatial_extent)
+
     def reset(self, ident):
 	"""Reset the internal structure and set the identifier"""
 	self.ident = ident
@@ -228,6 +241,11 @@
         """Return the layer"""
         return self.base.get_layer()
 
+    def spatial_overlapping(self, dataset):
+        """Return True if the spatial extents 2d overlap"""
+        
+        return self.spatial_extent.overlap_2d(dataset.spatial_extent)
+
     def reset(self, ident):
 	"""Reset the internal structure and set the identifier"""
 	self.ident = ident
@@ -288,6 +306,11 @@
         """Set the name of the map register table"""
         self.metadata.set_raster_register(name)
 
+    def spatial_overlapping(self, dataset):
+        """Return True if the spatial extents 2d overlap"""
+        
+        return self.spatial_extent.overlap_2d(dataset.spatial_extent)
+ 
     def reset(self, ident):
 
 	"""Reset the internal structure and set the identifier"""
@@ -332,6 +355,14 @@
         """Set the name of the map register table"""
         self.metadata.set_raster3d_register(name)
 
+    def spatial_overlapping(self, dataset):
+        """Return True if the spatial extents overlap"""
+        
+        if self.get_type() == dataset.get_type() or dataset.get_type() == "rast3d":
+            return self.spatial_extent.overlap(dataset.spatial_extent)
+        else:
+            return self.spatial_extent.overlap_2d(dataset.spatial_extent)
+
     def reset(self, ident):
 
 	"""Reset the internal structure and set the identifier"""
@@ -376,6 +407,11 @@
         """Set the name of the map register table"""
         self.metadata.set_vector_register(name)
 
+    def spatial_overlapping(self, dataset):
+        """Return True if the spatial extents 2d overlap"""
+        
+        return self.spatial_extent.overlap_2d(dataset.spatial_extent)
+
     def reset(self, ident):
 
 	"""Reset the internal structure and set the identifier"""

Modified: grass/trunk/lib/python/temporal/space_time_datasets_tools.py
===================================================================
--- grass/trunk/lib/python/temporal/space_time_datasets_tools.py	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/space_time_datasets_tools.py	2012-03-22 12:21:11 UTC (rev 51142)
@@ -465,8 +465,8 @@
 
 ###############################################################################
 
-def sample_stds_by_stds_topology(intype, sampletype, input, sampler, header, separator, method):
-    """ Sample the input space time dataset with a sample space time dataset and print the result to stdout
+def sample_stds_by_stds_topology(intype, sampletype, inputs, sampler, header, separator, method, spatial=False):
+    """ Sample the input space time datasets with a sample space time dataset and print the result to stdout
 
         In case multiple maps are located in the current granule, the map names are separated by comma.
         
@@ -480,67 +480,82 @@
         @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 sampling (start,during,contain,overlap,equal)
+        @param method: The method to be used for temporal sampling (start,during,contain,overlap,equal)
+        @param spatial: Perform spatial overlapping check
     """
     mapset =  core.gisenv()["MAPSET"]
 
-    print intype, sampletype
+    input_list = inputs.split(",")
+    sts = []
 
-    if input.find("@") >= 0:
-        id = input
-    else:
-        id = input + "@" + mapset
+    for input in input_list:
+        if input.find("@") >= 0:
+            id = input
+        else:
+            id = input + "@" + mapset
 
-    sp = dataset_factory(intype, id)
+        st = dataset_factory(intype, id)
+        sts.append(st)
 
     if sampler.find("@") >= 0:
         sid = sampler
     else:
         sid = sampler + "@" + mapset
 
-    ssp = dataset_factory(sampletype, sid)
+    sst = dataset_factory(sampletype, sid)
 
     dbif = sql_database_interface()
     dbif.connect()
 
-    if sp.is_in_db(dbif) == False:
-        core.fatal(_("Dataset <%s> not found in temporal database") % (id))
+    for st in sts:
+        if st.is_in_db(dbif) == False:
+            core.fatal(_("Dataset <%s> not found in temporal database") % (id))
+        st.select(dbif)
 
-    if ssp.is_in_db(dbif) == False:
+    if sst.is_in_db(dbif) == False:
         core.fatal(_("Dataset <%s> not found in temporal database") % (sid))
 
-    sp.select(dbif)
-    ssp.select(dbif)
+    sst.select(dbif)
 
     if separator == None or separator == "" or separator.find(",") >= 0:
         separator = " | "
        
-    mapmatrix = sp.sample_by_dataset_topology(ssp, method, dbif)
+    mapmatrizes = []
+    for st in sts:
+        mapmatrix = st.sample_by_dataset(sst, method, spatial, dbif)
+        if mapmatrix and len(mapmatrix) > 0:
+            mapmatrizes.append(mapmatrix)
 
-    if mapmatrix and len(mapmatrix) > 0:
+    if len(mapmatrizes) > 0:
 
         if header:
             string = ""
-            string += "%s%s" % ("sample_id", separator)
-            string += "%s%s" % ("ids", separator)
+            string += "%s%s" % (sst.get_id(), separator)
+            for st in sts:
+                string += "%s%s" % (st.get_id(), separator)
             string += "%s%s" % ("start_time", separator)
             string += "%s%s" % ("end_time", separator)
             string += "%s%s" % ("interval_length", separator)
             string += "%s"   % ("distance_from_begin")
             print string
 
-        first_time, dummy = mapmatrix[0]["granule"].get_valid_time()
+        first_time, dummy = mapmatrizes[0][0]["granule"].get_valid_time()
 
-        for entry in mapmatrix:
-            mapnames = ""
-            count = 0
-            for sample in entry["samples"]:
-                if count == 0:
-                    mapnames += str(sample.get_id())
-                else:
-                    mapnames += ",%s" % str(sample.get_id())
-                count += 1
-            
+        for i in range(len(mapmatrizes[0])):
+            mapname_list = []
+            for mapmatrix in mapmatrizes:
+                mapnames = ""
+                count = 0
+                entry = mapmatrix[i]
+                for sample in entry["samples"]:
+                    if count == 0:
+                        mapnames += str(sample.get_id())
+                    else:
+                        mapnames += ",%s" % str(sample.get_id())
+                    count += 1
+                mapname_list.append(mapnames)
+                
+            entry = mapmatrizes[0][i]
             map = entry["granule"]
 
             start, end = map.get_valid_time()
@@ -557,7 +572,8 @@
 
             string = ""
             string += "%s%s" % (map.get_id(), separator)
-            string += "%s%s" % (mapnames, separator)
+            for mapnames in mapname_list:
+                string += "%s%s" % (mapnames, separator)
             string += "%s%s" % (start, separator)
             string += "%s%s" % (end, separator)
             string += "%s%s" % (delta, separator)

Modified: grass/trunk/lib/python/temporal/spatial_extent.py
===================================================================
--- grass/trunk/lib/python/temporal/spatial_extent.py	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/spatial_extent.py	2012-03-22 12:21:11 UTC (rev 51142)
@@ -31,25 +31,493 @@
         self.set_spatial_extent(north, south, east, west, top, bottom)
 	self.set_projection(proj)
         
-    def overlap_2d(self, extent):
-        """Return True if the 2d extents overlap. Code is lend from wind_overlap.c in lib/gis"""  
+    def overlapping_2d(self, extent):
+        """Return True if the two dimensional extents overlap. Code is lend from wind_overlap.c in lib/gis
         
+	   Overlapping includes the spatial relations:
+	   * contain
+	   * in
+	   * cover
+	   * covered
+	   * equivalent
+	"""  
+        
         if self.get_projection() != extent.get_projection():
-            core.error(_("Projections are different. Unable to compute overlap_2d for spatial extents"))
+            core.error(_("Projections are different. Unable to compute overlapping_2d for spatial extents"))
+            return False
         
         N = extent.get_north()
         S = extent.get_south()
         E = extent.get_east()
         W = extent.get_west()
         
+        # Adjust the east and west in case of LL projection
+        if self.get_projection() == "LL":
+            while E < self.get_west():
+                E += 360.0
+                W += 360.0
+
+            while W > self.get_east():
+                E -= 360.0
+                W -= 360.0
+                
         if(self.get_north() <= S):
             return False
         
         if(self.get_south() >= N):
             return False
+            
+        if self.get_east() <= W:
+            return False
         
+        if self.get_west() >= E:
+            return False
+        
+        return True
+
+    def overlapping(self, extent):
+        """Return True if the three dimensional extents overlap
+        
+	   Overlapping includes the spatial relations:
+	   * contain
+	   * in
+	   * cover
+	   * covered
+	   * equivalent
+        """  
+        
+        if not self.overlapping_2d(extent):
+            return False
+            
+        T = extent.get_top()
+        B = extent.get_bottom()
+        
+        if self.get_top() < B:
+            return False
+        
+        if self.get_bottom() > T:
+            return False
+        
+        return True
+
+    def intersect_2d(self, extent):
+	"""Return the two dimensional intersection as spatial_extent object or None
+	   in case no intersection was found.
+	"""
+	
+	if not self.overlapping_2d(extent):
+	    return None
+	    
+	eN = extent.get_north()
+        eS = extent.get_south()
+        eE = extent.get_east()
+        eW = extent.get_west()
+        
+	N = self.get_north()
+        S = self.get_south()
+        E = self.get_east()
+        W = self.get_west()
+        
         # Adjust the east and west in case of LL projection
-        if self.get_proj() == "LL":
+        if self.get_projection() == "LL":
+            while eE < W:
+                eE += 360.0
+                eW += 360.0
+
+            while eW > E:
+                eE -= 360.0
+                eW -= 360.0	
+                
+        # Compute the extent
+        nN = N
+        nS = S
+        nE = E
+        nW = W
+        
+        if W < eW:
+	    nW = eW
+	if E > eE:
+	    nE = eE
+	if N > eN:
+	    nN = eN
+	if S < eS:
+	    nS = eS
+	
+	
+	new = spatial_extent(north=nN, south=nS, east=nE, west=nW, top=0, bottom=0, proj=self.get_projection())
+	return new
+
+    def intersect(self, extent):
+	"""Return the three dimensional intersection as spatial_extent object or None
+	   in case no intersection was found.
+	"""
+	
+	if not self.overlapping(extent):
+	    return None
+	    
+	new = self.intersect_2d(extent)
+	
+	eT = extent.get_top()
+	eB = extent.get_bottom()
+	
+	T = self.get_top()
+	B = self.get_bottom()
+	
+	nT = T
+	nB = B
+	
+	if B < eB:
+	    nB = eB
+	if T > eT:
+	    nT = eT
+	
+	new.set_top(nT)
+	new.set_bottom(nB)
+	
+	return new
+
+    def is_in_2d(self, extent):
+	"""Check two dimensional if the self is located in extent 
+	
+         _____	
+	|A _  |
+	| |_| |
+	|_____|
+	
+	"""
+        if self.get_projection() != extent.get_projection():
+            core.error(_("Projections are different. Unable to compute is_in_2d for spatial extents"))
+            return False
+            
+	eN = extent.get_north()
+        eS = extent.get_south()
+        eE = extent.get_east()
+        eW = extent.get_west()
+        
+	N = self.get_north()
+        S = self.get_south()
+        E = self.get_east()
+        W = self.get_west()
+        
+        # Adjust the east and west in case of LL projection
+        if self.get_projection() == "LL":
+            while eE < W:
+                eE += 360.0
+                eW += 360.0
+
+            while eW > E:
+                eE -= 360.0
+                eW -= 360.0	
+               
+        if W <= eW:
+	    return False
+	if E >= eE:
+	    return False
+	if N >= eN:
+	    return False
+	if S <= eS:
+	    return False
+	
+	return True
+	
+    def is_in(self, extent):
+	"""Check three dimensional if the self is located in extent """
+	if not self.is_in_2d(extent):
+	    return False
+	
+	eT = extent.get_top()
+	eB = extent.get_bottom()
+	
+	T = self.get_top()
+	B = self.get_bottom()
+	
+	if B <= eB:
+	    return False
+	if T >= eT:
+	    return False
+	    
+	return True
+
+    def contain_2d(self, extent):
+	"""Check two dimensional if self contains extent """
+	return extent.is_in_2d(self)
+	
+    def contain(self, extent):
+	"""Check three dimensional if self contains extent """
+	return extent.is_in(self)
+        	
+    def equivalent_2d(self, extent):
+	"""Check two dimensional if self is equivalent to extent """
+
+        if self.get_projection() != extent.get_projection():
+            core.error(_("Projections are different. Unable to compute equivalent_2d for spatial extents"))
+            return False
+            
+	eN = extent.get_north()
+        eS = extent.get_south()
+        eE = extent.get_east()
+        eW = extent.get_west()
+        
+	N = self.get_north()
+        S = self.get_south()
+        E = self.get_east()
+        W = self.get_west()
+        
+        # Adjust the east and west in case of LL projection
+        if self.get_projection() == "LL":
+            while eE < W:
+                eE += 360.0
+                eW += 360.0
+
+            while eW > E:
+                eE -= 360.0
+                eW -= 360.0	
+               
+        if W != eW:
+	    return False
+	if E != eE:
+	    return False
+	if N != eN:
+	    return False
+	if S != eS:
+	    return False
+	
+	return True
+	
+    def equivalent(self, extent):
+	"""Check three dimensional if self is equivalent to extent """
+
+	if not self.equivalent_2d(extent):
+	    return False
+	
+	eT = extent.get_top()
+	eB = extent.get_bottom()
+	
+	T = self.get_top()
+	B = self.get_bottom()
+	
+	if B != eB:
+	    return False
+	if T != eT:
+	    return False
+	    
+	return True
+
+    def cover_2d(self, extent):
+        """Return True if two dimensional self covers extent 
+            _____    _____    _____    _____
+           |A  __|  |__  A|  |A | B|  |B | A|
+           |  |B |  | B|  |  |  |__|  |__|  |
+           |__|__|  |__|__|  |_____|  |_____|
+           
+            _____    _____    _____    _____
+           |A|B| |  |A  __|  |A _  |  |__  A|
+           | |_| |  |  |__|B | |B| | B|__|  |
+           |_____|  |_____|  |_|_|_|  |_____|
+           
+            _____    _____    _____    _____
+           |A|B  |  |_____|A |A|B|A|  |_____|A
+           | |   |  |B    |  | | | |  |_____|B
+           |_|___|  |_____|  |_|_|_|  |_____|A
+                            
+           The following cases are excluded:
+	   * contain
+	   * in
+	   * equivalent
+        """    
+        
+        if self.get_projection() != extent.get_projection():
+            core.error(_("Projections are different. Unable to compute cover_2d for spatial extents"))
+            return False
+	    
+	# Exclude equivalent_2d
+        if self.equivalent_2d(extent):
+	    return False
+        
+	eN = extent.get_north()
+        eS = extent.get_south()
+        eE = extent.get_east()
+        eW = extent.get_west()
+        
+	N = self.get_north()
+        S = self.get_south()
+        E = self.get_east()
+        W = self.get_west()
+        
+        
+        # Adjust the east and west in case of LL projection
+        if self.get_projection() == "LL":
+            while eE < W:
+                eE += 360.0
+                eW += 360.0
+
+            while eW > E:
+                eE -= 360.0
+                eW -= 360.0	
+                
+	# Edges of extent located outside of self are not allowed 
+        if E < eW:
+	    return False
+	if W > eE:
+	    return False
+	if N < eS:
+	    return False
+	if S > eN:
+	    return False
+         
+        # First we check that at least one edge of extent meets an edge of self
+        if W != eW and E != eE and N != eN and S != eS:
+	    return False
+	    
+	# We check that at least one edge of extent is located in self
+	edge_count = 0
+	if W < eW and E > eW:
+	    edge_count += 1
+	if E > eE and W < eE:
+	    edge_count += 1
+	if N > eN and S < eN:
+	    edge_count += 1
+	if S < eS and N > eS:
+	    edge_count += 1
+	
+	if edge_count == 0:
+	    return False
+	
+	return True
+	
+    def cover(self, extent):
+        """Return True if three dimensional self covers extent 
+     
+           The following cases are excluded:
+	   * contain
+	   * in
+	   * equivalent
+        """ 
+        	    
+        if self.get_projection() != extent.get_projection():
+            core.error(_("Projections are different. Unable to compute cover for spatial extents"))
+            return False
+	    
+	# Exclude equivalent_2d
+        if self.equivalent_2d(extent):
+	    return False
+        
+	eN = extent.get_north()
+        eS = extent.get_south()
+        eE = extent.get_east()
+        eW = extent.get_west()
+        
+        eT = extent.get_top()
+	eB = extent.get_bottom()
+        
+	N = self.get_north()
+        S = self.get_south()
+        E = self.get_east()
+        W = self.get_west()
+	
+	T = self.get_top()
+	B = self.get_bottom()
+        
+        # Adjust the east and west in case of LL projection
+        if self.get_projection() == "LL":
+            while eE < W:
+                eE += 360.0
+                eW += 360.0
+
+            while eW > E:
+                eE -= 360.0
+                eW -= 360.0	
+                
+	# Edges of extent located outside of self are not allowed 
+        if E <= eW:
+	    return False
+	if W >= eE:
+	    return False
+	if N <= eS:
+	    return False
+	if S >= eN:
+	    return False
+	if T <= eB:
+	    return False
+	if B >= eT:
+	    return False
+         
+        # First we check that at least one edge of extent meets an edge of self
+        if W != eW and E != eE and N != eN and S != eS and B != eB and T != eT:
+	    return False
+	    
+	# We check that at least one edge of extent is located in self
+	edge_count = 0
+	if W < eW and E > eW:
+	    edge_count += 1
+	if E > eE and W < eE:
+	    edge_count += 1
+	if N > eN and S < eN:
+	    edge_count += 1
+	if S < eS and N > eS:
+	    edge_count += 1
+	if N > eN and S < eN:
+	    edge_count += 1
+	if S < eS and N > eS:
+	    edge_count += 1
+	if T > eT and B < eT:
+	    edge_count += 1
+	if B < eB and T > eB:
+	    edge_count += 1
+	
+	if edge_count == 0:
+	    return False
+	
+	return True
+        
+    def covered_2d(self, extent):
+	"""Check two dimensional if self is covered by  extent """
+
+	return extent.cover_2d(self)
+	
+    def covered(self, extent):
+	"""Check three dimensional if self is covered by extent """
+	
+	return extent.cover(self)
+        	
+    def overlap_2d(self, extent):
+        """Return True if the two dimensional extents overlap. Code is lend from wind_overlap.c in lib/gis
+            _____
+           |A  __|__
+           |  |  | B|
+           |__|__|  |
+              |_____|
+              
+           The following cases are excluded:
+	   * contain
+	   * in
+	   * cover
+	   * covered
+	   * equivalent
+        """    
+        
+        if self.contain_2d(extent):
+	    return False
+	    
+        if self.is_in_2d(extent):
+	    return False
+	    
+        if self.cover_2d(extent):
+	    return False
+	    
+        if self.covered_2d(extent):
+	    return False
+	    
+        if self.equivalent_2d(extent):
+	    return False
+        
+        N = extent.get_north()
+        S = extent.get_south()
+        E = extent.get_east()
+        W = extent.get_west()
+        
+        # Adjust the east and west in case of LL projection
+        if self.get_projection() == "LL":
             while E < self.get_west():
                 E += 360.0
                 W += 360.0
@@ -57,7 +525,13 @@
             while W > self.get_east():
                 E -= 360.0
                 W -= 360.0
-            
+                
+        if(self.get_north() <= S):
+            return False
+        
+        if(self.get_south() >= N):
+            return False
+        
         if self.get_east() <= W:
             return False
         
@@ -67,14 +541,60 @@
         return True
 
     def overlap(self, extent):
-        """Return True if the extents overlap."""  
+        """Return True if the three dimensional extents overlap
         
-        if self.overlap_2d(extent) == False:
-            return False
-            
+           The following cases are excluded:
+	   * contain
+	   * in
+	   * cover
+	   * covered
+	   * equivalent
+        """   
+
+        if self.is_in(extent):
+	    return False
+
+        if self.contain(extent):
+	    return False
+
+        if self.cover(extent):
+	    return False
+
+        if self.covered(extent):
+	    return False
+
+        if self.equivalent(extent):
+	    return False
+        
+        N = extent.get_north()
+        S = extent.get_south()
+        E = extent.get_east()
+        W = extent.get_west()
         T = extent.get_top()
         B = extent.get_bottom()
         
+        # Adjust the east and west in case of LL projection
+        if self.get_projection() == "LL":
+            while E < self.get_west():
+                E += 360.0
+                W += 360.0
+
+            while W > self.get_east():
+                E -= 360.0
+                W -= 360.0
+                
+        if(self.get_north() <= S):
+            return False
+        
+        if(self.get_south() >= N):
+            return False
+            
+        if self.get_east() <= W:
+            return False
+        
+        if self.get_west() >= E:
+            return False
+        
         if self.get_top() <= B:
             return False
         
@@ -82,7 +602,238 @@
             return False
         
         return True
+        
+    def meet_2d(self,extent):
+	""" Check if self and extent meet each other in two dimensions
+	  _____ _____    _____ _____
+	 |  A  |  B  |  |  B  |  A  |
+	 |_____|     |  |     |     |
+	       |_____|  |_____|_____|
+	       	       
+	         ___
+	        | A |
+	        |   |
+	        |___|    _____
+	       |  B  |  |  B  |
+	       |     |  |     |
+	       |_____|  |_____|_
+	                  |  A  |
+	                  |     |
+	                  |_____|
+	                  
+	"""
+	
+	eN = extent.get_north()
+        eS = extent.get_south()
+        eE = extent.get_east()
+        eW = extent.get_west()
+        
+        eT = extent.get_top()
+	eB = extent.get_bottom()
+        
+	N = self.get_north()
+        S = self.get_south()
+        E = self.get_east()
+        W = self.get_west()
+	        
+        # Adjust the east and west in case of LL projection
+        if self.get_projection() == "LL":
+            while eE < W:
+                eE += 360.0
+                eW += 360.0
 
+            while eW > E:
+                eE -= 360.0
+                eW -= 360.0	
+                
+        edge = None
+        edge_count = 0
+        
+        if E == eW:
+	    edge = "E"
+	    edge_count += 1
+        if W == eE:
+	    edge = "W"
+	    edge_count += 1
+        if N == eS:
+	    edge = "N"
+	    edge_count += 1
+        if S == eN:
+	    edge = "S"
+	    edge_count += 1
+	
+	# Meet a a single edge only
+	if edge_count != 1:
+	    return False
+	
+	# Check boundaries of the faces
+	if edge == "E" or edge == "W":
+	    if N < eS or S > eN:
+		return False
+		
+	if edge == "N" or edge == "S":
+	    if E < eW or W > eE:
+		return False
+	
+	return True
+
+    def meet(self,extent):
+	""" Check if self and extent touch meet other in three dimensions"""
+	eN = extent.get_north()
+        eS = extent.get_south()
+        eE = extent.get_east()
+        eW = extent.get_west()
+        
+        eT = extent.get_top()
+	eB = extent.get_bottom()
+        
+	N = self.get_north()
+        S = self.get_south()
+        E = self.get_east()
+        W = self.get_west()
+	
+	T = self.get_top()
+	B = self.get_bottom()
+        
+        # Adjust the east and west in case of LL projection
+        if self.get_projection() == "LL":
+            while eE < W:
+                eE += 360.0
+                eW += 360.0
+
+            while eW > E:
+                eE -= 360.0
+                eW -= 360.0	
+                
+        edge = None
+        edge_count = 0
+        
+        if E == eW:
+	    edge = "E"
+	    edge_count += 1
+        if W == eE:
+	    edge = "W"
+	    edge_count += 1
+        if N == eS:
+	    edge = "N"
+	    edge_count += 1
+        if S == eN:
+	    edge = "S"
+	    edge_count += 1
+        if T == eB:
+	    edge = "T"
+	    edge_count += 1
+        if B == eT:
+	    edge = "B"
+	    edge_count += 1	
+	
+	# Meet a a single edge only
+	if edge_count != 1:
+	    return False
+	
+	# Check boundaries of the faces
+	if edge == "E" or edge == "W":
+	    if N < eS or S > eN:
+		return False
+	    if T < eB or B > eT:
+		return False
+		
+	if edge == "N" or edge == "S":
+	    if E < eW or W > eE:
+		return False
+	    if T < eB or B > eT:
+		return False
+		
+	if edge == "T" or edge == "B":
+	    if E < eW or W > eE:
+		return False
+	    if N < eS or S > eN:
+		return False
+	
+	return True
+
+    def disjoint_2d(self, extent):
+        """Return True if the two dimensional extents are disjoint 
+        """  
+        
+        if self.overlapping_2d(extent) or self.meet_2d(extent):
+	    return False
+	return True
+
+    def disjoint(self, extent):
+        """Return True if the three dimensional extents are disjoint 
+        """  
+        
+        if self.overlapping(extent) or self.meet(extent):
+	    return False
+	return True
+                
+    def spatial_relation_2d(self, extent):
+	"""Returns the two dimensional spatial relation between self and extent
+	
+	    Spatial relations are:
+	    * disjoint
+	    * meet
+	    * overlap
+	    * cover
+	    * covered
+	    * in
+	    * contain
+	    * equivalent
+	"""
+        
+	if self.equivalent_2d(extent):
+	    return "equivalent"
+	if self.contain_2d(extent):
+	    return "contain"
+	if self.is_in_2d(extent):
+	    return "in"
+	if self.cover_2d(extent):
+	    return "cover"
+	if self.covered_2d(extent):
+	    return "covered"
+	if self.overlap_2d(extent):
+	    return "overlap"
+	if self.meet_2d(extent):
+	    return "meet"
+	if self.disjoint_2d(extent):
+	    return "disjoint"
+	    
+        return "unknown"
+        
+    def spatial_relation(self, extent):
+	"""Returns the three dimensional spatial relation between self and extent
+	
+	    Spatial relations are:
+	    * disjoint
+	    * meet
+	    * overlap
+	    * cover
+	    * covered
+	    * in
+	    * contain
+	    * equivalent
+	"""
+        
+	if self.equivalent(extent):
+	    return "equivalent"
+	if self.contain(extent):
+	    return "contain"
+	if self.is_in(extent):
+	    return "in"
+	if self.cover(extent):
+	    return "cover"
+	if self.covered(extent):
+	    return "covered"
+	if self.overlap(extent):
+	    return "overlap"
+	if self.meet(extent):
+	    return "meet"
+	if self.disjoint(extent):
+	    return "disjoint"
+	    
+        return "unknown"
+        
     def set_spatial_extent(self, north, south, east, west, top, bottom):
         """Set the spatial extent"""
 

Modified: grass/trunk/lib/python/temporal/temporal_extent.py
===================================================================
--- grass/trunk/lib/python/temporal/temporal_extent.py	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/temporal_extent.py	2012-03-22 12:21:11 UTC (rev 51142)
@@ -34,119 +34,119 @@
 	self.set_start_time(start_time)
 	self.set_end_time(end_time)
 
-    def starts(self, map):
+    def starts(self, extent):
 	"""Return True if this time object starts at the start of the provided time object and finishes within it
 	   A  |-----|
 	   B  |---------|
 	"""
-        if  self.D["end_time"] == None or map.D["end_time"] == None :
+        if  self.D["end_time"] == None or extent.D["end_time"] == None :
             return False
             
-	if self.D["start_time"] == map.D["start_time"] and self.D["end_time"] < map.D["end_time"]:
+	if self.D["start_time"] == extent.D["start_time"] and self.D["end_time"] < extent.D["end_time"]:
 	    return True
         else:
 	    return False
 
-    def started(self, map):
+    def started(self, extent):
 	"""Return True if this time object is started at the start of the provided time object
 	   A  |---------|
 	   B  |-----|
 	"""
-        if  self.D["end_time"] == None or map.D["end_time"] == None :
+        if  self.D["end_time"] == None or extent.D["end_time"] == None :
             return False
 
-	if self.D["start_time"] == map.D["start_time"] and self.D["end_time"] > map.D["end_time"]:
+	if self.D["start_time"] == extent.D["start_time"] and self.D["end_time"] > extent.D["end_time"]:
 	    return True
         else:
 	    return False
 
-    def finishes(self, map):
+    def finishes(self, extent):
 	"""Return True if this time object finishes at the end and within of the provided time object
 	   A      |-----|
 	   B  |---------|
 	"""
-        if  self.D["end_time"] == None or map.D["end_time"] == None :
+        if  self.D["end_time"] == None or extent.D["end_time"] == None :
             return False
 
-	if self.D["end_time"] == map.D["end_time"] and  self.D["start_time"] > map.D["start_time"] :
+	if self.D["end_time"] == extent.D["end_time"] and  self.D["start_time"] > extent.D["start_time"] :
 	    return True
         else:
 	    return False
 
-    def finished(self, map):
+    def finished(self, extent):
 	"""Return True if this time object finished at the end of the provided time object
 	   A  |---------|
 	   B      |-----|
 	"""
-        if  self.D["end_time"] == None or map.D["end_time"] == None :
+        if  self.D["end_time"] == None or extent.D["end_time"] == None :
             return False
 
-	if self.D["end_time"] == map.D["end_time"] and  self.D["start_time"] < map.D["start_time"] :
+	if self.D["end_time"] == extent.D["end_time"] and  self.D["start_time"] < extent.D["start_time"] :
 	    return True
         else:
 	    return False
 
-    def after(self, map):
+    def after(self, extent):
 	"""Return True if this time object is temporal located after the provided time object
 	   A             |---------|
 	   B  |---------|
 	"""
-        if map.D["end_time"] == None:
-            if self.D["start_time"] > map.D["start_time"]:
+        if extent.D["end_time"] == None:
+            if self.D["start_time"] > extent.D["start_time"]:
                 return True
             else:
                 return False
 
-	if self.D["start_time"] > map.D["end_time"]:
+	if self.D["start_time"] > extent.D["end_time"]:
 	    return True
         else:
 	    return False
 
-    def before(self, map):
+    def before(self, extent):
 	"""Return True if this time object is temporal located before the provided time object
 	   A  |---------|
 	   B             |---------|
 	"""
         if self.D["end_time"] == None:
-            if self.D["start_time"] < map.D["start_time"]:
+            if self.D["start_time"] < extent.D["start_time"]:
                 return True
             else:
                 return False
 
-	if self.D["end_time"] < map.D["start_time"]:
+	if self.D["end_time"] < extent.D["start_time"]:
 	    return True
         else:
 	    return False
 
-    def adjacent(self, map):
+    def adjacent(self, extent):
 	"""Return True if this time object is a meeting neighbour the provided time object
 	   A            |---------|
 	   B  |---------|
 	   A  |---------|
 	   B            |---------|
 	"""
-        if  self.D["end_time"] == None and map.D["end_time"] == None :
+        if  self.D["end_time"] == None and extent.D["end_time"] == None :
             return False
         
-	if (self.D["start_time"] == map.D["end_time"]) or (self.D["end_time"] == map.D["start_time"]):
+	if (self.D["start_time"] == extent.D["end_time"]) or (self.D["end_time"] == extent.D["start_time"]):
 	    return True
         else:
 	    return False
 
-    def follows(self, map):
+    def follows(self, extent):
 	"""Return True if this time object is temporal follows the provided time object
 	   A            |---------|
 	   B  |---------|
 	"""
-        if  map.D["end_time"] == None :
+        if  extent.D["end_time"] == None :
             return False
 
-	if self.D["start_time"] == map.D["end_time"]:
+	if self.D["start_time"] == extent.D["end_time"]:
 	    return True
         else:
 	    return False
 
-    def precedes(self, map):
+    def precedes(self, extent):
 	"""Return True if this time object is temporal precedes the provided time object
 	   A  |---------|
 	   B            |---------|
@@ -154,33 +154,33 @@
         if  self.D["end_time"] == None:
             return False
 
-	if self.D["end_time"] == map.D["start_time"]:
+	if self.D["end_time"] == extent.D["start_time"]:
 	    return True
         else:
 	    return False
 
-    def during(self, map):
+    def during(self, extent):
 	"""Return True if this time object is temporal located during the provided time object
 	   A   |-------|
 	   B  |---------|
 	"""
         # Check single point of time in interval
-        if  map.D["end_time"] == None:
+        if  extent.D["end_time"] == None:
                 return False
 
         # Check single point of time in interval
         if  self.D["end_time"] == None:
-            if self.D["start_time"] > map.D["start_time"] and self.D["start_time"] < map.D["end_time"]:
+            if self.D["start_time"] > extent.D["start_time"] and self.D["start_time"] < extent.D["end_time"]:
                 return True
             else:
                 return False
 
-	if self.D["start_time"] > map.D["start_time"] and self.D["end_time"] < map.D["end_time"]:
+	if self.D["start_time"] > extent.D["start_time"] and self.D["end_time"] < extent.D["end_time"]:
 	    return True
         else:
 	    return False
 
-    def contains(self, map):
+    def contains(self, extent):
 	"""Return True if this time object contains the provided time object
 	   A  |---------|
 	   B   |-------|
@@ -190,65 +190,65 @@
                 return False
 
         # Check single point of time in interval
-        if  map.D["end_time"] == None:
-            if self.D["start_time"] < map.D["start_time"] and self.D["end_time"] > map.D["start_time"]:
+        if  extent.D["end_time"] == None:
+            if self.D["start_time"] < extent.D["start_time"] and self.D["end_time"] > extent.D["start_time"]:
                 return True
             else:
                 return False
 
-	if self.D["start_time"] < map.D["start_time"] and self.D["end_time"] > map.D["end_time"]:
+	if self.D["start_time"] < extent.D["start_time"] and self.D["end_time"] > extent.D["end_time"]:
 	    return True
         else:
 	    return False
 
-    def equivalent(self, map):
+    def equivalent(self, extent):
 	"""Return True if this time object is temporal located equivalent the provided time object
 	   A  |---------|
 	   B  |---------|
 	"""
-        if  self.D["end_time"] == None and map.D["end_time"] == None :
-            if self.D["start_time"] == map.D["start_time"]:
+        if  self.D["end_time"] == None and extent.D["end_time"] == None :
+            if self.D["start_time"] == extent.D["start_time"]:
                 return True
             else:
                 return False
 
-        if  self.D["end_time"] == None or map.D["end_time"] == None :
+        if  self.D["end_time"] == None or extent.D["end_time"] == None :
             return False
 
-	if self.D["start_time"] == map.D["start_time"] and self.D["end_time"] == map.D["end_time"]:
+	if self.D["start_time"] == extent.D["start_time"] and self.D["end_time"] == extent.D["end_time"]:
 	    return True
         else:
 	    return False
 
-    def overlaps(self, map):
+    def overlaps(self, extent):
 	"""Return True if this time object is temporal overlaps the provided time object
            A  |---------|
 	   B    |---------|
 	"""
-        if  self.D["end_time"] == None or map.D["end_time"] == None :
+        if  self.D["end_time"] == None or extent.D["end_time"] == None :
             return False
 
-	if self.D["start_time"] < map.D["start_time"] and self.D["end_time"] < map.D["end_time"] and\
-	   self.D["end_time"] > map.D["start_time"]:
+	if self.D["start_time"] < extent.D["start_time"] and self.D["end_time"] < extent.D["end_time"] and\
+	   self.D["end_time"] > extent.D["start_time"]:
 	    return True
         else:
 	    return False
 
-    def overlapped(self, map):
+    def overlapped(self, extent):
 	"""Return True if this time object is temporal overlapped by the provided time object
 	   A    |---------|
            B  |---------|
 	"""
-        if  self.D["end_time"] == None or map.D["end_time"] == None :
+        if  self.D["end_time"] == None or extent.D["end_time"] == None :
             return False
             
-	if self.D["start_time"] > map.D["start_time"] and self.D["end_time"] > map.D["end_time"] and\
-	   self.D["start_time"] < map.D["end_time"]:
+	if self.D["start_time"] > extent.D["start_time"] and self.D["end_time"] > extent.D["end_time"] and\
+	   self.D["start_time"] < extent.D["end_time"]:
 	    return True
         else:
 	    return False
 
-    def temporal_relation(self, map):
+    def temporal_relation(self, extent):
 	"""Returns the temporal relation between temporal objects
 	   Temporal relationships are implemented after [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic]
 	"""
@@ -258,39 +258,39 @@
             return None
         if not self.D.has_key("end_time"):
             return None
-        if not map.D.has_key("start_time"):
+        if not extent.D.has_key("start_time"):
             return None
-        if not map.D.has_key("end_time"):
+        if not extent.D.has_key("end_time"):
             return None
 
-        if self.D["start_time"] == None or map.D["start_time"] == None:
+        if self.D["start_time"] == None or extent.D["start_time"] == None:
             return None
 
-	if self.equivalent(map):
+	if self.equivalent(extent):
 	    return "equivalent"
-	if self.during(map):
+	if self.during(extent):
 	    return "during"
-	if self.contains(map):
+	if self.contains(extent):
 	    return "contains"
-	if self.overlaps(map):
+	if self.overlaps(extent):
 	    return "overlaps"
-	if self.overlapped(map):
+	if self.overlapped(extent):
 	    return "overlapped"
-	if self.after(map):
+	if self.after(extent):
 	    return "after"
-	if self.before(map):
+	if self.before(extent):
 	    return "before"
-	if self.starts(map):
+	if self.starts(extent):
 	    return "starts"
-	if self.finishes(map):
+	if self.finishes(extent):
 	    return "finishes"
-	if self.started(map):
+	if self.started(extent):
 	    return "started"
-	if self.finished(map):
+	if self.finished(extent):
 	    return "finished"
-	if self.follows(map):
+	if self.follows(extent):
 	    return "follows"
-	if self.precedes(map):
+	if self.precedes(extent):
 	    return "precedes"
         return None
 
@@ -300,11 +300,11 @@
 	self.D["id"] = ident
 
     def set_start_time(self, start_time):
-	"""Set the valid start time of the map"""
+	"""Set the valid start time of the extent"""
 	self.D["start_time"] = start_time
 
     def set_end_time(self, end_time):
-	"""Set the valid end time of the map"""
+	"""Set the valid end time of the extent"""
 	self.D["end_time"] = end_time
 
     def get_id(self):
@@ -317,7 +317,7 @@
 	    return None
 
     def get_start_time(self):
-	"""Get the valid start time of the map
+	"""Get the valid start time of the extent
 	   @return None if not found"""
 	if self.D.has_key("start_time"):
 	    return self.D["start_time"]
@@ -325,7 +325,7 @@
 	    return None
 
     def get_end_time(self):
-	"""Get the valid end time of the map
+	"""Get the valid end time of the extent
 	   @return None if not found"""
 	if self.D.has_key("end_time"):
 	    return self.D["end_time"]

Modified: grass/trunk/lib/python/temporal/temporal_granularity.py
===================================================================
--- grass/trunk/lib/python/temporal/temporal_granularity.py	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/temporal_granularity.py	2012-03-22 12:21:11 UTC (rev 51142)
@@ -26,7 +26,15 @@
 ###############################################################################
 
 def compute_relative_time_granularity(maps):            
-    """ Compute the relative granularity"""
+    """ Compute the relative time granularity
+        
+        Attention: The computation of the granularity is only correct in case of not
+        overlapping intervals. Hence a correct temporal topology is required for
+        computation.
+    
+	
+        @param maps: a ordered by start_time list of map objects
+    """
 
     # The interval time must be scaled to days resolution
     granularity = None
@@ -68,7 +76,16 @@
 
 ###############################################################################
 
-def compute_absolute_time_granularity(maps):            
+def compute_absolute_time_granularity(maps):                  
+    """ Compute the absolute time granularity
+        
+        Attention: The computation of the granularity is only correct in case of not
+        overlapping intervals. Hence a correct temporal topology is required for
+        computation.
+    
+	
+        @param maps: a ordered by start_time list of map objects
+    """     
 
     has_seconds = False
     has_minutes = False

Modified: grass/trunk/lib/python/temporal/unit_tests.py
===================================================================
--- grass/trunk/lib/python/temporal/unit_tests.py	2012-03-22 10:28:16 UTC (rev 51141)
+++ grass/trunk/lib/python/temporal/unit_tests.py	2012-03-22 12:21:11 UTC (rev 51142)
@@ -570,7 +570,7 @@
     for i in range(6):
         end = start * fact
         map = raster_dataset(None)
-        map.set_relative_time(start, end)
+        map.set_relative_time(start, end, "years")
         maps.append(map)
         start = end
 
@@ -587,7 +587,7 @@
     for i in range(10):
         end = start * fact
         map = raster_dataset(None)
-        map.set_relative_time(start, end)
+        map.set_relative_time(start, end, "years")
         maps.append(map)
         start = end
 
@@ -972,3 +972,452 @@
     gran = compute_absolute_time_granularity(maps)
     if increment != gran:
         core.error("Wrong granularity reference %s != gran %s" % (increment, gran))
+
+###############################################################################
+
+def test_spatial_extent_intersection():
+    # Generate the extents
+    
+    A = spatial_extent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
+    B.print_info()
+    C = A.intersect(B)
+    C.print_info()
+    
+    if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
+       C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
+       C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
+        core.error("Wrong intersection computation")
+        
+    B = spatial_extent(north=40, south=30, east=60, west=10, bottom=-50, top=50)
+    B.print_info()
+    C = A.intersect(B)
+    C.print_info()
+    
+    if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
+       C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
+       C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
+        core.error("Wrong intersection computation")
+        
+    B = spatial_extent(north=40, south=30, east=60, west=30, bottom=-50, top=50)
+    B.print_info()
+    C = A.intersect(B)
+    C.print_info()
+    
+    if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
+       C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
+       C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
+        core.error("Wrong intersection computation")
+    
+    B = spatial_extent(north=40, south=30, east=60, west=30, bottom=-30, top=50)
+    B.print_info()
+    C = A.intersect(B)
+    C.print_info()
+    
+    if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
+       C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
+       C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
+        core.error("Wrong intersection computation")
+    
+    B = spatial_extent(north=40, south=30, east=60, west=30, bottom=-30, top=30)
+    B.print_info()
+    C = A.intersect(B)
+    C.print_info()
+    
+    if C.get_north() != B.get_north() or C.get_south() != B.get_south() or \
+       C.get_west() != B.get_west() or C.get_east() != B.get_east() or \
+       C.get_bottom() != B.get_bottom() or C.get_top() != B.get_top():
+        core.error("Wrong intersection computation")
+
+###############################################################################
+
+def test_spatial_relations():
+    # Generate the extents
+    
+    A = spatial_extent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "equivalent":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    B = spatial_extent(north=70, south=20, east=60, west=10, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "cover":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "cover":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    B = spatial_extent(north=70, south=30, east=60, west=10, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "cover":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "cover":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = B.spatial_relation_2d(A)
+    print relation
+    if relation!= "covered":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = B.spatial_relation(A)
+    print relation
+    if relation!= "covered":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    B = spatial_extent(north=70, south=30, east=50, west=10, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "cover":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = B.spatial_relation_2d(A)
+    print relation
+    if relation!= "covered":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "cover":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    B = spatial_extent(north=70, south=30, east=50, west=20, bottom=-50, top=50)
+    
+    relation = B.spatial_relation(A)
+    print relation
+    if relation!= "covered":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    B = spatial_extent(north=70, south=30, east=50, west=20, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "contain":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "cover":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    B = spatial_extent(north=70, south=30, east=50, west=20, bottom=-40, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "cover":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    B = spatial_extent(north=70, south=30, east=50, west=20, bottom=-40, top=40)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "contain":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = B.spatial_relation(A)
+    print relation
+    if relation!= "in":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    B = spatial_extent(north=90, south=30, east=50, west=20, bottom=-40, top=40)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "overlap":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "overlap":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    B = spatial_extent(north=90, south=5, east=70, west=5, bottom=-40, top=40)
+    A.print_info()
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "in":
+	core.error("Wrong spatial relation: %s"%(relation))
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "overlap":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    B = spatial_extent(north=90, south=5, east=70, west=5, bottom=-40, top=60)
+    A.print_info()
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "overlap":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+	
+    B = spatial_extent(north=90, south=5, east=70, west=5, bottom=-60, top=60)
+    A.print_info()
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "in":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    A = spatial_extent(north=80, south=60, east=60, west=10, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=60, south=20, east=60, west=10, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    A = spatial_extent(north=60, south=40, east=60, west=10, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=80, south=60, east=60, west=10, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=40, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=90, south=30, east=60, west=40, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=70, south=50, east=60, west=40, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=60, south=20, east=60, west=40, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=40, south=20, east=60, west=40, bottom=-50, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation_2d(B)
+    print relation
+    if relation!= "disjoint":
+	core.error("Wrong spatial relation: %s"%(relation))
+	
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "disjoint":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=60, south=20, east=60, west=40, bottom=-60, top=60)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
+    A.print_info()
+    B = spatial_extent(north=90, south=30, east=60, west=40, bottom=-40, top=40)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
+    A.print_info()
+    B = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
+    A.print_info()
+    B = spatial_extent(north=80, south=50, east=60, west=30, bottom=-50, top=0)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
+    A.print_info()
+    B = spatial_extent(north=70, south=50, east=50, west=30, bottom=-50, top=0)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
+    A.print_info()
+    B = spatial_extent(north=90, south=30, east=70, west=10, bottom=-50, top=0)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
+    A.print_info()
+    B = spatial_extent(north=70, south=30, east=50, west=10, bottom=-50, top=0)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ ###
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
+    A.print_info()
+    B = spatial_extent(north=80, south=40, east=60, west=20, bottom=0, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
+    A.print_info()
+    B = spatial_extent(north=80, south=50, east=60, west=30, bottom=0, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
+    A.print_info()
+    B = spatial_extent(north=70, south=50, east=50, west=30, bottom=0, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
+    A.print_info()
+    B = spatial_extent(north=90, south=30, east=70, west=10, bottom=0, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+    A = spatial_extent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
+    A.print_info()
+    B = spatial_extent(north=70, south=30, east=50, west=10, bottom=0, top=50)
+    B.print_info()
+    
+    relation = A.spatial_relation(B)
+    print relation
+    if relation!= "meet":
+	core.error("Wrong spatial relation: %s"%(relation))
+ 
+if __name__ == "__main__":
+    test_increment_datetime_by_string()
+    test_adjust_datetime_to_granularity()
+    test_spatial_extent_intersection()
+    #test_compute_relative_time_granularity()
+    test_compute_absolute_time_granularity()
+    test_compute_datetime_delta()
+    test_spatial_extent_intersection()
+    test_spatial_relations()



More information about the grass-commit mailing list