abstract_temporal_dataset.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616
  1. # -*- coding: utf-8 -*-
  2. """!@package grass.temporal
  3. @brief GRASS Python scripting module (temporal GIS functions)
  4. Temporal GIS related functions to be used in temporal GIS Python library package.
  5. Usage:
  6. >>> import grass.temporal as tgis
  7. >>> tmr = tgis.AbstractTemporalDataset()
  8. (C) 2008-2011 by the GRASS Development Team
  9. This program is free software under the GNU General Public
  10. License (>=v2). Read the file COPYING that comes with GRASS
  11. for details.
  12. @author Soeren Gebbert
  13. """
  14. from abstract_dataset import *
  15. from datetime_math import *
  16. class AbstractTemporalDataset(AbstractDataset):
  17. """!This class implements a temporal topology access structure for an abstract dataset
  18. This object will be set up by temporal topology creation method provided by the
  19. TemporallyTopologyBuilder.
  20. If correctly initialize the calls next() and prev()
  21. let the user walk temporally forward and backward in time.
  22. The following temporal relations with access methods are supported:
  23. * equal
  24. * follows
  25. * precedes
  26. * overlaps
  27. * overlapped
  28. * during (including starts, finishes)
  29. * contains (including started, finished)
  30. * starts
  31. * started
  32. * finishes
  33. * finished
  34. @code:
  35. # We have build the temporal topology and we know the first map
  36. start = first
  37. while start:
  38. # Print all maps this map temporally contains
  39. dlist = start.get_contains()
  40. for map in dlist:
  41. map.print_info()
  42. start = start.next()
  43. @endcode
  44. Usage:
  45. @code
  46. >>> import grass.temporal as tgis
  47. >>> tgis.init()
  48. >>> map = tgis.RasterDataset("a@P")
  49. >>> tmr = tgis.AbstractTemporalDataset()
  50. >>> tmr.set_next(map)
  51. >>> tmr.set_prev(map)
  52. >>> tmr.append_equal(map)
  53. >>> tmr.append_follows(map)
  54. >>> tmr.append_precedes(map)
  55. >>> tmr.append_overlapped(map)
  56. >>> tmr.append_overlaps(map)
  57. >>> tmr.append_during(map)
  58. >>> tmr.append_contains(map)
  59. >>> tmr.append_starts(map)
  60. >>> tmr.append_started(map)
  61. >>> tmr.append_finishes(map)
  62. >>> tmr.append_finished(map)
  63. >>> tmr.print_topology_info()
  64. +-------------------- Temporal Topology -------------------------------------+
  65. | Next: ...................... a@P
  66. | Previous: .................. a@P
  67. | Equal:...................... a@P
  68. | Follows: ................... a@P
  69. | Precedes: .................. a@P
  70. | Overlaps: .................. a@P
  71. | Overlapped: ................ a@P
  72. | During: .................... a@P
  73. | Contains: .................. a@P
  74. | Starts:.. .................. a@P
  75. | Started:. .................. a@P
  76. | Finishes:................... a@P
  77. | Finished:................... a@P
  78. >>> tmr.print_topology_shell_info()
  79. next=a@P
  80. prev=a@P
  81. equal=a@P
  82. follows=a@P
  83. precedes=a@P
  84. overlaps=a@P
  85. overlapped=a@P
  86. during=a@P
  87. contains=a@P
  88. starts=a@P
  89. started=a@P
  90. finishes=a@P
  91. finished=a@P
  92. @endcode
  93. """
  94. def __init__(self):
  95. AbstractDataset.__init__(self)
  96. self.reset_topology()
  97. def reset_topology(self):
  98. """!Reset any information about temporal topology"""
  99. self._topology = {}
  100. self._has_topology = False
  101. def get_number_of_relations(self):
  102. """! Return a dictionary in which the keys are the relation names and the value
  103. are the number of relations.
  104. The following relations are available:
  105. * equal
  106. * follows
  107. * precedes
  108. * overlaps
  109. * overlapped
  110. * during (including starts, finishes)
  111. * contains (including started, finished)
  112. * starts
  113. * started
  114. * finishes
  115. * finished
  116. To access topological information the temporal topology must be build first
  117. using the TemporalTopologyBuilder.
  118. @return the dictionary with relations as keys and number as values or None in case the topology wasn't build
  119. """
  120. if self._has_topology == False:
  121. return None
  122. relations = {}
  123. try:
  124. relations["equal"] = len(self._topology["EQUAL"])
  125. except:
  126. relations["equal"] = 0
  127. try:
  128. relations["follows"] = len(self._topology["FOLLOWS"])
  129. except:
  130. relations["follows"] = 0
  131. try:
  132. relations["precedes"] = len(self._topology["PRECEDES"])
  133. except:
  134. relations["precedes"] = 0
  135. try:
  136. relations["overlaps"] = len(self._topology["OVERLAPS"])
  137. except:
  138. relations["overlaps"] = 0
  139. try:
  140. relations["overlapped"] = len(self._topology["OVERLAPPED"])
  141. except:
  142. relations["overlapped"] = 0
  143. try:
  144. relations["during"] = len(self._topology["DURING"])
  145. except:
  146. relations["during"] = 0
  147. try:
  148. relations["contains"] = len(self._topology["CONTAINS"])
  149. except:
  150. relations["contains"] = 0
  151. try:
  152. relations["starts"] = len(self._topology["STARTS"])
  153. except:
  154. relations["starts"] = 0
  155. try:
  156. relations["started"] = len(self._topology["STARTED"])
  157. except:
  158. relations["started"] = 0
  159. try:
  160. relations["finishes"] = len(self._topology["FINISHES"])
  161. except:
  162. relations["finishes"] = 0
  163. try:
  164. relations["finished"] = len(self._topology["FINISHED"])
  165. except:
  166. relations["finished"] = 0
  167. return relations
  168. def set_topology_build_true(self):
  169. """!Same as name"""
  170. self._has_topology = True
  171. def set_topology_build_false(self):
  172. """!Same as name"""
  173. self._has_topology = False
  174. def is_topology_build(self):
  175. """!Check if the temporal topology was build"""
  176. return self._has_topology
  177. def set_next(self, map_):
  178. """!Set the map that is temporally as closest located after this map.
  179. Temporally located means that the start time of the "next" map is
  180. temporally located AFTER the start time of this map, but temporally
  181. near than other maps of the same dataset.
  182. @param map_: This object should be of type AbstractMapDataset
  183. or derived classes
  184. """
  185. self._topology["NEXT"] = map_
  186. def set_prev(self, map_):
  187. """!Set the map that is temporally as closest located before this map.
  188. Temporally located means that the start time of the "previous" map is
  189. temporally located BEFORE the start time of this map, but temporally
  190. near than other maps of the same dataset.
  191. @param map_: This object should be of type AbstractMapDataset
  192. or derived classes
  193. """
  194. self._topology["PREV"] = map_
  195. def next(self):
  196. """!Return the map with a start time temporally located after
  197. the start time of this map, but temporal closer than other maps
  198. @return A map object or None
  199. """
  200. if "NEXT" not in self._topology:
  201. return None
  202. return self._topology["NEXT"]
  203. def prev(self):
  204. """!Return the map with a start time temporally located before
  205. the start time of this map, but temporal closer than other maps
  206. @return A map object or None
  207. """
  208. if "PREV" not in self._topology:
  209. return None
  210. return self._topology["PREV"]
  211. def append_equal(self, map_):
  212. """!Append a map with equivalent temporal extent as this map
  213. @param map_: This object should be of type AbstractMapDataset
  214. or derived classes
  215. """
  216. if "EQUAL" not in self._topology:
  217. self._topology["EQUAL"] = []
  218. self._topology["EQUAL"].append(map_)
  219. def get_equal(self):
  220. """!Return a list of map objects with equivalent temporal extent as this map
  221. @return A list of map objects or None
  222. """
  223. if "EQUAL" not in self._topology:
  224. return None
  225. return self._topology["EQUAL"]
  226. def append_starts(self, map_):
  227. """!Append a map that this map temporally starts with
  228. @param map_: This object should be of type AbstractMapDataset
  229. or derived classes
  230. """
  231. if "STARTS" not in self._topology:
  232. self._topology["STARTS"] = []
  233. self._topology["STARTS"].append(map_)
  234. def get_starts(self):
  235. """!Return a list of map objects that this map temporally starts with
  236. @return A list of map objects or None
  237. """
  238. if "STARTS" not in self._topology:
  239. return None
  240. return self._topology["STARTS"]
  241. def append_started(self, map_):
  242. """!Append a map that this map temporally started with
  243. @param map_: This object should be of type AbstractMapDataset
  244. or derived classes
  245. """
  246. if "STARTED" not in self._topology:
  247. self._topology["STARTED"] = []
  248. self._topology["STARTED"].append(map_)
  249. def get_started(self):
  250. """!Return a list of map objects that this map temporally started with
  251. @return A list of map objects or None
  252. """
  253. if "STARTED" not in self._topology:
  254. return None
  255. return self._topology["STARTED"]
  256. def append_finishes(self, map_):
  257. """!Append a map that this map temporally finishes with
  258. @param map_: This object should be of type AbstractMapDataset
  259. or derived classes
  260. """
  261. if "FINISHES" not in self._topology:
  262. self._topology["FINISHES"] = []
  263. self._topology["FINISHES"].append(map_)
  264. def get_finishes(self):
  265. """!Return a list of map objects that this map temporally finishes with
  266. @return A list of map objects or None
  267. """
  268. if "FINISHES" not in self._topology:
  269. return None
  270. return self._topology["FINISHES"]
  271. def append_finished(self, map_):
  272. """!Append a map that this map temporally finished with
  273. @param map_: This object should be of type AbstractMapDataset
  274. or derived classes
  275. """
  276. if "FINISHED" not in self._topology:
  277. self._topology["FINISHED"] = []
  278. self._topology["FINISHED"].append(map_)
  279. def get_finished(self):
  280. """!Return a list of map objects that this map temporally finished with
  281. @return A list of map objects or None
  282. """
  283. if "FINISHED" not in self._topology:
  284. return None
  285. return self._topology["FINISHED"]
  286. def append_overlaps(self, map_):
  287. """!Append a map that this map temporally overlaps
  288. @param map_: This object should be of type AbstractMapDataset
  289. or derived classes
  290. """
  291. if "OVERLAPS" not in self._topology:
  292. self._topology["OVERLAPS"] = []
  293. self._topology["OVERLAPS"].append(map_)
  294. def get_overlaps(self):
  295. """!Return a list of map objects that this map temporally overlaps
  296. @return A list of map objects or None
  297. """
  298. if "OVERLAPS" not in self._topology:
  299. return None
  300. return self._topology["OVERLAPS"]
  301. def append_overlapped(self, map_):
  302. """!Append a map that this map temporally overlapped
  303. @param map_: This object should be of type AbstractMapDataset
  304. or derived classes
  305. """
  306. if "OVERLAPPED" not in self._topology:
  307. self._topology["OVERLAPPED"] = []
  308. self._topology["OVERLAPPED"].append(map_)
  309. def get_overlapped(self):
  310. """!Return a list of map objects that this map temporally overlapped
  311. @return A list of map objects or None
  312. """
  313. if "OVERLAPPED" not in self._topology:
  314. return None
  315. return self._topology["OVERLAPPED"]
  316. def append_follows(self, map_):
  317. """!Append a map that this map temporally follows
  318. @param map_: This object should be of type AbstractMapDataset
  319. or derived classes
  320. """
  321. if "FOLLOWS" not in self._topology:
  322. self._topology["FOLLOWS"] = []
  323. self._topology["FOLLOWS"].append(map_)
  324. def get_follows(self):
  325. """!Return a list of map objects that this map temporally follows
  326. @return A list of map objects or None
  327. """
  328. if "FOLLOWS" not in self._topology:
  329. return None
  330. return self._topology["FOLLOWS"]
  331. def append_precedes(self, map_):
  332. """!Append a map that this map temporally precedes
  333. @param map_: This object should be of type AbstractMapDataset
  334. or derived classes
  335. """
  336. if "PRECEDES" not in self._topology:
  337. self._topology["PRECEDES"] = []
  338. self._topology["PRECEDES"].append(map_)
  339. def get_precedes(self):
  340. """!Return a list of map objects that this map temporally precedes
  341. @return A list of map objects or None
  342. """
  343. if "PRECEDES" not in self._topology:
  344. return None
  345. return self._topology["PRECEDES"]
  346. def append_during(self, map_):
  347. """!Append a map that this map is temporally located during
  348. This includes temporal relationships starts and finishes
  349. @param map_: This object should be of type
  350. AbstractMapDataset or derived classes
  351. """
  352. if "DURING" not in self._topology:
  353. self._topology["DURING"] = []
  354. self._topology["DURING"].append(map_)
  355. def get_during(self):
  356. """!Return a list of map objects that this map is temporally located during
  357. This includes temporally relationships starts and finishes
  358. @return A list of map objects or None
  359. """
  360. if "DURING" not in self._topology:
  361. return None
  362. return self._topology["DURING"]
  363. def append_contains(self, map_):
  364. """!Append a map that this map temporally contains
  365. This includes temporal relationships started and finished
  366. @param map_: This object should be of type AbstractMapDataset
  367. or derived classes
  368. """
  369. if "CONTAINS" not in self._topology:
  370. self._topology["CONTAINS"] = []
  371. self._topology["CONTAINS"].append(map_)
  372. def get_contains(self):
  373. """!Return a list of map objects that this map temporally contains
  374. This includes temporal relationships started and finished
  375. @return A list of map objects or None
  376. """
  377. if "CONTAINS" not in self._topology:
  378. return None
  379. return self._topology["CONTAINS"]
  380. def _generate_map_list_string(self, map_list, line_wrap=True):
  381. count = 0
  382. string = ""
  383. for map_ in map_list:
  384. if line_wrap and count > 0 and count % 3 == 0:
  385. string += "\n | ............................ "
  386. count = 0
  387. if count == 0:
  388. string += map_.get_id()
  389. else:
  390. string += ",%s" % map_.get_id()
  391. count += 1
  392. return string
  393. # Set the properties
  394. equal = property(fget=get_equal,
  395. fset=append_equal)
  396. follows = property(fget=get_follows,
  397. fset=append_follows)
  398. precedes = property(fget=get_precedes,
  399. fset=append_precedes)
  400. overlaps = property(fget=get_overlaps,
  401. fset=append_overlaps)
  402. overlapped = property(fget=get_overlapped,
  403. fset=append_overlapped)
  404. during = property(fget=get_during,
  405. fset=append_during)
  406. contains = property(fget=get_contains,
  407. fset=append_contains)
  408. starts = property(fget=get_starts,
  409. fset=append_starts)
  410. started = property(fget=get_started,
  411. fset=append_started)
  412. finishes = property(fget=get_finishes,
  413. fset=append_finishes)
  414. finished = property(fget=get_finished,
  415. fset=append_finished)
  416. def print_topology_info(self):
  417. """!Print information about this class in human readable style"""
  418. _next = self.next()
  419. _prev = self.prev()
  420. _equal = self.get_equal()
  421. _follows = self.get_follows()
  422. _precedes = self.get_precedes()
  423. _overlaps = self.get_overlaps()
  424. _overlapped = self.get_overlapped()
  425. _during = self.get_during()
  426. _contains = self.get_contains()
  427. _starts = self.get_starts()
  428. _started = self.get_started()
  429. _finishes = self.get_finishes()
  430. _finished = self.get_finished()
  431. print " +-------------------- Temporal Topology -------------------------------------+"
  432. # 0123456789012345678901234567890
  433. if _next is not None:
  434. print " | Next: ...................... " + str(_next.get_id())
  435. if _prev is not None:
  436. print " | Previous: .................. " + str(_prev.get_id())
  437. if _equal is not None:
  438. print " | Equal:...................... " + \
  439. self._generate_map_list_string(_equal)
  440. if _follows is not None:
  441. print " | Follows: ................... " + \
  442. self._generate_map_list_string(_follows)
  443. if _precedes is not None:
  444. print " | Precedes: .................. " + \
  445. self._generate_map_list_string(_precedes)
  446. if _overlaps is not None:
  447. print " | Overlaps: .................. " + \
  448. self._generate_map_list_string(_overlaps)
  449. if _overlapped is not None:
  450. print " | Overlapped: ................ " + \
  451. self._generate_map_list_string(_overlapped)
  452. if _during is not None:
  453. print " | During: .................... " + \
  454. self._generate_map_list_string(_during)
  455. if _contains is not None:
  456. print " | Contains: .................. " + \
  457. self._generate_map_list_string(_contains)
  458. if _starts is not None:
  459. print " | Starts:.. .................. " + \
  460. self._generate_map_list_string(_starts)
  461. if _started is not None:
  462. print " | Started:. .................. " + \
  463. self._generate_map_list_string(_started)
  464. if _finishes is not None:
  465. print " | Finishes:................... " + \
  466. self._generate_map_list_string(_finishes)
  467. if _finished is not None:
  468. print " | Finished:................... " + \
  469. self._generate_map_list_string(_finished)
  470. def print_topology_shell_info(self):
  471. """!Print information about this class in shell style"""
  472. _next = self.next()
  473. _prev = self.prev()
  474. _equal = self.get_equal()
  475. _follows = self.get_follows()
  476. _precedes = self.get_precedes()
  477. _overlaps = self.get_overlaps()
  478. _overlapped = self.get_overlapped()
  479. _during = self.get_during()
  480. _contains = self.get_contains()
  481. _starts = self.get_starts()
  482. _started = self.get_started()
  483. _finishes = self.get_finishes()
  484. _finished = self.get_finished()
  485. if _next is not None:
  486. print "next=" + _next.get_id()
  487. if _prev is not None:
  488. print "prev=" + _prev.get_id()
  489. if _equal is not None:
  490. print "equal=" + self._generate_map_list_string(_equal, False)
  491. if _follows is not None:
  492. print "follows=" + self._generate_map_list_string(_follows, False)
  493. if _precedes is not None:
  494. print "precedes=" + self._generate_map_list_string(
  495. _precedes, False)
  496. if _overlaps is not None:
  497. print "overlaps=" + self._generate_map_list_string(
  498. _overlaps, False)
  499. if _overlapped is not None:
  500. print "overlapped=" + \
  501. self._generate_map_list_string(_overlapped, False)
  502. if _during is not None:
  503. print "during=" + self._generate_map_list_string(_during, False)
  504. if _contains is not None:
  505. print "contains=" + self._generate_map_list_string(
  506. _contains, False)
  507. if _starts is not None:
  508. print "starts=" + \
  509. self._generate_map_list_string(_starts)
  510. if _started is not None:
  511. print "started=" + \
  512. self._generate_map_list_string(_started)
  513. if _finishes is not None:
  514. print "finishes=" + \
  515. self._generate_map_list_string(_finishes)
  516. if _finished is not None:
  517. print "finished=" + \
  518. self._generate_map_list_string(_finished)
  519. ###############################################################################
  520. if __name__ == "__main__":
  521. import doctest
  522. doctest.testmod()