temporal_extent.py 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429
  1. """!@package grass.temporal
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS related temporal extent functions to be used in Python scripts and tgis packages.
  4. Usage:
  5. @code
  6. >>> import grass.temporal as tgis
  7. >>> from datetime import datetime
  8. >>> tgis.init()
  9. >>> t = tgis.RasterRelativeTime()
  10. >>> t = tgis.RasterAbsoluteTime()
  11. @endcode
  12. (C) 2008-2011 by the GRASS Development Team
  13. This program is free software under the GNU General Public
  14. License (>=v2). Read the file COPYING that comes with GRASS
  15. for details.
  16. @author Soeren Gebbert
  17. """
  18. from base import *
  19. ###############################################################################
  20. class AbstractTemporalExtent(SQLDatabaseInterface):
  21. """!This is the abstract time base class for relative and absolute time objects
  22. It abstract class implements the interface to absolute and relative time.
  23. Absolute time is represented by datetime time stamps,
  24. relative time is represented by a unit an integer value.
  25. This class implements temporal topology relationships computation
  26. after [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic].
  27. Usage:
  28. @code
  29. >>> init()
  30. >>> A = AbstractTemporalExtent(table="raster_absolute_time",
  31. ... ident="soil@PERMANENT", start_time=datetime(2001, 01, 01),
  32. ... end_time=datetime(2005,01,01) )
  33. >>> A.id
  34. 'soil@PERMANENT'
  35. >>> A.start_time
  36. datetime.datetime(2001, 1, 1, 0, 0)
  37. >>> A.end_time
  38. datetime.datetime(2005, 1, 1, 0, 0)
  39. >>> A.print_info()
  40. | Start time:................. 2001-01-01 00:00:00
  41. | End time:................... 2005-01-01 00:00:00
  42. >>> A.print_shell_info()
  43. start_time=2001-01-01 00:00:00
  44. end_time=2005-01-01 00:00:00
  45. >>> # relative time
  46. >>> A = AbstractTemporalExtent(table="raster_absolute_time",
  47. ... ident="soil@PERMANENT", start_time=0, end_time=1 )
  48. >>> A.id
  49. 'soil@PERMANENT'
  50. >>> A.start_time
  51. 0
  52. >>> A.end_time
  53. 1
  54. >>> A.print_info()
  55. | Start time:................. 0
  56. | End time:................... 1
  57. >>> A.print_shell_info()
  58. start_time=0
  59. end_time=1
  60. @endcode
  61. """
  62. def __init__(self, table=None, ident=None, start_time=None, end_time=None):
  63. SQLDatabaseInterface.__init__(self, table, ident)
  64. self.set_id(ident)
  65. self.set_start_time(start_time)
  66. self.set_end_time(end_time)
  67. def intersect(self, extent):
  68. """!Intersect this temporal extent with the provided temporal extent and
  69. return a new temporal extent with the new start and end time
  70. @param extent The temporal extent to intersect with
  71. @return The new temporal extent with start and end time,
  72. or None in case of no intersection
  73. Usage:
  74. @code
  75. >>> A = AbstractTemporalExtent(start_time=5, end_time=6 )
  76. >>> inter = A.intersect(A)
  77. >>> inter.print_info()
  78. | Start time:................. 5
  79. | End time:................... 6
  80. >>> A = AbstractTemporalExtent(start_time=5, end_time=6 )
  81. >>> B = AbstractTemporalExtent(start_time=5, end_time=7 )
  82. >>> inter = A.intersect(B)
  83. >>> inter.print_info()
  84. | Start time:................. 5
  85. | End time:................... 6
  86. >>> inter = B.intersect(A)
  87. >>> inter.print_info()
  88. | Start time:................. 5
  89. | End time:................... 6
  90. >>> A = AbstractTemporalExtent(start_time=3, end_time=6 )
  91. >>> B = AbstractTemporalExtent(start_time=5, end_time=7 )
  92. >>> inter = A.intersect(B)
  93. >>> inter.print_info()
  94. | Start time:................. 5
  95. | End time:................... 6
  96. >>> inter = B.intersect(A)
  97. >>> inter.print_info()
  98. | Start time:................. 5
  99. | End time:................... 6
  100. >>> A = AbstractTemporalExtent(start_time=3, end_time=8 )
  101. >>> B = AbstractTemporalExtent(start_time=5, end_time=6 )
  102. >>> inter = A.intersect(B)
  103. >>> inter.print_info()
  104. | Start time:................. 5
  105. | End time:................... 6
  106. >>> inter = B.intersect(A)
  107. >>> inter.print_info()
  108. | Start time:................. 5
  109. | End time:................... 6
  110. >>> A = AbstractTemporalExtent(start_time=5, end_time=8 )
  111. >>> B = AbstractTemporalExtent(start_time=3, end_time=6 )
  112. >>> inter = A.intersect(B)
  113. >>> inter.print_info()
  114. | Start time:................. 5
  115. | End time:................... 6
  116. >>> inter = B.intersect(A)
  117. >>> inter.print_info()
  118. | Start time:................. 5
  119. | End time:................... 6
  120. >>> A = AbstractTemporalExtent(start_time=5, end_time=None )
  121. >>> B = AbstractTemporalExtent(start_time=3, end_time=6 )
  122. >>> inter = A.intersect(B)
  123. >>> inter.print_info()
  124. | Start time:................. 5
  125. | End time:................... None
  126. >>> inter = B.intersect(A)
  127. >>> inter.print_info()
  128. | Start time:................. 5
  129. | End time:................... None
  130. >>> A = AbstractTemporalExtent(start_time=5, end_time=8 )
  131. >>> B = AbstractTemporalExtent(start_time=3, end_time=4 )
  132. >>> inter = A.intersect(B)
  133. >>> print inter
  134. None
  135. >>> A = AbstractTemporalExtent(start_time=5, end_time=8 )
  136. >>> B = AbstractTemporalExtent(start_time=3, end_time=None )
  137. >>> inter = A.intersect(B)
  138. >>> print inter
  139. None
  140. @endcode
  141. """
  142. relation = self.temporal_relation(extent)
  143. if relation == "after" or relation == "before":
  144. return None
  145. if self.D["end_time"] is None:
  146. return AbstractTemporalExtent(start_time=self.D["start_time"])
  147. if extent.D["end_time"] is None:
  148. return AbstractTemporalExtent(start_time=extent.D["start_time"])
  149. start = None
  150. end = None
  151. if self.D["start_time"] > extent.D["start_time"]:
  152. start = self.D["start_time"]
  153. else:
  154. start = extent.D["start_time"]
  155. if self.D["end_time"] > extent.D["end_time"]:
  156. end = extent.D["end_time"]
  157. else:
  158. end = self.D["end_time"]
  159. return AbstractTemporalExtent(start_time=start, end_time=end)
  160. def disjoint_union(self, extent):
  161. """!Creates a disjoint union with this temporal extent and the provided one.
  162. Return a new temporal extent with the new start and end time.
  163. @param extent The temporal extent to create a union with
  164. @return The new temporal extent with start and end time
  165. Usage:
  166. @code
  167. >>> A = AbstractTemporalExtent(start_time=5, end_time=6 )
  168. >>> inter = A.intersect(A)
  169. >>> inter.print_info()
  170. | Start time:................. 5
  171. | End time:................... 6
  172. >>> A = AbstractTemporalExtent(start_time=5, end_time=6 )
  173. >>> B = AbstractTemporalExtent(start_time=5, end_time=7 )
  174. >>> inter = A.disjoint_union(B)
  175. >>> inter.print_info()
  176. | Start time:................. 5
  177. | End time:................... 7
  178. >>> inter = B.disjoint_union(A)
  179. >>> inter.print_info()
  180. | Start time:................. 5
  181. | End time:................... 7
  182. >>> A = AbstractTemporalExtent(start_time=3, end_time=6 )
  183. >>> B = AbstractTemporalExtent(start_time=5, end_time=7 )
  184. >>> inter = A.disjoint_union(B)
  185. >>> inter.print_info()
  186. | Start time:................. 3
  187. | End time:................... 7
  188. >>> inter = B.disjoint_union(A)
  189. >>> inter.print_info()
  190. | Start time:................. 3
  191. | End time:................... 7
  192. >>> A = AbstractTemporalExtent(start_time=3, end_time=8 )
  193. >>> B = AbstractTemporalExtent(start_time=5, end_time=6 )
  194. >>> inter = A.disjoint_union(B)
  195. >>> inter.print_info()
  196. | Start time:................. 3
  197. | End time:................... 8
  198. >>> inter = B.disjoint_union(A)
  199. >>> inter.print_info()
  200. | Start time:................. 3
  201. | End time:................... 8
  202. >>> A = AbstractTemporalExtent(start_time=5, end_time=8 )
  203. >>> B = AbstractTemporalExtent(start_time=3, end_time=6 )
  204. >>> inter = A.disjoint_union(B)
  205. >>> inter.print_info()
  206. | Start time:................. 3
  207. | End time:................... 8
  208. >>> inter = B.disjoint_union(A)
  209. >>> inter.print_info()
  210. | Start time:................. 3
  211. | End time:................... 8
  212. >>> A = AbstractTemporalExtent(start_time=5, end_time=None )
  213. >>> B = AbstractTemporalExtent(start_time=3, end_time=6 )
  214. >>> inter = A.disjoint_union(B)
  215. >>> inter.print_info()
  216. | Start time:................. 3
  217. | End time:................... 6
  218. >>> inter = B.disjoint_union(A)
  219. >>> inter.print_info()
  220. | Start time:................. 3
  221. | End time:................... 6
  222. >>> A = AbstractTemporalExtent(start_time=5, end_time=8 )
  223. >>> B = AbstractTemporalExtent(start_time=3, end_time=4 )
  224. >>> inter = A.disjoint_union(B)
  225. >>> inter.print_info()
  226. | Start time:................. 3
  227. | End time:................... 8
  228. >>> inter = B.disjoint_union(A)
  229. >>> inter.print_info()
  230. | Start time:................. 3
  231. | End time:................... 8
  232. >>> A = AbstractTemporalExtent(start_time=5, end_time=8 )
  233. >>> B = AbstractTemporalExtent(start_time=3, end_time=None )
  234. >>> inter = A.disjoint_union(B)
  235. >>> inter.print_info()
  236. | Start time:................. 3
  237. | End time:................... 8
  238. >>> inter = B.disjoint_union(A)
  239. >>> inter.print_info()
  240. | Start time:................. 3
  241. | End time:................... 8
  242. >>> A = AbstractTemporalExtent(start_time=5, end_time=None )
  243. >>> B = AbstractTemporalExtent(start_time=3, end_time=8 )
  244. >>> inter = A.disjoint_union(B)
  245. >>> inter.print_info()
  246. | Start time:................. 3
  247. | End time:................... 8
  248. >>> inter = B.disjoint_union(A)
  249. >>> inter.print_info()
  250. | Start time:................. 3
  251. | End time:................... 8
  252. >>> A = AbstractTemporalExtent(start_time=5, end_time=None )
  253. >>> B = AbstractTemporalExtent(start_time=3, end_time=None )
  254. >>> inter = A.disjoint_union(B)
  255. >>> inter.print_info()
  256. | Start time:................. 3
  257. | End time:................... 5
  258. >>> inter = B.disjoint_union(A)
  259. >>> inter.print_info()
  260. | Start time:................. 3
  261. | End time:................... 5
  262. @endcoe
  263. """
  264. start = None
  265. end = None
  266. if self.D["start_time"] < extent.D["start_time"]:
  267. start = self.D["start_time"]
  268. else:
  269. start = extent.D["start_time"]
  270. # End time handling
  271. if self.D["end_time"] is None and extent.D["end_time"] is None:
  272. if self.D["start_time"] > extent.D["start_time"]:
  273. end = self.D["start_time"]
  274. else:
  275. end = extent.D["start_time"]
  276. elif self.D["end_time"] is None:
  277. if self.D["start_time"] > extent.D["end_time"]:
  278. end = self.D["start_time"]
  279. else:
  280. end = extent.D["end_time"]
  281. elif extent.D["end_time"] is None:
  282. if self.D["end_time"] > extent.D["start_time"]:
  283. end = self.D["end_time"]
  284. else:
  285. end = extent.D["start_time"]
  286. elif self.D["end_time"] < extent.D["end_time"]:
  287. end = extent.D["end_time"]
  288. else:
  289. end = self.D["end_time"]
  290. return AbstractTemporalExtent(start_time=start, end_time=end)
  291. def union(self, extent):
  292. """!Creates a union with this temporal extent and the provided one.
  293. Return a new temporal extent with the new start and end time.
  294. @param extent The temporal extent to create a union with
  295. @return The new temporal extent with start and end time,
  296. or None in case the temporal extents are unrelated (before or after)
  297. @code
  298. >>> A = AbstractTemporalExtent(start_time=5, end_time=8 )
  299. >>> B = AbstractTemporalExtent(start_time=3, end_time=4 )
  300. >>> inter = A.intersect(B)
  301. >>> print inter
  302. None
  303. >>> A = AbstractTemporalExtent(start_time=5, end_time=8 )
  304. >>> B = AbstractTemporalExtent(start_time=3, end_time=None )
  305. >>> inter = A.intersect(B)
  306. >>> print inter
  307. None
  308. @endcode
  309. """
  310. relation = self.temporal_relation(extent)
  311. if relation == "after" or relation == "before":
  312. return None
  313. return self.disjoint_union(extent)
  314. def starts(self, extent):
  315. """!Return True if this temporal extent (A) starts at the start of the
  316. provided temporal extent (B) and finishes within it
  317. @verbatim
  318. A |-----|
  319. B |---------|
  320. @endverbatim
  321. @param extent The temporal extent object with which this extent starts
  322. Usage:
  323. @code
  324. >>> A = AbstractTemporalExtent(start_time=5, end_time=6 )
  325. >>> B = AbstractTemporalExtent(start_time=5, end_time=7 )
  326. >>> A.starts(B)
  327. True
  328. >>> B.starts(A)
  329. False
  330. @endcode
  331. """
  332. if self.D["end_time"] is None or extent.D["end_time"] is None:
  333. return False
  334. if self.D["start_time"] == extent.D["start_time"] and \
  335. self.D["end_time"] < extent.D["end_time"]:
  336. return True
  337. else:
  338. return False
  339. def started(self, extent):
  340. """!Return True if this temporal extent (A) started at the start of the
  341. provided temporal extent (B) and finishes after it
  342. @verbatim
  343. A |---------|
  344. B |-----|
  345. @endverbatim
  346. @param extent The temporal extent object with which this extent started
  347. Usage:
  348. @code
  349. >>> A = AbstractTemporalExtent(start_time=5, end_time=7 )
  350. >>> B = AbstractTemporalExtent(start_time=5, end_time=6 )
  351. >>> A.started(B)
  352. True
  353. >>> B.started(A)
  354. False
  355. @endcode
  356. """
  357. if self.D["end_time"] is None or extent.D["end_time"] is None:
  358. return False
  359. if self.D["start_time"] == extent.D["start_time"] and \
  360. self.D["end_time"] > extent.D["end_time"]:
  361. return True
  362. else:
  363. return False
  364. def finishes(self, extent):
  365. """!Return True if this temporal extent (A) starts after the start of the
  366. provided temporal extent (B) and finishes with it
  367. @verbatim
  368. A |-----|
  369. B |---------|
  370. @endverbatim
  371. @param extent The temporal extent object with which this extent finishes
  372. Usage:
  373. @code
  374. >>> A = AbstractTemporalExtent(start_time=6, end_time=7 )
  375. >>> B = AbstractTemporalExtent(start_time=5, end_time=7 )
  376. >>> A.finishes(B)
  377. True
  378. >>> B.finishes(A)
  379. False
  380. @endcode
  381. """
  382. if self.D["end_time"] is None or extent.D["end_time"] is None:
  383. return False
  384. if self.D["end_time"] == extent.D["end_time"] and \
  385. self.D["start_time"] > extent.D["start_time"]:
  386. return True
  387. else:
  388. return False
  389. def finished(self, extent):
  390. """!Return True if this temporal extent (A) starts before the start of the
  391. provided temporal extent (B) and finishes with it
  392. @verbatim
  393. A |---------|
  394. B |-----|
  395. @endverbatim
  396. @param extent The temporal extent object with which this extent finishes
  397. Usage:
  398. @code
  399. >>> A = AbstractTemporalExtent(start_time=5, end_time=7 )
  400. >>> B = AbstractTemporalExtent(start_time=6, end_time=7 )
  401. >>> A.finished(B)
  402. True
  403. >>> B.finished(A)
  404. False
  405. @endcode
  406. """
  407. if self.D["end_time"] is None or extent.D["end_time"] is None:
  408. return False
  409. if self.D["end_time"] == extent.D["end_time"] and \
  410. self.D["start_time"] < extent.D["start_time"]:
  411. return True
  412. else:
  413. return False
  414. def after(self, extent):
  415. """!Return True if this temporal extent (A) is located after the
  416. provided temporal extent (B)
  417. @verbatim
  418. A |---------|
  419. B |---------|
  420. @endverbatim
  421. @param extent The temporal extent object that is located before this extent
  422. Usage:
  423. @code
  424. >>> A = AbstractTemporalExtent(start_time=8, end_time=9 )
  425. >>> B = AbstractTemporalExtent(start_time=6, end_time=7 )
  426. >>> A.after(B)
  427. True
  428. >>> B.after(A)
  429. False
  430. @endcode
  431. """
  432. if extent.D["end_time"] is None:
  433. if self.D["start_time"] > extent.D["start_time"]:
  434. return True
  435. else:
  436. return False
  437. if self.D["start_time"] > extent.D["end_time"]:
  438. return True
  439. else:
  440. return False
  441. def before(self, extent):
  442. """!Return True if this temporal extent (A) is located before the
  443. provided temporal extent (B)
  444. @verbatim
  445. A |---------|
  446. B |---------|
  447. @endverbatim
  448. @param extent The temporal extent object that is located after this extent
  449. Usage:
  450. @code
  451. >>> A = AbstractTemporalExtent(start_time=6, end_time=7 )
  452. >>> B = AbstractTemporalExtent(start_time=8, end_time=9 )
  453. >>> A.before(B)
  454. True
  455. >>> B.before(A)
  456. False
  457. @endcode
  458. """
  459. if self.D["end_time"] is None:
  460. if self.D["start_time"] < extent.D["start_time"]:
  461. return True
  462. else:
  463. return False
  464. if self.D["end_time"] < extent.D["start_time"]:
  465. return True
  466. else:
  467. return False
  468. def adjacent(self, extent):
  469. """!Return True if this temporal extent (A) is a meeting neighbor the
  470. provided temporal extent (B)
  471. @verbatim
  472. A |---------|
  473. B |---------|
  474. A |---------|
  475. B |---------|
  476. @endverbatim
  477. @param extent The temporal extent object that is a meeting neighbor
  478. of this extent
  479. Usage:
  480. @code
  481. >>> A = AbstractTemporalExtent(start_time=5, end_time=7 )
  482. >>> B = AbstractTemporalExtent(start_time=7, end_time=9 )
  483. >>> A.adjacent(B)
  484. True
  485. >>> B.adjacent(A)
  486. True
  487. >>> A = AbstractTemporalExtent(start_time=5, end_time=7 )
  488. >>> B = AbstractTemporalExtent(start_time=3, end_time=5 )
  489. >>> A.adjacent(B)
  490. True
  491. >>> B.adjacent(A)
  492. True
  493. @endcode
  494. """
  495. if self.D["end_time"] is None and extent.D["end_time"] is None:
  496. return False
  497. if (self.D["start_time"] == extent.D["end_time"]) or \
  498. (self.D["end_time"] == extent.D["start_time"]):
  499. return True
  500. else:
  501. return False
  502. def follows(self, extent):
  503. """!Return True if this temporal extent (A) follows the
  504. provided temporal extent (B)
  505. @verbatim
  506. A |---------|
  507. B |---------|
  508. @endverbatim
  509. @param extent The temporal extent object that is the predecessor
  510. of this extent
  511. Usage:
  512. @code
  513. >>> A = AbstractTemporalExtent(start_time=5, end_time=7 )
  514. >>> B = AbstractTemporalExtent(start_time=3, end_time=5 )
  515. >>> A.follows(B)
  516. True
  517. >>> B.follows(A)
  518. False
  519. @endcode
  520. """
  521. if extent.D["end_time"] is None:
  522. return False
  523. if self.D["start_time"] == extent.D["end_time"]:
  524. return True
  525. else:
  526. return False
  527. def precedes(self, extent):
  528. """!Return True if this temporal extent (A) precedes the provided
  529. temporal extent (B)
  530. @verbatim
  531. A |---------|
  532. B |---------|
  533. @endverbatim
  534. @param extent The temporal extent object that is the successor
  535. of this extent
  536. Usage:
  537. @code
  538. >>> A = AbstractTemporalExtent(start_time=5, end_time=7 )
  539. >>> B = AbstractTemporalExtent(start_time=7, end_time=9 )
  540. >>> A.precedes(B)
  541. True
  542. >>> B.precedes(A)
  543. False
  544. @endcode
  545. """
  546. if self.D["end_time"] is None:
  547. return False
  548. if self.D["end_time"] == extent.D["start_time"]:
  549. return True
  550. else:
  551. return False
  552. def during(self, extent):
  553. """!Return True if this temporal extent (A) is located during the provided
  554. temporal extent (B)
  555. @verbatim
  556. A |-------|
  557. B |---------|
  558. @endverbatim
  559. @param extent The temporal extent object that contains this extent
  560. Usage:
  561. @code
  562. >>> A = AbstractTemporalExtent(start_time=5, end_time=7 )
  563. >>> B = AbstractTemporalExtent(start_time=4, end_time=9 )
  564. >>> A.during(B)
  565. True
  566. >>> B.during(A)
  567. False
  568. @endcode
  569. """
  570. # Check single point of time in interval
  571. if extent.D["end_time"] is None:
  572. return False
  573. # Check single point of time in interval
  574. if self.D["end_time"] is None:
  575. if self.D["start_time"] > extent.D["start_time"] and \
  576. self.D["start_time"] < extent.D["end_time"]:
  577. return True
  578. else:
  579. return False
  580. if self.D["start_time"] > extent.D["start_time"] and \
  581. self.D["end_time"] < extent.D["end_time"]:
  582. return True
  583. else:
  584. return False
  585. def contains(self, extent):
  586. """!Return True if this temporal extent (A) contains the provided
  587. temporal extent (B)
  588. @verbatim
  589. A |---------|
  590. B |-------|
  591. @endverbatim
  592. @param extent The temporal extent object that is located
  593. during this extent
  594. Usage:
  595. @code
  596. >>> A = AbstractTemporalExtent(start_time=4, end_time=9 )
  597. >>> B = AbstractTemporalExtent(start_time=5, end_time=8 )
  598. >>> A.contains(B)
  599. True
  600. >>> B.contains(A)
  601. False
  602. @endcode
  603. """
  604. # Check single point of time in interval
  605. if self.D["end_time"] is None:
  606. return False
  607. # Check single point of time in interval
  608. if extent.D["end_time"] is None:
  609. if self.D["start_time"] < extent.D["start_time"] and \
  610. self.D["end_time"] > extent.D["start_time"]:
  611. return True
  612. else:
  613. return False
  614. if self.D["start_time"] < extent.D["start_time"] and \
  615. self.D["end_time"] > extent.D["end_time"]:
  616. return True
  617. else:
  618. return False
  619. def equal(self, extent):
  620. """!Return True if this temporal extent (A) is equal to the provided
  621. temporal extent (B)
  622. @verbatim
  623. A |---------|
  624. B |---------|
  625. @endverbatim
  626. @param extent The temporal extent object that is equal
  627. during this extent
  628. Usage:
  629. @code
  630. >>> A = AbstractTemporalExtent(start_time=5, end_time=6 )
  631. >>> B = AbstractTemporalExtent(start_time=5, end_time=6 )
  632. >>> A.equal(B)
  633. True
  634. >>> B.equal(A)
  635. True
  636. @endcode
  637. """
  638. if self.D["end_time"] is None and extent.D["end_time"] is None:
  639. if self.D["start_time"] == extent.D["start_time"]:
  640. return True
  641. else:
  642. return False
  643. if self.D["end_time"] is None or extent.D["end_time"] is None:
  644. return False
  645. if self.D["start_time"] == extent.D["start_time"] and \
  646. self.D["end_time"] == extent.D["end_time"]:
  647. return True
  648. else:
  649. return False
  650. def overlapped(self, extent):
  651. """!Return True if this temporal extent (A) overlapped the provided
  652. temporal extent (B)
  653. @verbatim
  654. A |---------|
  655. B |---------|
  656. @endverbatim
  657. @param extent The temporal extent object that is overlaps
  658. this extent
  659. Usage:
  660. @code
  661. >>> A = AbstractTemporalExtent(start_time=5, end_time=7 )
  662. >>> B = AbstractTemporalExtent(start_time=6, end_time=8 )
  663. >>> A.overlapped(B)
  664. True
  665. >>> B.overlapped(A)
  666. False
  667. @endcode
  668. """
  669. if self.D["end_time"] is None or extent.D["end_time"] is None:
  670. return False
  671. if self.D["start_time"] < extent.D["start_time"] and \
  672. self.D["end_time"] < extent.D["end_time"] and \
  673. self.D["end_time"] > extent.D["start_time"]:
  674. return True
  675. else:
  676. return False
  677. def overlaps(self, extent):
  678. """!Return True if this temporal extent (A) overlapps the provided
  679. temporal extent (B)
  680. @verbatim
  681. A |---------|
  682. B |---------|
  683. @endverbatim
  684. @param extent The temporal extent object that is overlapped
  685. this extent
  686. Usage:
  687. @code
  688. >>> A = AbstractTemporalExtent(start_time=6, end_time=8 )
  689. >>> B = AbstractTemporalExtent(start_time=5, end_time=7 )
  690. >>> A.overlaps(B)
  691. True
  692. >>> B.overlaps(A)
  693. False
  694. @endcode
  695. """
  696. if self.D["end_time"] is None or extent.D["end_time"] is None:
  697. return False
  698. if self.D["start_time"] > extent.D["start_time"] and \
  699. self.D["end_time"] > extent.D["end_time"] and \
  700. self.D["start_time"] < extent.D["end_time"]:
  701. return True
  702. else:
  703. return False
  704. def temporal_relation(self, extent):
  705. """!Returns the temporal relation between temporal objects
  706. Temporal relationships are implemented after
  707. [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic]
  708. The following temporal relationships are supported:
  709. - equal
  710. - during
  711. - contains
  712. - overlaps
  713. - overlapped
  714. - after
  715. - before
  716. - starts
  717. - finishes
  718. - started
  719. - finished
  720. - follows
  721. - precedes
  722. @param extent The temporal extent
  723. @return The name of the temporal relation or None if no relation found
  724. """
  725. # First check for correct time
  726. if "start_time" not in self.D:
  727. return None
  728. if "end_time" not in self.D:
  729. return None
  730. if "start_time" not in extent.D:
  731. return None
  732. if "end_time" not in extent.D:
  733. return None
  734. # Return None if the start_time is undefined
  735. if self.D["start_time"] is None or extent.D["start_time"] is None:
  736. return None
  737. if self.equal(extent):
  738. return "equal"
  739. if self.during(extent):
  740. return "during"
  741. if self.contains(extent):
  742. return "contains"
  743. if self.overlaps(extent):
  744. return "overlaps"
  745. if self.overlapped(extent):
  746. return "overlapped"
  747. if self.after(extent):
  748. return "after"
  749. if self.before(extent):
  750. return "before"
  751. if self.starts(extent):
  752. return "starts"
  753. if self.finishes(extent):
  754. return "finishes"
  755. if self.started(extent):
  756. return "started"
  757. if self.finished(extent):
  758. return "finished"
  759. if self.follows(extent):
  760. return "follows"
  761. if self.precedes(extent):
  762. return "precedes"
  763. return None
  764. def set_id(self, ident):
  765. """!Convenient method to set the unique identifier (primary key)"""
  766. self.ident = ident
  767. self.D["id"] = ident
  768. def set_start_time(self, start_time):
  769. """!Set the valid start time of the extent"""
  770. self.D["start_time"] = start_time
  771. def set_end_time(self, end_time):
  772. """!Set the valid end time of the extent"""
  773. self.D["end_time"] = end_time
  774. def get_id(self):
  775. """!Convenient method to get the unique identifier (primary key)
  776. @return None if not found
  777. """
  778. if "id" in self.D:
  779. return self.D["id"]
  780. else:
  781. return None
  782. def get_start_time(self):
  783. """!Get the valid start time of the extent
  784. @return None if not found"""
  785. if "start_time" in self.D:
  786. return self.D["start_time"]
  787. else:
  788. return None
  789. def get_end_time(self):
  790. """!Get the valid end time of the extent
  791. @return None if not found"""
  792. if "end_time" in self.D:
  793. return self.D["end_time"]
  794. else:
  795. return None
  796. # Set the properties
  797. id = property(fget=get_id, fset=set_id)
  798. start_time = property(fget=get_start_time, fset=set_start_time)
  799. end_time = property(fget=get_end_time, fset=set_end_time)
  800. def print_info(self):
  801. """!Print information about this class in human readable style"""
  802. # 0123456789012345678901234567890
  803. print " | Start time:................. " + str(self.get_start_time())
  804. print " | End time:................... " + str(self.get_end_time())
  805. def print_shell_info(self):
  806. """!Print information about this class in shell style"""
  807. print "start_time=" + str(self.get_start_time())
  808. print "end_time=" + str(self.get_end_time())
  809. ###############################################################################
  810. class AbsoluteTemporalExtent(AbstractTemporalExtent):
  811. """!This is the absolute time class for all maps and spacetime datasets
  812. start_time and end_time must be of type datetime
  813. """
  814. def __init__(self, table=None, ident=None, start_time=None, end_time=None,
  815. timezone=None):
  816. AbstractTemporalExtent.__init__(
  817. self, table, ident, start_time, end_time)
  818. self.set_timezone(timezone)
  819. def set_timezone(self, timezone):
  820. """!Set the timezone of the map, the timezone is of type string.
  821. Timezones are not supported yet, instead the timezone
  822. is set in the datetime string as offset in minutes.
  823. """
  824. self.D["timezone"] = timezone
  825. def get_timezone(self):
  826. """!Get the timezone of the map
  827. Timezones are not supported yet, instead the timezone
  828. is set in the datetime string as offset in minutes.
  829. @return None if not found"""
  830. if "timezone" in self.D:
  831. return self.D["timezone"]
  832. else:
  833. return None
  834. timezone = property(fget=get_timezone, fset=set_timezone)
  835. def print_info(self):
  836. """!Print information about this class in human readable style"""
  837. # 0123456789012345678901234567890
  838. print " +-------------------- Absolute time -----------------------------------------+"
  839. AbstractTemporalExtent.print_info(self)
  840. #print " | Timezone:................... " + str(self.get_timezone())
  841. def print_shell_info(self):
  842. """!Print information about this class in shell style"""
  843. AbstractTemporalExtent.print_shell_info(self)
  844. #print "timezone=" + str(self.get_timezone())
  845. ###############################################################################
  846. class RasterAbsoluteTime(AbsoluteTemporalExtent):
  847. def __init__(self, ident=None, start_time=None, end_time=None,
  848. timezone=None):
  849. AbsoluteTemporalExtent.__init__(self, "raster_absolute_time",
  850. ident, start_time, end_time, timezone)
  851. class Raster3DAbsoluteTime(AbsoluteTemporalExtent):
  852. def __init__(self, ident=None, start_time=None, end_time=None,
  853. timezone=None):
  854. AbsoluteTemporalExtent.__init__(self, "raster3d_absolute_time",
  855. ident, start_time, end_time, timezone)
  856. class VectorAbsoluteTime(AbsoluteTemporalExtent):
  857. def __init__(self, ident=None, start_time=None, end_time=None,
  858. timezone=None):
  859. AbsoluteTemporalExtent.__init__(self, "vector_absolute_time",
  860. ident, start_time, end_time, timezone)
  861. ###############################################################################
  862. class STDSAbsoluteTime(AbsoluteTemporalExtent):
  863. """!This class implements the absolute time extent for space time dataset
  864. In addition to the existing functionality the granularity and the
  865. map_time are added.
  866. Usage:
  867. @code
  868. >>> init()
  869. >>> A = STDSAbsoluteTime(table="strds_absolute_time",
  870. ... ident="strds@PERMANENT", start_time=datetime(2001, 01, 01),
  871. ... end_time=datetime(2005,01,01), granularity="1 days",
  872. ... map_time="interval")
  873. >>> A.id
  874. 'strds@PERMANENT'
  875. >>> A.start_time
  876. datetime.datetime(2001, 1, 1, 0, 0)
  877. >>> A.end_time
  878. datetime.datetime(2005, 1, 1, 0, 0)
  879. >>> A.granularity
  880. '1 days'
  881. >>> A.map_time
  882. 'interval'
  883. >>> A.print_info()
  884. +-------------------- Absolute time -----------------------------------------+
  885. | Start time:................. 2001-01-01 00:00:00
  886. | End time:................... 2005-01-01 00:00:00
  887. | Granularity:................ 1 days
  888. | Temporal type of maps:...... interval
  889. >>> A.print_shell_info()
  890. start_time=2001-01-01 00:00:00
  891. end_time=2005-01-01 00:00:00
  892. granularity=1 days
  893. map_time=interval
  894. @endcode
  895. """
  896. def __init__(self, table=None, ident=None, start_time=None, end_time=None,
  897. granularity=None, timezone=None, map_time=None):
  898. AbsoluteTemporalExtent.__init__(
  899. self, table, ident, start_time, end_time, timezone)
  900. self.set_granularity(granularity)
  901. self.set_map_time(map_time)
  902. def set_granularity(self, granularity):
  903. """!Set the granularity of the space time dataset"""
  904. self.D["granularity"] = granularity
  905. def set_map_time(self, map_time):
  906. """!Set the type of the map time
  907. Registered maps may have different types of time:
  908. - Single point of time "point"
  909. - Time intervals "interval"
  910. - Single point and interval time "mixed"
  911. This variable will be set automatically when maps are registered.
  912. """
  913. self.D["map_time"] = map_time
  914. def get_granularity(self):
  915. """!Get the granularity of the space time dataset
  916. @return None if not found"""
  917. if "granularity" in self.D:
  918. return self.D["granularity"]
  919. else:
  920. return None
  921. def get_map_time(self):
  922. """!Get the type of the map time
  923. Registered maps may have different types of time:
  924. Single point of time "point"
  925. Time intervals "interval"
  926. Or single point and interval time "mixed"
  927. This variable will be set automatically when maps are registered.
  928. """
  929. if "map_time" in self.D:
  930. return self.D["map_time"]
  931. else:
  932. return None
  933. # Properties
  934. granularity = property(fget=get_granularity, fset=set_granularity)
  935. map_time = property(fget=get_map_time, fset=set_map_time)
  936. def print_info(self):
  937. """!Print information about this class in human readable style"""
  938. AbsoluteTemporalExtent.print_info(self)
  939. # 0123456789012345678901234567890
  940. print " | Granularity:................ " + str(self.get_granularity())
  941. print " | Temporal type of maps:...... " + str(self.get_map_time())
  942. def print_shell_info(self):
  943. """!Print information about this class in shell style"""
  944. AbsoluteTemporalExtent.print_shell_info(self)
  945. print "granularity=" + str(self.get_granularity())
  946. print "map_time=" + str(self.get_map_time())
  947. ###############################################################################
  948. class STRDSAbsoluteTime(STDSAbsoluteTime):
  949. def __init__(self, ident=None, start_time=None, end_time=None,
  950. granularity=None, timezone=None):
  951. STDSAbsoluteTime.__init__(self, "strds_absolute_time",
  952. ident, start_time, end_time, granularity, timezone)
  953. class STR3DSAbsoluteTime(STDSAbsoluteTime):
  954. def __init__(self, ident=None, start_time=None, end_time=None,
  955. granularity=None, timezone=None):
  956. STDSAbsoluteTime.__init__(self, "str3ds_absolute_time",
  957. ident, start_time, end_time, granularity, timezone)
  958. class STVDSAbsoluteTime(STDSAbsoluteTime):
  959. def __init__(self, ident=None, start_time=None, end_time=None,
  960. granularity=None, timezone=None):
  961. STDSAbsoluteTime.__init__(self, "stvds_absolute_time",
  962. ident, start_time, end_time, granularity, timezone)
  963. ###############################################################################
  964. class RelativeTemporalExtent(AbstractTemporalExtent):
  965. """!This is the relative time class for all maps and space time datasets
  966. start_time and end_time must be of type integer
  967. Usage:
  968. @code
  969. >>> init()
  970. >>> A = RelativeTemporalExtent(table="raster_relative_time",
  971. ... ident="soil@PERMANENT", start_time=0, end_time=1, unit="years")
  972. >>> A.id
  973. 'soil@PERMANENT'
  974. >>> A.start_time
  975. 0
  976. >>> A.end_time
  977. 1
  978. >>> A.unit
  979. 'years'
  980. >>> A.print_info()
  981. +-------------------- Relative time -----------------------------------------+
  982. | Start time:................. 0
  983. | End time:................... 1
  984. | Relative time unit:......... years
  985. >>> A.print_shell_info()
  986. start_time=0
  987. end_time=1
  988. unit=years
  989. @endcode
  990. """
  991. def __init__(self, table=None, ident=None, start_time=None, end_time=None,
  992. unit=None):
  993. AbstractTemporalExtent.__init__(
  994. self, table, ident, start_time, end_time)
  995. self.D["unit"] = unit
  996. def set_unit(self, unit):
  997. """!Set the unit of the relative time. Valid units are:
  998. - years
  999. - months
  1000. - days
  1001. - hours
  1002. - minutes
  1003. - seconds
  1004. """
  1005. self.D["unit"] = unit
  1006. def get_unit(self):
  1007. """!Get the unit of the relative time
  1008. @return None if not found"""
  1009. if "unit" in self.D:
  1010. return self.D["unit"]
  1011. else:
  1012. return None
  1013. def temporal_relation(self, map):
  1014. """!Returns the temporal relation between temporal objects
  1015. Temporal relationships are implemented after
  1016. [Allen and Ferguson 1994 Actions and Events in Interval Temporal Logic]
  1017. """
  1018. # Check units for relative time
  1019. if "unit" not in self.D:
  1020. return None
  1021. if "unit" not in map.D:
  1022. return None
  1023. # Units must be equal
  1024. if self.D["unit"] != map.D["unit"]:
  1025. return None
  1026. return AbstractTemporalExtent.temporal_relation(self, map)
  1027. # Properties
  1028. unit = property(fget=get_unit, fset=set_unit)
  1029. def print_info(self):
  1030. """!Print information about this class in human readable style"""
  1031. # 0123456789012345678901234567890
  1032. print " +-------------------- Relative time -----------------------------------------+"
  1033. AbstractTemporalExtent.print_info(self)
  1034. print " | Relative time unit:......... " + str(self.get_unit())
  1035. def print_shell_info(self):
  1036. """!Print information about this class in shell style"""
  1037. AbstractTemporalExtent.print_shell_info(self)
  1038. print "unit=" + str(self.get_unit())
  1039. ###############################################################################
  1040. class RasterRelativeTime(RelativeTemporalExtent):
  1041. def __init__(self, ident=None, start_time=None, end_time=None):
  1042. RelativeTemporalExtent.__init__(
  1043. self, "raster_relative_time", ident, start_time, end_time)
  1044. class Raster3DRelativeTime(RelativeTemporalExtent):
  1045. def __init__(self, ident=None, start_time=None, end_time=None):
  1046. RelativeTemporalExtent.__init__(self,
  1047. "raster3d_relative_time", ident, start_time, end_time)
  1048. class VectorRelativeTime(RelativeTemporalExtent):
  1049. def __init__(self, ident=None, start_time=None, end_time=None):
  1050. RelativeTemporalExtent.__init__(
  1051. self, "vector_relative_time", ident, start_time, end_time)
  1052. ###############################################################################
  1053. class STDSRelativeTime(RelativeTemporalExtent):
  1054. """!This is the relative time class for all maps and space time datasets
  1055. start_time and end_time must be of type integer
  1056. Usage:
  1057. @code
  1058. >>> init()
  1059. >>> A = STDSRelativeTime(table="strds_relative_time",
  1060. ... ident="strds@PERMANENT", start_time=0, end_time=1, unit="years",
  1061. ... granularity=5, map_time="interval")
  1062. >>> A.id
  1063. 'strds@PERMANENT'
  1064. >>> A.start_time
  1065. 0
  1066. >>> A.end_time
  1067. 1
  1068. >>> A.unit
  1069. 'years'
  1070. >>> A.granularity
  1071. 5
  1072. >>> A.map_time
  1073. 'interval'
  1074. >>> A.print_info()
  1075. +-------------------- Relative time -----------------------------------------+
  1076. | Start time:................. 0
  1077. | End time:................... 1
  1078. | Relative time unit:......... years
  1079. | Granularity:................ 5
  1080. | Temporal type of maps:...... interval
  1081. >>> A.print_shell_info()
  1082. start_time=0
  1083. end_time=1
  1084. unit=years
  1085. granularity=5
  1086. map_time=interval
  1087. @endcode
  1088. """
  1089. def __init__(self, table=None, ident=None, start_time=None, end_time=None,
  1090. unit=None, granularity=None, map_time=None):
  1091. RelativeTemporalExtent.__init__(
  1092. self, table, ident, start_time, end_time, unit)
  1093. self.set_granularity(granularity)
  1094. self.set_map_time(map_time)
  1095. def set_granularity(self, granularity):
  1096. """!Set the granularity of the space time dataset"""
  1097. self.D["granularity"] = granularity
  1098. def set_map_time(self, map_time):
  1099. """!Set the type of the map time
  1100. Registered maps may have different types of time:
  1101. Single point of time "point"
  1102. Time intervals "interval"
  1103. Or single point and interval time "mixed"
  1104. This variable will be set automatically when maps are registered.
  1105. """
  1106. self.D["map_time"] = map_time
  1107. def get_granularity(self):
  1108. """!Get the granularity of the space time dataset
  1109. @return None if not found"""
  1110. if "granularity" in self.D:
  1111. return self.D["granularity"]
  1112. else:
  1113. return None
  1114. def get_map_time(self):
  1115. """!Get the type of the map time
  1116. Registered maps may have different types of time:
  1117. Single point of time "point"
  1118. Time intervals "interval"
  1119. Or single point and interval time "mixed"
  1120. This variable will be set automatically when maps are registered.
  1121. """
  1122. if "map_time" in self.D:
  1123. return self.D["map_time"]
  1124. else:
  1125. return None
  1126. # Properties
  1127. granularity = property(fget=get_granularity, fset=set_granularity)
  1128. map_time = property(fget=get_map_time, fset=set_map_time)
  1129. def print_info(self):
  1130. """!Print information about this class in human readable style"""
  1131. RelativeTemporalExtent.print_info(self)
  1132. # 0123456789012345678901234567890
  1133. print " | Granularity:................ " + str(self.get_granularity())
  1134. print " | Temporal type of maps:...... " + str(self.get_map_time())
  1135. def print_shell_info(self):
  1136. """!Print information about this class in shell style"""
  1137. RelativeTemporalExtent.print_shell_info(self)
  1138. print "granularity=" + str(self.get_granularity())
  1139. print "map_time=" + str(self.get_map_time())
  1140. ###############################################################################
  1141. class STRDSRelativeTime(STDSRelativeTime):
  1142. def __init__(self, ident=None, start_time=None, end_time=None,
  1143. granularity=None):
  1144. STDSRelativeTime.__init__(self, "strds_relative_time",
  1145. ident, start_time, end_time, granularity)
  1146. class STR3DSRelativeTime(STDSRelativeTime):
  1147. def __init__(self, ident=None, start_time=None, end_time=None,
  1148. granularity=None):
  1149. STDSRelativeTime.__init__(self, "str3ds_relative_time",
  1150. ident, start_time, end_time, granularity)
  1151. class STVDSRelativeTime(STDSRelativeTime):
  1152. def __init__(self, ident=None, start_time=None, end_time=None,
  1153. granularity=None):
  1154. STDSRelativeTime.__init__(self, "stvds_relative_time",
  1155. ident, start_time, end_time, granularity)
  1156. ###############################################################################
  1157. if __name__ == "__main__":
  1158. import doctest
  1159. doctest.testmod()