spatio_temporal_relationships.py 30 KB

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