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