temporal_extent.py 36 KB

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