temporal_extent.py 35 KB

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