# -*- 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()