temporal_extent.py 49 KB

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