temporal_extent.py 49 KB

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