temporal_extent.py 49 KB

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