temporal_relationships.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. """!@package grass.temporal
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS related functions to be used in temporal GIS Python library package.
  4. Usage:
  5. @code
  6. import grass.temporal as tgis
  7. tgis.print_temporal_relations(maps)
  8. ...
  9. @endcode
  10. (C) 2008-2011 by the GRASS Development Team
  11. This program is free software under the GNU General Public
  12. License (>=v2). Read the file COPYING that comes with GRASS
  13. for details.
  14. @author Soeren Gebbert
  15. """
  16. from abstract_map_dataset import *
  17. from datetime_math import *
  18. class temporal_topology_builder(object):
  19. """!This class is designed to build the temporal topology based on a list of maps
  20. Example:
  21. # We have a space time raster dataset and build a map list
  22. # from all registered maps ordered by start time
  23. maps = strds.get_registered_maps_as_objects()
  24. # Now lets build the temporal topology of the maps in the list
  25. tb = temporal_topology_builder()
  26. tb.build(maps, True)
  27. for _map in tb:
  28. _map.print_temporal_topology_info()
  29. _follows = _map.get_follows()
  30. if _follows:
  31. for f in _follows:
  32. f.print_temporal_topology_info()
  33. # Using the next and previous methods, we can iterate over the
  34. # topological related maps in this way
  35. _first = tb.get_first()
  36. while _first:
  37. _first.print_temporal_topology_info()
  38. _first = _first.next()
  39. # Dictionary like accessed
  40. _map = tb["name@mapset"]
  41. """
  42. def __init__(self):
  43. self._reset()
  44. def _reset(self):
  45. self._store = {}
  46. self._first = None
  47. def _set_first(self, first):
  48. self._first = first
  49. self._insert(first)
  50. def _detect_first(self):
  51. if len(self) > 0:
  52. _prev = self._store.values()[0]
  53. while _prev != None:
  54. self._first = _prev
  55. _prev = _prev.prev()
  56. def _insert(self, t):
  57. self._store[t.get_id()] = t
  58. def get_first(self):
  59. """!Return the first map with the earliest start time
  60. @return The map with the earliest start time
  61. """
  62. return self._first
  63. def build(self, maps, is_sorted = False):
  64. """!Build the temporal topology structure
  65. This method builds the temporal topology based on all maps in the provided map list.
  66. The temporal topology structure of each map, defined in class temporal_map_relations,
  67. will be reseted and rebuild.
  68. After building the temporal topology the modified map objects can be accessed
  69. in the same way as a dictionary using there id. The implemented iterator assures
  70. the chronological iteration over the maps.
  71. @param maps: A list of abstract_dataset objects with initiated temporal extent
  72. @param is_sorted Set to True if the map list is sorted by start time, sorting will dramatically reduce computation time
  73. """
  74. for _map in maps:
  75. _map.reset_temporal_topology()
  76. for i in xrange(len(maps)):
  77. if is_sorted:
  78. offset = i + 1
  79. found_next = False
  80. else:
  81. offset = 0
  82. # Needed for "next" computation
  83. start0, end0 = maps[i].get_valid_time()
  84. for j in xrange(offset, len(maps)):
  85. # Do not build topology of the same maps
  86. if maps[i] == maps[j]:
  87. continue
  88. # Get the temporal relationship
  89. relation = maps[j].temporal_relation(maps[i])
  90. # We can skip several relationships if not sorted
  91. if not is_sorted:
  92. if relation == "before":
  93. continue
  94. if relation == "precedes":
  95. continue
  96. if relation == "overlapped":
  97. continue
  98. if relation == "finished":
  99. continue
  100. # Build the next reference
  101. if is_sorted:
  102. if not found_next and relation != "equivalent" and relation != "started":
  103. maps[i].set_next(maps[j])
  104. found_next = True
  105. else:
  106. start2, end2 = maps[j].get_valid_time()
  107. if maps[i].next():
  108. start1, end1 = maps[i].next().get_valid_time()
  109. if start2 > start0 and start2 < start1:
  110. maps[i].set_next(maps[j])
  111. else:
  112. if start2 > start0:
  113. maps[i].set_next(maps[j])
  114. # The start time of map j is equal or later than map i
  115. if relation == "equivalent":
  116. maps[j].append_equivalent(maps[i])
  117. maps[i].append_equivalent(maps[j])
  118. elif relation == "follows":
  119. maps[j].append_follows(maps[i])
  120. maps[i].append_precedes(maps[j])
  121. elif relation == "during" or relation == "starts" or relation == "finishes":
  122. maps[j].append_during(maps[i])
  123. maps[i].append_contains(maps[j])
  124. elif relation == "started":
  125. # Consider equal start time, in case "started" map j contains map i
  126. maps[j].append_contains(maps[i])
  127. maps[i].append_during(maps[j])
  128. elif relation == "overlaps":
  129. maps[j].append_overlaps(maps[i])
  130. maps[i].append_overlapped(maps[j])
  131. # Break if the last map follows
  132. if relation == "follows":
  133. if j < len(maps) - 1:
  134. relation = maps[j + 1].temporal_relation(maps[i])
  135. if relation == "after":
  136. break
  137. # Break if the the next map is after
  138. if relation == "after":
  139. break
  140. # Build the previous pointer and store the map internally
  141. for _map in maps:
  142. _next = _map.next()
  143. if _next:
  144. _next.set_prev(_map)
  145. _map.set_temporal_topology_build_true()
  146. self._insert(_map)
  147. # Detect the first map
  148. self._detect_first()
  149. def __iter__(self):
  150. _start = self._first
  151. while _start != None:
  152. yield _start
  153. _start = _start.next()
  154. def __getitem__(self, index):
  155. return self._store[index.get_id()]
  156. def __len__(self):
  157. return len(self._store)
  158. def __contains__(self, _map):
  159. return _map in self._store.values()
  160. def print_temporal_relations(maps1, maps2):
  161. """!Print the temporal relation matrix of the temporal ordered map lists maps1 and maps2
  162. to stdout.
  163. @param maps1: a ordered by start_time list of map objects with initiated temporal extent
  164. @param maps2: a ordered by start_time list of map objects with initiated temporal extent
  165. """
  166. identical = False
  167. use_id = True
  168. if maps1 == maps2:
  169. identical = True
  170. use_id = False
  171. for i in range(len(maps1)):
  172. if identical == True:
  173. start = i + 1
  174. else:
  175. start = 0
  176. for j in range(start, len(maps2)):
  177. relation = maps1[j].temporal_relation(maps2[i])
  178. if use_id == False:
  179. print maps2[j].base.get_name(), relation, maps1[i].base.get_name()
  180. else:
  181. print maps2[j].base.get_id(), relation, maps1[i].base.get_id()
  182. # Break if the last map follows
  183. if relation == "follows":
  184. if j < len(maps1) - 1:
  185. relation = maps1[j + 1].temporal_relation(maps2[i])
  186. if relation == "after":
  187. break
  188. # Break if the the next map is after
  189. if relation == "after":
  190. break
  191. def get_temporal_relation_matrix(maps1, maps2):
  192. """!Return the temporal relation matrix of two map lists
  193. Booth map lists must be ordered by start time
  194. The temporal relationship matrix includes the temporal relations between
  195. the two map lists. Returned is a nested dict representing
  196. a sparse (upper right side in case maps1 == maps2) relationship matrix.
  197. @param maps1: A sorted (start_time) list of abstract_dataset objects with initiated temporal extent
  198. @param maps2: A sorted (start_time) list of abstract_dataset objects with initiated temporal extent
  199. """
  200. matrix = {}
  201. identical = False
  202. if maps1 == maps2:
  203. identical = True
  204. for i in range(len(maps1)):
  205. if identical == True:
  206. start = i + 1
  207. else:
  208. start = 0
  209. row = {}
  210. for j in range(start, len(maps2)):
  211. relation = maps1[j].temporal_relation(maps2[i])
  212. row[maps2[j].base.get_id()] = relation
  213. # Break if the last map follows
  214. if relation == "follows":
  215. if j < len(maps1) - 1:
  216. relation = maps1[j + 1].temporal_relation(maps2[i])
  217. if relation == "after":
  218. break
  219. # Break if the the next map is after
  220. if relation == "after":
  221. break
  222. matrix[maps1[i].base.get_id()] = row
  223. return matrix
  224. def count_temporal_relations(maps1, maps2):
  225. """!Count the temporal relations between the two lists of maps
  226. The map lists must be ordered by start time. Temporal relations are counted
  227. by analyzing the sparse (upper right side in case maps1 == maps2) temporal relationships matrix.
  228. @param maps1: A sorted (start_time) list of abstract_dataset objects with initiated temporal extent
  229. @param maps2: A sorted (start_time) list of abstract_dataset objects with initiated temporal extent
  230. @return A dictionary with counted temporal relationships
  231. """
  232. tcount = {}
  233. identical = False
  234. if maps1 == maps2:
  235. identical = True
  236. for i in range(len(maps1)):
  237. if identical == True:
  238. start = i + 1
  239. else:
  240. start = 0
  241. for j in range(start, len(maps2)):
  242. relation = maps1[j].temporal_relation(maps2[i])
  243. if relation == "before":
  244. continue
  245. if tcount.has_key(relation):
  246. tcount[relation] = tcount[relation] + 1
  247. else:
  248. tcount[relation] = 1
  249. # Break if the last map follows
  250. if relation == "follows":
  251. if j < len(maps1) - 1:
  252. relation = maps1[j + 1].temporal_relation(maps2[i])
  253. if relation == "after":
  254. break
  255. # Break if the the next map is after
  256. if relation == "after":
  257. break
  258. return tcount