temporal_relationships.py 13 KB

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