temporal_relationships.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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. ###############################################################################
  19. class temporal_topology_builder(object):
  20. """!This class is designed to build the temporal topology based on a lists of maps
  21. Example:
  22. @code
  23. # We have a space time raster dataset and build a map list
  24. # from all registered maps ordered by start time
  25. maps = strds.get_registered_maps_as_objects()
  26. # Now lets build the temporal topology of the maps in the list
  27. tb = temporal_topology_builder()
  28. tb.build(maps)
  29. for _map in tb:
  30. _map.print_temporal_topology_info()
  31. _follows = _map.get_follows()
  32. if _follows:
  33. for f in _follows:
  34. f.print_temporal_topology_info()
  35. # Using the next and previous methods, we can iterate over the
  36. # topological related maps in this way
  37. _first = tb.get_first()
  38. while _first:
  39. _first.print_temporal_topology_info()
  40. _first = _first.next()
  41. # Dictionary like accessed
  42. _map = tb["name@mapset"]
  43. @endcode
  44. """
  45. def __init__(self):
  46. self._reset()
  47. def _reset(self):
  48. self._store = {}
  49. self._first = None
  50. self._temporal_iteratable = False
  51. def _set_first(self, first):
  52. self._first = first
  53. self._insert(first)
  54. def _detect_first(self):
  55. if len(self) > 0:
  56. _prev = self._store.values()[0]
  57. while _prev != None:
  58. self._first = _prev
  59. _prev = _prev.prev()
  60. def _insert(self, t):
  61. self._store[t.get_id()] = t
  62. def get_first(self):
  63. """!Return the first map with the earliest start time
  64. @return The map with the earliest start time
  65. """
  66. return self._first
  67. def _build_internal_iteratable(self, maps):
  68. """!Build an iteratable temporal topology structure for all maps in the list and store the maps internally
  69. Basically the "next" and "prev" relations will be set in the temporal topology structure of each map
  70. The maps will be added to the object, so they can be accessed using the iterator of this class
  71. @param maps: A sorted (by start_time)list of abstract_dataset objects with initiated temporal extent
  72. """
  73. self._build_iteratable(maps)
  74. for _map in maps:
  75. self._insert(_map)
  76. # Detect the first map
  77. self._detect_first()
  78. def _build_iteratable(self, maps):
  79. """!Build an iteratable temporal topology structure for all maps in the list
  80. Basically the "next" and "prev" relations will be set in the temporal topology structure of each map.
  81. @param maps: A sorted (by start_time)list of abstract_dataset objects with initiated temporal extent
  82. """
  83. for i in xrange(len(maps)):
  84. offset = i + 1
  85. for j in xrange(offset, len(maps)):
  86. # Get the temporal relationship
  87. relation = maps[j].temporal_relation(maps[i])
  88. # Build the next reference
  89. if relation != "equivalent" and relation != "started":
  90. maps[i].set_next(maps[j])
  91. break
  92. for _map in maps:
  93. _next = _map.next()
  94. if _next:
  95. _next.set_prev(_map)
  96. _map.set_temporal_topology_build_true()
  97. def build2(self, mapsA, mapsB):
  98. """!Build the temporal topology structure between two ordered lists of maps
  99. This method builds the temporal topology from mapsA to mapsB and vice verse.
  100. The temporal topology structure of each map, defined in class temporal_map_relations,
  101. will be reseted and rebuild for mapsA and mapsB.
  102. After building the temporal topology the modified map objects of mapsA can be accessed
  103. in the same way as a dictionary using there id. The implemented iterator assures
  104. the chronological iteration over the mapsA.
  105. @param mapsA: A sorted list (by start_time) of abstract_dataset objects with initiated temporal extent
  106. @param mapsB: A sorted list (by start_time) of abstract_dataset objects with initiated temporal extent
  107. """
  108. if mapsA == mapsB:
  109. self.build(mapsA, True)
  110. return
  111. for _map in mapsA:
  112. _map.reset_temporal_topology()
  113. for _map in mapsB:
  114. _map.reset_temporal_topology()
  115. for i in xrange(len(mapsA)):
  116. for j in xrange(len(mapsB)):
  117. # Get the temporal relationship
  118. relation = mapsB[j].temporal_relation(mapsA[i])
  119. if relation == "before":
  120. continue
  121. if relation == "equivalent":
  122. mapsB[j].append_equivalent(mapsA[i])
  123. mapsA[i].append_equivalent(mapsB[j])
  124. elif relation == "follows":
  125. mapsB[j].append_follows(mapsA[i])
  126. mapsA[i].append_precedes(mapsB[j])
  127. elif relation == "precedes":
  128. mapsB[j].append_precedes(mapsA[i])
  129. mapsA[i].append_follows(mapsB[j])
  130. elif relation == "during" or relation == "starts" or relation == "finishes":
  131. mapsB[j].append_during(mapsA[i])
  132. mapsA[i].append_contains(mapsB[j])
  133. elif relation == "contains" or relation == "started" or relation == "finished":
  134. mapsB[j].append_contains(mapsA[i])
  135. mapsA[i].append_during(mapsB[j])
  136. elif relation == "overlaps":
  137. mapsB[j].append_overlaps(mapsA[i])
  138. mapsA[i].append_overlapped(mapsB[j])
  139. elif relation == "overlapped":
  140. mapsB[j].append_overlapped(mapsA[i])
  141. mapsA[i].append_overlaps(mapsB[j])
  142. # Break if the next map follows and the over-next maps is after
  143. if relation == "follows":
  144. if j < len(mapsB) - 1:
  145. relation = mapsB[j + 1].temporal_relation(mapsA[i])
  146. if relation == "after":
  147. break
  148. # Break if the the next map is after
  149. if relation == "after":
  150. break
  151. self._build_internal_iteratable(mapsA)
  152. self._build_iteratable(mapsB)
  153. def build(self, maps):
  154. """!Build the temporal topology structure
  155. This method builds the temporal topology based on all maps in the provided map list.
  156. The temporal topology structure of each map, defined in class temporal_map_relations,
  157. will be reseted and rebuild.
  158. After building the temporal topology the modified map objects can be accessed
  159. in the same way as a dictionary using there id. The implemented iterator assures
  160. the chronological iteration over the maps.
  161. @param maps: A sorted list (by start_time) of abstract_dataset objects with initiated temporal extent
  162. """
  163. for _map in maps:
  164. _map.reset_temporal_topology()
  165. for i in xrange(len(maps)):
  166. offset = i + 1
  167. for j in xrange(offset, len(maps)):
  168. # Get the temporal relationship
  169. relation = maps[j].temporal_relation(maps[i])
  170. # The start time of map j is equal or later than map i
  171. if relation == "equivalent":
  172. maps[j].append_equivalent(maps[i])
  173. maps[i].append_equivalent(maps[j])
  174. elif relation == "follows":
  175. maps[j].append_follows(maps[i])
  176. maps[i].append_precedes(maps[j])
  177. elif relation == "during" or relation == "starts" or relation == "finishes":
  178. maps[j].append_during(maps[i])
  179. maps[i].append_contains(maps[j])
  180. elif relation == "started":
  181. # Consider equal start time, in case "started" map j contains map i
  182. maps[j].append_contains(maps[i])
  183. maps[i].append_during(maps[j])
  184. elif relation == "overlaps":
  185. maps[j].append_overlaps(maps[i])
  186. maps[i].append_overlapped(maps[j])
  187. # Break if the last map follows
  188. if relation == "follows":
  189. if j < len(maps) - 1:
  190. relation = maps[j + 1].temporal_relation(maps[i])
  191. if relation == "after":
  192. break
  193. # Break if the the next map is after
  194. if relation == "after":
  195. break
  196. self._build_internal_iteratable(maps)
  197. def __iter__(self):
  198. _start = self._first
  199. while _start != None:
  200. yield _start
  201. _start = _start.next()
  202. def __getitem__(self, index):
  203. return self._store[index.get_id()]
  204. def __len__(self):
  205. return len(self._store)
  206. def __contains__(self, _map):
  207. return _map in self._store.values()
  208. ###############################################################################
  209. def print_temporal_topology_relationships(maps1, maps2):
  210. """!Print the temporal relation matrix of the temporal ordered map lists maps1 and maps2
  211. to stdout.
  212. @param maps1: A sorted (by start_time) list of abstract_dataset objects with initiated temporal extent
  213. @param maps2: A sorted (by start_time) list of abstract_dataset objects with initiated temporal extent
  214. """
  215. identical = False
  216. use_id = True
  217. if maps1 == maps2:
  218. identical = True
  219. use_id = False
  220. for i in range(len(maps1)):
  221. if identical == True:
  222. start = i + 1
  223. else:
  224. start = 0
  225. for j in range(start, len(maps2)):
  226. relation = maps1[j].temporal_relation(maps2[i])
  227. if use_id == False:
  228. print maps2[j].base.get_name(), relation, maps1[i].base.get_name()
  229. else:
  230. print maps2[j].base.get_id(), relation, maps1[i].base.get_id()
  231. # Break if the last map follows
  232. if relation == "follows":
  233. if j < len(maps1) - 1:
  234. relation = maps1[j + 1].temporal_relation(maps2[i])
  235. if relation == "after":
  236. break
  237. # Break if the the next map is after
  238. if relation == "after":
  239. break
  240. ###############################################################################
  241. def count_temporal_topology_relationships(maps1, maps2):
  242. """!Count the temporal relations between the two lists of maps
  243. The map lists must be ordered by start time. Temporal relations are counted
  244. by analyzing the sparse (upper right side in case maps1 == maps2) temporal relationships matrix.
  245. @param maps1: A sorted (by start_time) list of abstract_dataset objects with initiated temporal extent
  246. @param maps2: A sorted (by start_time) list of abstract_dataset objects with initiated temporal extent
  247. @return A dictionary with counted temporal relationships
  248. """
  249. tcount = {}
  250. identical = False
  251. if maps1 == maps2:
  252. identical = True
  253. for i in range(len(maps1)):
  254. if identical == True:
  255. start = i + 1
  256. else:
  257. start = 0
  258. for j in range(start, len(maps2)):
  259. relation = maps1[j].temporal_relation(maps2[i])
  260. if relation == "before":
  261. continue
  262. if tcount.has_key(relation):
  263. tcount[relation] = tcount[relation] + 1
  264. else:
  265. tcount[relation] = 1
  266. # Break if the last map follows
  267. if relation == "follows":
  268. if j < len(maps1) - 1:
  269. relation = maps1[j + 1].temporal_relation(maps2[i])
  270. if relation == "after":
  271. break
  272. # Break if the the next map is after
  273. if relation == "after":
  274. break
  275. return tcount