spatio_temporal_relationships.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. """!@package grass.temporal
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS related functions to be used in temporal GIS Python library package.
  4. Usage:
  5. @code
  6. import grass.temporal as tgis
  7. tgis.print_temporal_relations(maps)
  8. ...
  9. @endcode
  10. (C) 2008-2011 by the GRASS Development Team
  11. This program is free software under the GNU General Public
  12. License (>=v2). Read the file COPYING that comes with GRASS
  13. for details.
  14. @author Soeren Gebbert
  15. """
  16. from abstract_dataset import *
  17. from datetime_math import *
  18. import grass.lib.vector as vector
  19. import grass.lib.gis as gis
  20. from ctypes import *
  21. ###############################################################################
  22. class SpatioTemporalTopologyBuilder(object):
  23. """!This class is designed to build the spatio-temporal topology
  24. of spatio-temporally related abstract dataset objects.
  25. The abstract dataset objects must be provided as a single list, or in two lists.
  26. Example:
  27. @code
  28. # We have a space time raster dataset and build a map list
  29. # from all registered maps ordered by start time
  30. maps = strds.get_registered_maps_as_objects()
  31. # Now lets build the temporal topology of the maps in the list
  32. tb = SpatioTemporalTopologyBuilder()
  33. tb.build(maps)
  34. dbif, connected = init_dbif(None)
  35. for map in tb:
  36. map.select(dbif)
  37. map.print_info()
  38. # Same can be done with the existing map list
  39. # But be aware that this is might not be temporally ordered
  40. for map in maps:
  41. map.select(dbf)
  42. map.print_info()
  43. # Using the next and previous methods, we can iterate over the
  44. # topological related maps in this way
  45. first = tb.get_first()
  46. while first:
  47. first.print_topology_info()
  48. first = first.next()
  49. # Dictionary like accessed
  50. map = tb["name@mapset"]
  51. >>> # Example with two lists of maps
  52. >>> import grass.temporal as tgis
  53. >>> # Create two list of maps with equal time stamps
  54. >>> mapsA = []
  55. >>> mapsB = []
  56. >>> for i in range(10):
  57. ... idA = "a%i@B"%(i)
  58. ... mapA = tgis.RasterDataset(idA)
  59. ... idB = "b%i@B"%(i)
  60. ... mapB = tgis.RasterDataset(idB)
  61. ... check = mapA.set_relative_time(i, i + 1, "months")
  62. ... check = mapB.set_relative_time(i, i + 1, "months")
  63. ... mapsA.append(mapA)
  64. ... mapsB.append(mapB)
  65. >>> # Build the topology between the two map lists
  66. >>> tb = SpatioTemporalTopologyBuilder()
  67. >>> tb.build(mapsA, mapsB, None)
  68. >>> # Check relations of mapsA
  69. >>> for map in mapsA:
  70. ... if map.get_equal():
  71. ... relations = map.get_equal()
  72. ... print "Map %s has equal relation to map %s"%(map.get_name(),
  73. ... relations[0].get_name())
  74. Map a0 has equal relation to map b0
  75. Map a1 has equal relation to map b1
  76. Map a2 has equal relation to map b2
  77. Map a3 has equal relation to map b3
  78. Map a4 has equal relation to map b4
  79. Map a5 has equal relation to map b5
  80. Map a6 has equal relation to map b6
  81. Map a7 has equal relation to map b7
  82. Map a8 has equal relation to map b8
  83. Map a9 has equal relation to map b9
  84. >>> # Check relations of mapsB
  85. >>> for map in mapsB:
  86. ... if map.get_equal():
  87. ... relations = map.get_equal()
  88. ... print "Map %s has equal relation to map %s"%(map.get_name(),
  89. ... relations[0].get_name())
  90. Map b0 has equal relation to map a0
  91. Map b1 has equal relation to map a1
  92. Map b2 has equal relation to map a2
  93. Map b3 has equal relation to map a3
  94. Map b4 has equal relation to map a4
  95. Map b5 has equal relation to map a5
  96. Map b6 has equal relation to map a6
  97. Map b7 has equal relation to map a7
  98. Map b8 has equal relation to map a8
  99. Map b9 has equal relation to map a9
  100. @endcode
  101. """
  102. def __init__(self):
  103. self._reset()
  104. # 0001-01-01 00:00:00
  105. self._timeref = datetime(1,1,1)
  106. def _reset(self):
  107. self._store = {}
  108. self._first = None
  109. self._iteratable = False
  110. def _set_first(self, first):
  111. self._first = first
  112. self._insert(first)
  113. def _detect_first(self):
  114. if len(self) > 0:
  115. prev_ = self._store.values()[0]
  116. while prev_ is not None:
  117. self._first = prev_
  118. prev_ = prev_.prev()
  119. def _insert(self, t):
  120. self._store[t.get_id()] = t
  121. def get_first(self):
  122. """!Return the first map with the earliest start time
  123. @return The map with the earliest start time
  124. """
  125. return self._first
  126. def _build_internal_iteratable(self, maps, spatial):
  127. """!Build an iteratable temporal topology structure for all maps in
  128. the list and store the maps internally
  129. Basically the "next" and "prev" relations will be set in the
  130. temporal topology structure of each map
  131. The maps will be added to the object, so they can be
  132. accessed using the iterator of this class
  133. @param maps A sorted (by start_time)list of abstract_dataset
  134. objects with initiated temporal extent
  135. """
  136. self._build_iteratable(maps, spatial)
  137. for _map in maps:
  138. self._insert(_map)
  139. # Detect the first map
  140. self._detect_first()
  141. def _build_iteratable(self, maps, spatial):
  142. """!Build an iteratable temporal topology structure for
  143. all maps in the list
  144. Basically the "next" and "prev" relations will be set in
  145. the temporal topology structure of each map.
  146. @param maps A sorted (by start_time)list of abstract_dataset
  147. objects with initiated temporal extent
  148. """
  149. # for i in xrange(len(maps)):
  150. # offset = i + 1
  151. # for j in xrange(offset, len(maps)):
  152. # # Get the temporal relationship
  153. # relation = maps[j].temporal_relation(maps[i])
  154. #
  155. # # Build the next reference
  156. # if relation != "equal" and relation != "started":
  157. # maps[i].set_next(maps[j])
  158. # break
  159. # First we need to order the map list chronologically
  160. sorted_maps = sorted(
  161. maps, key=AbstractDatasetComparisonKeyStartTime)
  162. for i in xrange(len(sorted_maps) - 1):
  163. sorted_maps[i].set_next(sorted_maps[i + 1])
  164. for map_ in sorted_maps:
  165. next_ = map_.next()
  166. if next_:
  167. next_.set_prev(map_)
  168. map_.set_temporal_topology_build_true()
  169. if spatial is not None:
  170. map_.set_spatial_topology_build_true()
  171. def _map_to_rect(self, tree, map_, spatial=None):
  172. """Use the temporal extent of a map to create and return a RTree rectange
  173. @param spatial This indicates if the spatial topology is created as well:
  174. spatial can be None (no spatial topology), "2D" using west, east,
  175. #south, north or "3D" using west, east, south, north, bottom, top
  176. """
  177. rect = vector.RTreeAllocRect(tree)
  178. start, end = map_.get_temporal_extent_as_tuple()
  179. if not end:
  180. end = start
  181. if map_.is_time_absolute():
  182. start = time_delta_to_relative_time(start - self._timeref)
  183. end = time_delta_to_relative_time(end - self._timeref)
  184. if spatial is None:
  185. vector.RTreeSetRect1D(rect, tree, float(start), float(end))
  186. elif spatial == "2D":
  187. north, south, east, west, top, bottom = map_.get_spatial_extent_as_tuple()
  188. vector.RTreeSetRect3D(rect, tree, west, east, south, north,
  189. float(start), float(end))
  190. elif spatial == "3D":
  191. north, south, east, west, top, bottom = map_.get_spatial_extent_as_tuple()
  192. vector.RTreeSetRect4D(rect, tree, west, east, south, north,
  193. bottom, top, float(start), float(end))
  194. return rect
  195. def _build_rtree(self, maps, spatial=None):
  196. """Build and return the 1-4 dimensional R*-Tree
  197. @param spatial This indicates if the spatial topology is created as well:
  198. spatial can be None (no spatial topology), "2D" using west, east,
  199. south, north or "3D" using west, east, south, north, bottom, top
  200. """
  201. dim = 1
  202. if spatial == "2D":
  203. dim = 3
  204. if spatial == "3D":
  205. dim = 4
  206. tree = vector.RTreeCreateTree(-1, 0, dim)
  207. for i in xrange(len(maps)):
  208. rect = self._map_to_rect(tree, maps[i], spatial)
  209. vector.RTreeInsertRect(rect, i + 1, tree)
  210. return tree
  211. def build(self, mapsA, mapsB=None, spatial=None):
  212. """!Build the spatio-temporal topology structure between
  213. one or two unordered lists of abstract dataset objects
  214. This method builds the temporal or spatio-temporal topology from mapsA to
  215. mapsB and vice verse. The spatio-temporal topology structure of each map
  216. will be reseted and rebuild for mapsA and mapsB.
  217. After building the temporal or spatio-temporal topology the modified
  218. map objects of mapsA can be accessed
  219. in the same way as a dictionary using there id.
  220. The implemented iterator assures
  221. the chronological iteration over the mapsA.
  222. @param mapsA A list of abstract_dataset
  223. objects with initiated spatio-temporal extent
  224. @param mapsB An optional list of abstract_dataset
  225. objects with initiated spatio-temporal extent
  226. @param spatial This indicates if the spatial topology is created as well:
  227. spatial can be None (no spatial topology), "2D" using west, east,
  228. south, north or "3D" using west, east, south, north, bottom, top
  229. """
  230. identical = False
  231. if mapsA == mapsB:
  232. identical = True
  233. if mapsB == None:
  234. mapsB = mapsA
  235. idetnical = True
  236. for map_ in mapsA:
  237. map_.reset_topology()
  238. if not identical:
  239. for map_ in mapsB:
  240. map_.reset_topology()
  241. tree = self. _build_rtree(mapsA, spatial)
  242. for j in xrange(len(mapsB)):
  243. list_ = gis.ilist()
  244. rect = self._map_to_rect(tree, mapsB[j], spatial)
  245. num = vector.RTreeSearch2(tree, rect, byref(list_))
  246. vector.RTreeFreeRect(rect)
  247. for k in xrange(list_.n_values):
  248. i = list_.value[k] - 1
  249. # Get the temporal relationship
  250. relation = mapsB[j].temporal_relation(mapsA[i])
  251. A = mapsA[i]
  252. B = mapsB[j]
  253. set_temoral_relationship(A, B, relation)
  254. if spatial is not None:
  255. relation = mapsB[j].spatial_relation(mapsA[i])
  256. set_spatial_relationship(A, B, relation)
  257. self._build_internal_iteratable(mapsA, spatial)
  258. if not identical and mapsB != None:
  259. self._build_iteratable(mapsB, spatial)
  260. vector.RTreeDestroyTree(tree)
  261. def __iter__(self):
  262. start_ = self._first
  263. while start_ is not None:
  264. yield start_
  265. start_ = start_.next()
  266. def __getitem__(self, index):
  267. return self._store[index.get_id()]
  268. def __len__(self):
  269. return len(self._store)
  270. def __contains__(self, _map):
  271. return _map in self._store.values()
  272. ###############################################################################
  273. def set_temoral_relationship(A, B, relation):
  274. if relation == "equal":
  275. if B != A:
  276. if not B.get_equal() or \
  277. (B.get_equal() and \
  278. A not in B.get_equal()):
  279. B.append_equal(A)
  280. if not A.get_equal() or \
  281. (A.get_equal() and \
  282. B not in A.get_equal()):
  283. A.append_equal(B)
  284. elif relation == "follows":
  285. if not B.get_follows() or \
  286. (B.get_follows() and \
  287. A not in B.get_follows()):
  288. B.append_follows(A)
  289. if not A.get_precedes() or \
  290. (A.get_precedes() and
  291. B not in A.get_precedes()):
  292. A.append_precedes(B)
  293. elif relation == "precedes":
  294. if not B.get_precedes() or \
  295. (B.get_precedes() and \
  296. A not in B.get_precedes()):
  297. B.append_precedes(A)
  298. if not A.get_follows() or \
  299. (A.get_follows() and \
  300. B not in A.get_follows()):
  301. A.append_follows(B)
  302. elif relation == "during" or relation == "starts" or \
  303. relation == "finishes":
  304. if not B.get_during() or \
  305. (B.get_during() and \
  306. A not in B.get_during()):
  307. B.append_during(A)
  308. if not A.get_contains() or \
  309. (A.get_contains() and \
  310. B not in A.get_contains()):
  311. A.append_contains(B)
  312. if relation == "starts":
  313. if not B.get_starts() or \
  314. (B.get_starts() and \
  315. A not in B.get_starts()):
  316. B.append_starts(A)
  317. if not A.get_started() or \
  318. (A.get_started() and \
  319. B not in A.get_started()):
  320. A.append_started(B)
  321. if relation == "finishes":
  322. if not B.get_finishes() or \
  323. (B.get_finishes() and \
  324. A not in B.get_finishes()):
  325. B.append_finishes(A)
  326. if not A.get_finished() or \
  327. (A.get_finished() and \
  328. B not in A.get_finished()):
  329. A.append_finished(B)
  330. elif relation == "contains" or relation == "started" or \
  331. relation == "finished":
  332. if not B.get_contains() or \
  333. (B.get_contains() and \
  334. A not in B.get_contains()):
  335. B.append_contains(A)
  336. if not A.get_during() or \
  337. (A.get_during() and \
  338. B not in A.get_during()):
  339. A.append_during(B)
  340. if relation == "started":
  341. if not B.get_started() or \
  342. (B.get_started() and \
  343. A not in B.get_started()):
  344. B.append_started(A)
  345. if not A.get_starts() or \
  346. (A.get_starts() and \
  347. B not in A.get_starts()):
  348. A.append_starts(B)
  349. if relation == "finished":
  350. if not B.get_finished() or \
  351. (B.get_finished() and \
  352. A not in B.get_finished()):
  353. B.append_finished(A)
  354. if not A.get_finishes() or \
  355. (A.get_finishes() and \
  356. B not in A.get_finishes()):
  357. A.append_finishes(B)
  358. elif relation == "overlaps":
  359. if not B.get_overlaps() or \
  360. (B.get_overlaps() and \
  361. A not in B.get_overlaps()):
  362. B.append_overlaps(A)
  363. if not A.get_overlapped() or \
  364. (A.get_overlapped() and \
  365. B not in A.get_overlapped()):
  366. A.append_overlapped(B)
  367. elif relation == "overlapped":
  368. if not B.get_overlapped() or \
  369. (B.get_overlapped() and \
  370. A not in B.get_overlapped()):
  371. B.append_overlapped(A)
  372. if not A.get_overlaps() or \
  373. (A.get_overlaps() and \
  374. B not in A.get_overlaps()):
  375. A.append_overlaps(B)
  376. ###############################################################################
  377. def set_spatial_relationship(A, B, relation):
  378. if relation == "equivalent":
  379. if B != A:
  380. if not B.get_equivalent() or \
  381. (B.get_equivalent() and \
  382. A not in B.get_equivalent()):
  383. B.append_equivalent(A)
  384. if not A.get_equivalent() or \
  385. (A.get_equivalent() and \
  386. B not in A.get_equivalent()):
  387. A.append_equivalent(B)
  388. elif relation == "overlap":
  389. if not B.get_overlap() or \
  390. (B.get_overlap() and \
  391. A not in B.get_overlap()):
  392. B.append_overlap(A)
  393. if not A.get_overlap() or \
  394. (A.get_overlap() and
  395. B not in A.get_overlap()):
  396. A.append_overlap(B)
  397. elif relation == "meet":
  398. if not B.get_meet() or \
  399. (B.get_meet() and \
  400. A not in B.get_meet()):
  401. B.append_meet(A)
  402. if not A.get_meet() or \
  403. (A.get_meet() and
  404. B not in A.get_meet()):
  405. A.append_meet(B)
  406. elif relation == "contain":
  407. if not B.get_contain() or \
  408. (B.get_contain() and \
  409. A not in B.get_contain()):
  410. B.append_contain(A)
  411. if not A.get_in() or \
  412. (A.get_in() and \
  413. B not in A.get_in()):
  414. A.append_in(B)
  415. elif relation == "in":
  416. if not B.get_in() or \
  417. (B.get_in() and \
  418. A not in B.get_in()):
  419. B.append_in(A)
  420. if not A.get_contain() or \
  421. (A.get_contain() and \
  422. B not in A.get_contain()):
  423. A.append_contain(B)
  424. elif relation == "cover":
  425. if not B.get_cover() or \
  426. (B.get_cover() and \
  427. A not in B.get_cover()):
  428. B.append_cover(A)
  429. if not A.get_covered() or \
  430. (A.get_covered() and \
  431. B not in A.get_covered()):
  432. A.append_covered(B)
  433. elif relation == "covered":
  434. if not B.get_covered() or \
  435. (B.get_covered() and \
  436. A not in B.get_covered()):
  437. B.append_covered(A)
  438. if not A.get_cover() or \
  439. (A.get_cover() and \
  440. B not in A.get_cover()):
  441. A.append_cover(B)
  442. ###############################################################################
  443. def print_temporal_topology_relationships(maps1, maps2=None, dbif=None):
  444. """!Print the temporal relationships of the
  445. map lists maps1 and maps2 to stdout.
  446. @param maps1 A list of abstract_dataset
  447. objects with initiated temporal extent
  448. @param maps2 An optional list of abstract_dataset
  449. objects with initiated temporal extent
  450. @param dbif The database interface to be used
  451. """
  452. tb = SpatioTemporalTopologyBuilder()
  453. tb.build(maps1, maps2)
  454. dbif, connected = init_dbif(dbif)
  455. for _map in tb:
  456. _map.select(dbif)
  457. _map.print_info()
  458. if connected:
  459. dbif.close()
  460. return
  461. ###############################################################################
  462. def print_spatio_temporal_topology_relationships(maps1, maps2=None, spatial="2D", dbif=None):
  463. """!Print the temporal relationships of the
  464. map lists maps1 and maps2 to stdout.
  465. @param maps1 A list of abstract_dataset
  466. objects with initiated temporal extent
  467. @param maps2 An optional list of abstract_dataset
  468. objects with initiated temporal extent
  469. @param spatial The dimension of the spatial extent to be used: "2D" using west, east,
  470. south, north or "3D" using west, east, south, north, bottom, top
  471. @param dbif The database interface to be used
  472. """
  473. tb = SpatioTemporalTopologyBuilder()
  474. tb.build(maps1, maps2, spatial)
  475. dbif, connected = init_dbif(dbif)
  476. for _map in tb:
  477. _map.select(dbif)
  478. _map.print_info()
  479. if connected:
  480. dbif.close()
  481. return
  482. ###############################################################################
  483. def count_temporal_topology_relationships(maps1, maps2=None, dbif=None):
  484. """!Count the temporal relations of a single list of maps or between two lists of maps
  485. @param maps1 A list of abstract_dataset
  486. objects with initiated temporal extent
  487. @param maps2 A list of abstract_dataset
  488. objects with initiated temporal extent
  489. @param dbif The database interface to be used
  490. @return A dictionary with counted temporal relationships
  491. """
  492. tb = SpatioTemporalTopologyBuilder()
  493. tb.build(maps1, maps2)
  494. dbif, connected = init_dbif(dbif)
  495. relations = None
  496. for _map in tb:
  497. if relations != None:
  498. r = _map.get_number_of_relations()
  499. for k in r.keys():
  500. relations[k] += r[k]
  501. else:
  502. relations = _map.get_number_of_relations()
  503. if connected:
  504. dbif.close()
  505. return relations
  506. ###############################################################################
  507. def create_temporal_relation_sql_where_statement(
  508. start, end, use_start=True, use_during=False,
  509. use_overlap=False, use_contain=False, use_equal=False,
  510. use_follows=False, use_precedes=False):
  511. """!Create a SQL WHERE statement for temporal relation selection of maps in space time datasets
  512. @param start The start time
  513. @param end The end time
  514. @param use_start Select maps of which the start time is located in the selection granule
  515. @verbatim
  516. map : s
  517. granule: s-----------------e
  518. map : s--------------------e
  519. granule: s-----------------e
  520. map : s--------e
  521. granule: s-----------------e
  522. @endverbatim
  523. @param use_during Select maps which are temporal during the selection granule
  524. @verbatim
  525. map : s-----------e
  526. granule: s-----------------e
  527. @endverbatim
  528. @param use_overlap Select maps which temporal overlap the selection granule
  529. @verbatim
  530. map : s-----------e
  531. granule: s-----------------e
  532. map : s-----------e
  533. granule: s----------e
  534. @endverbatim
  535. @param use_contain Select maps which temporally contain the selection granule
  536. @verbatim
  537. map : s-----------------e
  538. granule: s-----------e
  539. @endverbatim
  540. @param use_equal Select maps which temporally equal to the selection granule
  541. @verbatim
  542. map : s-----------e
  543. granule: s-----------e
  544. @endverbatim
  545. @param use_follows Select maps which temporally follow the selection granule
  546. @verbatim
  547. map : s-----------e
  548. granule: s-----------e
  549. @endverbatim
  550. @param use_precedes Select maps which temporally precedes the selection granule
  551. @verbatim
  552. map : s-----------e
  553. granule: s-----------e
  554. @endverbatim
  555. Usage:
  556. @code
  557. >>> # Relative time
  558. >>> start = 1
  559. >>> end = 2
  560. >>> create_temporal_relation_sql_where_statement(start, end,
  561. ... use_start=False)
  562. >>> create_temporal_relation_sql_where_statement(start, end)
  563. '((start_time >= 1 and start_time < 2) )'
  564. >>> create_temporal_relation_sql_where_statement(start, end,
  565. ... use_start=True)
  566. '((start_time >= 1 and start_time < 2) )'
  567. >>> create_temporal_relation_sql_where_statement(start, end,
  568. ... use_start=False, use_during=True)
  569. '(((start_time > 1 and end_time < 2) OR (start_time >= 1 and end_time < 2) OR (start_time > 1 and end_time <= 2)))'
  570. >>> create_temporal_relation_sql_where_statement(start, end,
  571. ... use_start=False, use_overlap=True)
  572. '(((start_time < 1 and end_time > 1 and end_time < 2) OR (start_time < 2 and start_time > 1 and end_time > 2)))'
  573. >>> create_temporal_relation_sql_where_statement(start, end,
  574. ... use_start=False, use_contain=True)
  575. '(((start_time < 1 and end_time > 2) OR (start_time <= 1 and end_time > 2) OR (start_time < 1 and end_time >= 2)))'
  576. >>> create_temporal_relation_sql_where_statement(start, end,
  577. ... use_start=False, use_equal=True)
  578. '((start_time = 1 and end_time = 2))'
  579. >>> create_temporal_relation_sql_where_statement(start, end,
  580. ... use_start=False, use_follows=True)
  581. '((start_time = 2))'
  582. >>> create_temporal_relation_sql_where_statement(start, end,
  583. ... use_start=False, use_precedes=True)
  584. '((end_time = 1))'
  585. >>> create_temporal_relation_sql_where_statement(start, end,
  586. ... use_start=True, use_during=True, use_overlap=True, use_contain=True,
  587. ... use_equal=True, use_follows=True, use_precedes=True)
  588. '((start_time >= 1 and start_time < 2) OR ((start_time > 1 and end_time < 2) OR (start_time >= 1 and end_time < 2) OR (start_time > 1 and end_time <= 2)) OR ((start_time < 1 and end_time > 1 and end_time < 2) OR (start_time < 2 and start_time > 1 and end_time > 2)) OR ((start_time < 1 and end_time > 2) OR (start_time <= 1 and end_time > 2) OR (start_time < 1 and end_time >= 2)) OR (start_time = 1 and end_time = 2) OR (start_time = 2) OR (end_time = 1))'
  589. >>> # Absolute time
  590. >>> start = datetime(2001, 1, 1, 12, 30)
  591. >>> end = datetime(2001, 3, 31, 14, 30)
  592. >>> create_temporal_relation_sql_where_statement(start, end,
  593. ... use_start=False)
  594. >>> create_temporal_relation_sql_where_statement(start, end)
  595. "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') )"
  596. >>> create_temporal_relation_sql_where_statement(start, end,
  597. ... use_start=True)
  598. "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') )"
  599. >>> create_temporal_relation_sql_where_statement(start, end,
  600. ... use_start=False, use_during=True)
  601. "(((start_time > '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time >= '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time > '2001-01-01 12:30:00' and end_time <= '2001-03-31 14:30:00')))"
  602. >>> create_temporal_relation_sql_where_statement(start, end,
  603. ... use_start=False, use_overlap=True)
  604. "(((start_time < '2001-01-01 12:30:00' and end_time > '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time < '2001-03-31 14:30:00' and start_time > '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00')))"
  605. >>> create_temporal_relation_sql_where_statement(start, end,
  606. ... use_start=False, use_contain=True)
  607. "(((start_time < '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00') OR (start_time <= '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00') OR (start_time < '2001-01-01 12:30:00' and end_time >= '2001-03-31 14:30:00')))"
  608. >>> create_temporal_relation_sql_where_statement(start, end,
  609. ... use_start=False, use_equal=True)
  610. "((start_time = '2001-01-01 12:30:00' and end_time = '2001-03-31 14:30:00'))"
  611. >>> create_temporal_relation_sql_where_statement(start, end,
  612. ... use_start=False, use_follows=True)
  613. "((start_time = '2001-03-31 14:30:00'))"
  614. >>> create_temporal_relation_sql_where_statement(start, end,
  615. ... use_start=False, use_precedes=True)
  616. "((end_time = '2001-01-01 12:30:00'))"
  617. >>> create_temporal_relation_sql_where_statement(start, end,
  618. ... use_start=True, use_during=True, use_overlap=True, use_contain=True,
  619. ... use_equal=True, use_follows=True, use_precedes=True)
  620. "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') OR ((start_time > '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time >= '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time > '2001-01-01 12:30:00' and end_time <= '2001-03-31 14:30:00')) OR ((start_time < '2001-01-01 12:30:00' and end_time > '2001-01-01 12:30:00' and end_time < '2001-03-31 14:30:00') OR (start_time < '2001-03-31 14:30:00' and start_time > '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00')) OR ((start_time < '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00') OR (start_time <= '2001-01-01 12:30:00' and end_time > '2001-03-31 14:30:00') OR (start_time < '2001-01-01 12:30:00' and end_time >= '2001-03-31 14:30:00')) OR (start_time = '2001-01-01 12:30:00' and end_time = '2001-03-31 14:30:00') OR (start_time = '2001-03-31 14:30:00') OR (end_time = '2001-01-01 12:30:00'))"
  621. @endcode
  622. """
  623. where = "("
  624. if use_start:
  625. if isinstance(start, datetime):
  626. where += "(start_time >= '%s' and start_time < '%s') " % (start, end)
  627. else:
  628. where += "(start_time >= %i and start_time < %i) " % (start, end)
  629. if use_during:
  630. if use_start:
  631. where += " OR "
  632. if isinstance(start, datetime):
  633. where += "((start_time > '%s' and end_time < '%s') OR " % (start, end)
  634. where += "(start_time >= '%s' and end_time < '%s') OR " % (start, end)
  635. where += "(start_time > '%s' and end_time <= '%s'))" % (start, end)
  636. else:
  637. where += "((start_time > %i and end_time < %i) OR " % (start, end)
  638. where += "(start_time >= %i and end_time < %i) OR " % (start, end)
  639. where += "(start_time > %i and end_time <= %i))" % (start, end)
  640. if use_overlap:
  641. if use_start or use_during:
  642. where += " OR "
  643. if isinstance(start, datetime):
  644. where += "((start_time < '%s' and end_time > '%s' and end_time < '%s') OR " % (start, start, end)
  645. where += "(start_time < '%s' and start_time > '%s' and end_time > '%s'))" % (end, start, end)
  646. else:
  647. where += "((start_time < %i and end_time > %i and end_time < %i) OR " % (start, start, end)
  648. where += "(start_time < %i and start_time > %i and end_time > %i))" % (end, start, end)
  649. if use_contain:
  650. if use_start or use_during or use_overlap:
  651. where += " OR "
  652. if isinstance(start, datetime):
  653. where += "((start_time < '%s' and end_time > '%s') OR " % (start, end)
  654. where += "(start_time <= '%s' and end_time > '%s') OR " % (start, end)
  655. where += "(start_time < '%s' and end_time >= '%s'))" % (start, end)
  656. else:
  657. where += "((start_time < %i and end_time > %i) OR " % (start, end)
  658. where += "(start_time <= %i and end_time > %i) OR " % (start, end)
  659. where += "(start_time < %i and end_time >= %i))" % (start, end)
  660. if use_equal:
  661. if use_start or use_during or use_overlap or use_contain:
  662. where += " OR "
  663. if isinstance(start, datetime):
  664. where += "(start_time = '%s' and end_time = '%s')" % (start, end)
  665. else:
  666. where += "(start_time = %i and end_time = %i)" % (start, end)
  667. if use_follows:
  668. if use_start or use_during or use_overlap or use_contain or use_equal:
  669. where += " OR "
  670. if isinstance(start, datetime):
  671. where += "(start_time = '%s')" % (end)
  672. else:
  673. where += "(start_time = %i)" % (end)
  674. if use_precedes:
  675. if use_start or use_during or use_overlap or use_contain or use_equal \
  676. or use_follows:
  677. where += " OR "
  678. if isinstance(start, datetime):
  679. where += "(end_time = '%s')" % (start)
  680. else:
  681. where += "(end_time = %i)" % (start)
  682. where += ")"
  683. # Catch empty where statement
  684. if where == "()":
  685. where = None
  686. return where
  687. ###############################################################################
  688. if __name__ == "__main__":
  689. import doctest
  690. doctest.testmod()