temporal_extent.py 41 KB

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