temporal_extent.py 49 KB

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