spatio_temporal_relationships.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068
  1. """
  2. Class to build the spatio-temporal topology between map lists
  3. Usage:
  4. .. code-block:: python
  5. import grass.temporal as tgis
  6. tgis.print_temporal_relations(maps)
  7. (C) 2012-2013 by the GRASS Development Team
  8. This program is free software under the GNU General Public
  9. License (>=v2). Read the file COPYING that comes with GRASS
  10. for details.
  11. :authors: Soeren Gebbert
  12. """
  13. from __future__ import print_function
  14. from datetime import datetime
  15. from .core import init_dbif
  16. from .abstract_dataset import AbstractDatasetComparisonKeyStartTime
  17. from .datetime_math import time_delta_to_relative_time_seconds
  18. import grass.lib.vector as vector
  19. import grass.lib.rtree as rtree
  20. import grass.lib.gis as gis
  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
  26. two lists.
  27. Example:
  28. .. code-block:: python
  29. # We have a space time raster dataset and build a map list
  30. # from all registered maps ordered by start time
  31. maps = strds.get_registered_maps_as_objects()
  32. # Now lets build the temporal topology of the maps in the list
  33. tb = SpatioTemporalTopologyBuilder()
  34. tb.build(maps)
  35. dbif, connection_state_changed = init_dbif(None)
  36. for map in tb:
  37. map.select(dbif)
  38. map.print_info()
  39. # Same can be done with the existing map list
  40. # But be aware that this is might not be temporally ordered
  41. for map in maps:
  42. map.select(dbf)
  43. map.print_info()
  44. # Using the next and previous methods, we can iterate over the
  45. # topological related maps in this way
  46. first = tb.get_first()
  47. while first:
  48. first.print_topology_info()
  49. first = first.next()
  50. # Dictionary like accessed
  51. map = tb["name@mapset"]
  52. >>> # Example with two lists of maps
  53. >>> import grass.temporal as tgis
  54. >>> import datetime
  55. >>> # Create two list of maps with equal time stamps
  56. >>> mapsA = []
  57. >>> mapsB = []
  58. >>> for i in range(4):
  59. ... idA = "a%i@B"%(i)
  60. ... mapA = tgis.RasterDataset(idA)
  61. ... idB = "b%i@B"%(i)
  62. ... mapB = tgis.RasterDataset(idB)
  63. ... check = mapA.set_relative_time(i, i + 1, "months")
  64. ... check = mapB.set_relative_time(i, i + 1, "months")
  65. ... mapsA.append(mapA)
  66. ... mapsB.append(mapB)
  67. >>> # Build the topology between the two map lists
  68. >>> tb = SpatioTemporalTopologyBuilder()
  69. >>> tb.build(mapsA, mapsB, None)
  70. >>> # Check relations of mapsA
  71. >>> for map in mapsA:
  72. ... if map.get_equal():
  73. ... relations = map.get_equal()
  74. ... print("Map %s has equal relation to map %s"%(map.get_name(),
  75. ... relations[0].get_name()))
  76. Map a0 has equal relation to map b0
  77. Map a1 has equal relation to map b1
  78. Map a2 has equal relation to map b2
  79. Map a3 has equal relation to map b3
  80. >>> # Check relations of mapsB
  81. >>> for map in mapsB:
  82. ... if map.get_equal():
  83. ... relations = map.get_equal()
  84. ... print("Map %s has equal relation to map %s"%(map.get_name(),
  85. ... relations[0].get_name()))
  86. Map b0 has equal relation to map a0
  87. Map b1 has equal relation to map a1
  88. Map b2 has equal relation to map a2
  89. Map b3 has equal relation to map a3
  90. >>> mapsA = []
  91. >>> mapsB = []
  92. >>> for i in range(4):
  93. ... idA = "a%i@B"%(i)
  94. ... mapA = tgis.RasterDataset(idA)
  95. ... idB = "b%i@B"%(i)
  96. ... mapB = tgis.RasterDataset(idB)
  97. ... check = mapA.set_relative_time(i, i + 1, "months")
  98. ... check = mapB.set_relative_time(i + 1, i + 2, "months")
  99. ... mapsA.append(mapA)
  100. ... mapsB.append(mapB)
  101. >>> # Build the topology between the two map lists
  102. >>> tb = SpatioTemporalTopologyBuilder()
  103. >>> tb.build(mapsA, mapsB, None)
  104. >>> # Check relations of mapsA
  105. >>> for map in mapsA:
  106. ... print(map.get_temporal_extent_as_tuple())
  107. ... m = map.get_temporal_relations()
  108. ... for key in m.keys():
  109. ... if key not in ["NEXT", "PREV"]:
  110. ... print((key, m[key][0].get_temporal_extent_as_tuple()))
  111. (0, 1)
  112. ('PRECEDES', (1, 2))
  113. (1, 2)
  114. ('PRECEDES', (2, 3))
  115. ('EQUAL', (1, 2))
  116. (2, 3)
  117. ('FOLLOWS', (1, 2))
  118. ('PRECEDES', (3, 4))
  119. ('EQUAL', (2, 3))
  120. (3, 4)
  121. ('FOLLOWS', (2, 3))
  122. ('EQUAL', (3, 4))
  123. ('PRECEDES', (4, 5))
  124. >>> mapsA = []
  125. >>> mapsB = []
  126. >>> for i in range(4):
  127. ... idA = "a%i@B"%(i)
  128. ... mapA = tgis.RasterDataset(idA)
  129. ... idB = "b%i@B"%(i)
  130. ... mapB = tgis.RasterDataset(idB)
  131. ... start = datetime.datetime(2000 + i, 1, 1)
  132. ... end = datetime.datetime(2000 + i + 1, 1, 1)
  133. ... check = mapA.set_absolute_time(start, end)
  134. ... start = datetime.datetime(2000 + i + 1, 1, 1)
  135. ... end = datetime.datetime(2000 + i + 2, 1, 1)
  136. ... check = mapB.set_absolute_time(start, end)
  137. ... mapsA.append(mapA)
  138. ... mapsB.append(mapB)
  139. >>> # Build the topology between the two map lists
  140. >>> tb = SpatioTemporalTopologyBuilder()
  141. >>> tb.build(mapsA, mapsB, None)
  142. >>> # Check relations of mapsA
  143. >>> for map in mapsA:
  144. ... print(map.get_temporal_extent_as_tuple())
  145. ... m = map.get_temporal_relations()
  146. ... for key in m.keys():
  147. ... if key not in ["NEXT", "PREV"]:
  148. ... print((key, m[key][0].get_temporal_extent_as_tuple()))
  149. (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0))
  150. ('PRECEDES', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0)))
  151. (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0))
  152. ('PRECEDES', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  153. ('EQUAL', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0)))
  154. (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))
  155. ('FOLLOWS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0)))
  156. ('PRECEDES', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  157. ('EQUAL', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  158. (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))
  159. ('FOLLOWS', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  160. ('EQUAL', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  161. ('PRECEDES', (datetime.datetime(2004, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0)))
  162. >>> mapsA = []
  163. >>> mapsB = []
  164. >>> for i in range(4):
  165. ... idA = "a%i@B"%(i)
  166. ... mapA = tgis.RasterDataset(idA)
  167. ... idB = "b%i@B"%(i)
  168. ... mapB = tgis.RasterDataset(idB)
  169. ... start = datetime.datetime(2000 + i, 1, 1)
  170. ... end = datetime.datetime(2000 + i + 1, 1, 1)
  171. ... check = mapA.set_absolute_time(start, end)
  172. ... start = datetime.datetime(2000 + i, 1, 1)
  173. ... end = datetime.datetime(2000 + i + 3, 1, 1)
  174. ... check = mapB.set_absolute_time(start, end)
  175. ... mapsA.append(mapA)
  176. ... mapsB.append(mapB)
  177. >>> # Build the topology between the two map lists
  178. >>> tb = SpatioTemporalTopologyBuilder()
  179. >>> tb.build(mapsA, mapsB, None)
  180. >>> # Check relations of mapsA
  181. >>> for map in mapsA:
  182. ... print(map.get_temporal_extent_as_tuple())
  183. ... m = map.get_temporal_relations()
  184. ... for key in m.keys():
  185. ... if key not in ["NEXT", "PREV"]:
  186. ... print((key, m[key][0].get_temporal_extent_as_tuple()))
  187. (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0))
  188. ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  189. ('STARTS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  190. ('PRECEDES', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  191. (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0))
  192. ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  193. ('STARTS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  194. ('PRECEDES', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0)))
  195. (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))
  196. ('PRECEDES', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0)))
  197. ('FINISHES', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  198. ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  199. ('STARTS', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0)))
  200. (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))
  201. ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  202. ('DURING', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  203. ('FINISHES', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  204. ('STARTS', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0)))
  205. >>> mapsA = []
  206. >>> mapsB = []
  207. >>> for i in range(4):
  208. ... idA = "a%i@B"%(i)
  209. ... mapA = tgis.RasterDataset(idA)
  210. ... idB = "b%i@B"%(i)
  211. ... mapB = tgis.RasterDataset(idB)
  212. ... start = datetime.datetime(2000 + i, 1, 1)
  213. ... end = datetime.datetime(2000 + i + 2, 1, 1)
  214. ... check = mapA.set_absolute_time(start, end)
  215. ... start = datetime.datetime(2000 + i, 1, 1)
  216. ... end = datetime.datetime(2000 + i + 3, 1, 1)
  217. ... check = mapB.set_absolute_time(start, end)
  218. ... mapsA.append(mapA)
  219. ... mapsB.append(mapB)
  220. >>> # Build the topology between the two map lists
  221. >>> tb = SpatioTemporalTopologyBuilder()
  222. >>> tb.build(mapsA, mapsB, None)
  223. >>> # Check relations of mapsA
  224. >>> for map in mapsA:
  225. ... print(map.get_temporal_extent_as_tuple())
  226. ... m = map.get_temporal_relations()
  227. ... for key in m.keys():
  228. ... if key not in ["NEXT", "PREV"]:
  229. ... print((key, m[key][0].get_temporal_extent_as_tuple()))
  230. (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0))
  231. ('OVERLAPS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  232. ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  233. ('STARTS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  234. ('PRECEDES', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0)))
  235. (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))
  236. ('OVERLAPS', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0)))
  237. ('PRECEDES', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0)))
  238. ('FINISHES', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  239. ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  240. ('STARTS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  241. (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))
  242. ('OVERLAPS', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0)))
  243. ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  244. ('FINISHES', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  245. ('DURING', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  246. ('STARTS', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0)))
  247. (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0))
  248. ('OVERLAPPED', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)))
  249. ('DURING', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0)))
  250. ('FINISHES', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0)))
  251. ('STARTS', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0)))
  252. ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)))
  253. >>> mapsA = []
  254. >>> mapsB = []
  255. >>> for i in range(4):
  256. ... idA = "a%i@B"%(i)
  257. ... mapA = tgis.RasterDataset(idA)
  258. ... idB = "b%i@B"%(i)
  259. ... mapB = tgis.RasterDataset(idB)
  260. ... start = datetime.datetime(2000, 1, 1, 0, 0, i)
  261. ... end = datetime.datetime(2000, 1, 1, 0, 0, i + 2)
  262. ... check = mapA.set_absolute_time(start, end)
  263. ... start = datetime.datetime(2000, 1, 1, 0, 0, i + 1)
  264. ... end = datetime.datetime(2000, 1, 1, 0, 0, i + 3)
  265. ... check = mapB.set_absolute_time(start, end)
  266. ... mapsA.append(mapA)
  267. ... mapsB.append(mapB)
  268. >>> # Build the topology between the two map lists
  269. >>> tb = SpatioTemporalTopologyBuilder()
  270. >>> tb.build(mapsA, mapsB, None)
  271. >>> # Check relations of mapsA
  272. >>> for map in mapsA:
  273. ... print(map.get_temporal_extent_as_tuple())
  274. ... m = map.get_temporal_relations()
  275. ... for key in m.keys():
  276. ... if key not in ["NEXT", "PREV"]:
  277. ... print((key, m[key][0].get_temporal_extent_as_tuple()))
  278. (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2))
  279. ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
  280. ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
  281. (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))
  282. ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
  283. ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)))
  284. ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
  285. (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))
  286. ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)))
  287. ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
  288. ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 4), datetime.datetime(2000, 1, 1, 0, 0, 6)))
  289. ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
  290. (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))
  291. ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 4), datetime.datetime(2000, 1, 1, 0, 0, 6)))
  292. ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
  293. ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
  294. ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)))
  295. >>> mapsA = []
  296. >>> for i in range(4):
  297. ... idA = "a%i@B"%(i)
  298. ... mapA = tgis.RasterDataset(idA)
  299. ... start = datetime.datetime(2000, 1, 1, 0, 0, i)
  300. ... end = datetime.datetime(2000, 1, 1, 0, 0, i + 2)
  301. ... check = mapA.set_absolute_time(start, end)
  302. ... mapsA.append(mapA)
  303. >>> tb = SpatioTemporalTopologyBuilder()
  304. >>> tb.build(mapsA)
  305. >>> # Check relations of mapsA
  306. >>> for map in mapsA:
  307. ... print(map.get_temporal_extent_as_tuple())
  308. ... m = map.get_temporal_relations()
  309. ... for key in m.keys():
  310. ... if key not in ["NEXT", "PREV"]:
  311. ... print((key, m[key][0].get_temporal_extent_as_tuple()))
  312. (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2))
  313. ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
  314. ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
  315. (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))
  316. ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
  317. ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2)))
  318. ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)))
  319. (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))
  320. ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)))
  321. ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2)))
  322. ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
  323. (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))
  324. ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)))
  325. ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)))
  326. """
  327. def __init__(self):
  328. self._reset()
  329. # 0001-01-01 00:00:00
  330. self._timeref = datetime(1, 1, 1)
  331. def _reset(self):
  332. self._store = {}
  333. self._first = None
  334. self._iteratable = False
  335. def _set_first(self, first):
  336. self._first = first
  337. self._insert(first)
  338. def _detect_first(self):
  339. if len(self) > 0:
  340. prev_ = list(self._store.values())[0]
  341. while prev_ is not None:
  342. self._first = prev_
  343. prev_ = prev_.prev()
  344. def _insert(self, t):
  345. self._store[t.get_id()] = t
  346. def get_first(self):
  347. """Return the first map with the earliest start time
  348. :return: The map with the earliest start time
  349. """
  350. return self._first
  351. def _build_internal_iteratable(self, maps, spatial):
  352. """Build an iteratable temporal topology structure for all maps in
  353. the list and store the maps internally
  354. Basically the "next" and "prev" relations will be set in the
  355. temporal topology structure of each map
  356. The maps will be added to the object, so they can be
  357. accessed using the iterator of this class
  358. :param maps: A sorted (by start_time)list of abstract_dataset
  359. objects with initiated temporal extent
  360. """
  361. self._build_iteratable(maps, spatial)
  362. for _map in maps:
  363. self._insert(_map)
  364. # Detect the first map
  365. self._detect_first()
  366. def _build_iteratable(self, maps, spatial):
  367. """Build an iteratable temporal topology structure for
  368. all maps in the list
  369. Basically the "next" and "prev" relations will be set in
  370. the temporal topology structure of each map.
  371. :param maps: A sorted (by start_time)list of abstract_dataset
  372. objects with initiated temporal extent
  373. """
  374. # for i in xrange(len(maps)):
  375. # offset = i + 1
  376. # for j in xrange(offset, len(maps)):
  377. # # Get the temporal relationship
  378. # relation = maps[j].temporal_relation(maps[i])
  379. #
  380. # # Build the next reference
  381. # if relation != "equal" and relation != "started":
  382. # maps[i].set_next(maps[j])
  383. # break
  384. # First we need to order the map list chronologically
  385. sorted_maps = sorted(maps, key=AbstractDatasetComparisonKeyStartTime)
  386. for i in range(len(sorted_maps) - 1):
  387. sorted_maps[i].set_next(sorted_maps[i + 1])
  388. for map_ in sorted_maps:
  389. next_ = map_.next()
  390. if next_:
  391. next_.set_prev(map_)
  392. map_.set_temporal_topology_build_true()
  393. if spatial is not None:
  394. map_.set_spatial_topology_build_true()
  395. def _map_to_rect(self, tree, map_, spatial=None):
  396. """Use the spatio-temporal extent of a map to create and
  397. return a RTree rectangle
  398. :param spatial: This indicates if the spatial topology is created
  399. as well: spatial can be None (no spatial topology),
  400. "2D" using west, east, south, north or "3D" using
  401. west, east, south, north, bottom, top
  402. """
  403. rect = rtree.RTreeAllocRect(tree)
  404. start, end = map_.get_temporal_extent_as_tuple()
  405. if not end:
  406. end = start
  407. if map_.is_time_absolute():
  408. start = time_delta_to_relative_time_seconds(start - self._timeref)
  409. end = time_delta_to_relative_time_seconds(end - self._timeref)
  410. if spatial is None:
  411. rtree.RTreeSetRect1D(rect, tree, float(start), float(end))
  412. elif spatial == "2D":
  413. north, south, east, west, top, bottom = map_.get_spatial_extent_as_tuple()
  414. rtree.RTreeSetRect3D(
  415. rect, tree, west, east, south, north, float(start), float(end)
  416. )
  417. elif spatial == "3D":
  418. north, south, east, west, top, bottom = map_.get_spatial_extent_as_tuple()
  419. rtree.RTreeSetRect4D(
  420. rect,
  421. tree,
  422. west,
  423. east,
  424. south,
  425. north,
  426. bottom,
  427. top,
  428. float(start),
  429. float(end),
  430. )
  431. return rect
  432. def _build_rtree(self, maps, spatial=None):
  433. """Build and return the 1-4 dimensional R*-Tree
  434. :param spatial: This indicates if the spatial topology is created
  435. as well: spatial can be None (no spatial topology),
  436. "2D" using west, east, south, north or "3D" using
  437. west, east, south, north, bottom, top
  438. """
  439. dim = 1
  440. if spatial == "2D":
  441. dim = 3
  442. if spatial == "3D":
  443. dim = 4
  444. tree = rtree.RTreeCreateTree(-1, 0, dim)
  445. for i in range(len(maps)):
  446. rect = self._map_to_rect(tree, maps[i], spatial)
  447. rtree.RTreeInsertRect(rect, i + 1, tree)
  448. return tree
  449. def build(self, mapsA, mapsB=None, spatial=None):
  450. """Build the spatio-temporal topology structure between
  451. one or two unordered lists of abstract dataset objects
  452. This method builds the temporal or spatio-temporal topology from
  453. mapsA to mapsB and vice verse. The spatio-temporal topology
  454. structure of each map will be reset and rebuild for mapsA and
  455. mapsB.
  456. After building the temporal or spatio-temporal topology the modified
  457. map objects of mapsA can be accessed
  458. in the same way as a dictionary using there id.
  459. The implemented iterator assures
  460. the chronological iteration over the mapsA.
  461. :param mapsA: A list of abstract_dataset
  462. objects with initiated spatio-temporal extent
  463. :param mapsB: An optional list of abstract_dataset
  464. objects with initiated spatio-temporal extent
  465. :param spatial: This indicates if the spatial topology is created
  466. as well: spatial can be None (no spatial topology),
  467. "2D" using west, east, south, north or "3D" using
  468. west, east, south, north, bottom, top
  469. """
  470. identical = False
  471. if mapsA == mapsB:
  472. identical = True
  473. if mapsB is None:
  474. mapsB = mapsA
  475. identical = True
  476. for map_ in mapsA:
  477. map_.reset_topology()
  478. if not identical:
  479. for map_ in mapsB:
  480. map_.reset_topology()
  481. tree = self._build_rtree(mapsA, spatial)
  482. list_ = gis.G_new_ilist()
  483. for j in range(len(mapsB)):
  484. rect = self._map_to_rect(tree, mapsB[j], spatial)
  485. vector.RTreeSearch2(tree, rect, list_)
  486. rtree.RTreeFreeRect(rect)
  487. for k in range(list_.contents.n_values):
  488. i = list_.contents.value[k] - 1
  489. # Get the temporal relationship
  490. relation = mapsB[j].temporal_relation(mapsA[i])
  491. A = mapsA[i]
  492. B = mapsB[j]
  493. set_temoral_relationship(A, B, relation)
  494. if spatial is not None:
  495. relation = mapsB[j].spatial_relation(mapsA[i])
  496. set_spatial_relationship(A, B, relation)
  497. self._build_internal_iteratable(mapsA, spatial)
  498. if not identical and mapsB is not None:
  499. self._build_iteratable(mapsB, spatial)
  500. gis.G_free_ilist(list_)
  501. rtree.RTreeDestroyTree(tree)
  502. def __iter__(self):
  503. start_ = self._first
  504. while start_ is not None:
  505. yield start_
  506. start_ = start_.next()
  507. def __getitem__(self, index):
  508. return self._store[index.get_id()]
  509. def __len__(self):
  510. return len(self._store)
  511. def __contains__(self, _map):
  512. return _map in self._store.values()
  513. ###############################################################################
  514. def set_temoral_relationship(A, B, relation):
  515. if relation == "equal" or relation == "equals":
  516. if A != B:
  517. if not B.get_equal() or (B.get_equal() and A not in B.get_equal()):
  518. B.append_equal(A)
  519. if not A.get_equal() or (A.get_equal() and B not in A.get_equal()):
  520. A.append_equal(B)
  521. elif relation == "follows":
  522. if not B.get_follows() or (B.get_follows() and A not in B.get_follows()):
  523. B.append_follows(A)
  524. if not A.get_precedes() or (A.get_precedes() and B not in A.get_precedes()):
  525. A.append_precedes(B)
  526. elif relation == "precedes":
  527. if not B.get_precedes() or (B.get_precedes() and A not in B.get_precedes()):
  528. B.append_precedes(A)
  529. if not A.get_follows() or (A.get_follows() and B not in A.get_follows()):
  530. A.append_follows(B)
  531. elif relation == "during" or relation == "starts" or relation == "finishes":
  532. if not B.get_during() or (B.get_during() and A not in B.get_during()):
  533. B.append_during(A)
  534. if not A.get_contains() or (A.get_contains() and B not in A.get_contains()):
  535. A.append_contains(B)
  536. if relation == "starts":
  537. if not B.get_starts() or (B.get_starts() and A not in B.get_starts()):
  538. B.append_starts(A)
  539. if not A.get_started() or (A.get_started() and B not in A.get_started()):
  540. A.append_started(B)
  541. if relation == "finishes":
  542. if not B.get_finishes() or (B.get_finishes() and A not in B.get_finishes()):
  543. B.append_finishes(A)
  544. if not A.get_finished() or (A.get_finished() and B not in A.get_finished()):
  545. A.append_finished(B)
  546. elif relation == "contains" or relation == "started" or relation == "finished":
  547. if not B.get_contains() or (B.get_contains() and A not in B.get_contains()):
  548. B.append_contains(A)
  549. if not A.get_during() or (A.get_during() and B not in A.get_during()):
  550. A.append_during(B)
  551. if relation == "started":
  552. if not B.get_started() or (B.get_started() and A not in B.get_started()):
  553. B.append_started(A)
  554. if not A.get_starts() or (A.get_starts() and B not in A.get_starts()):
  555. A.append_starts(B)
  556. if relation == "finished":
  557. if not B.get_finished() or (B.get_finished() and A not in B.get_finished()):
  558. B.append_finished(A)
  559. if not A.get_finishes() or (A.get_finishes() and B not in A.get_finishes()):
  560. A.append_finishes(B)
  561. elif relation == "overlaps":
  562. if not B.get_overlaps() or (B.get_overlaps() and A not in B.get_overlaps()):
  563. B.append_overlaps(A)
  564. if not A.get_overlapped() or (
  565. A.get_overlapped() and B not in A.get_overlapped()
  566. ):
  567. A.append_overlapped(B)
  568. elif relation == "overlapped":
  569. if not B.get_overlapped() or (
  570. B.get_overlapped() and A not in B.get_overlapped()
  571. ):
  572. B.append_overlapped(A)
  573. if not A.get_overlaps() or (A.get_overlaps() and B not in A.get_overlaps()):
  574. A.append_overlaps(B)
  575. ###############################################################################
  576. def set_spatial_relationship(A, B, relation):
  577. if relation == "equivalent":
  578. if A != B:
  579. if not B.get_equivalent() or (
  580. B.get_equivalent() and A not in B.get_equivalent()
  581. ):
  582. B.append_equivalent(A)
  583. if not A.get_equivalent() or (
  584. A.get_equivalent() and B not in A.get_equivalent()
  585. ):
  586. A.append_equivalent(B)
  587. elif relation == "overlap":
  588. if not B.get_overlap() or (B.get_overlap() and A not in B.get_overlap()):
  589. B.append_overlap(A)
  590. if not A.get_overlap() or (A.get_overlap() and B not in A.get_overlap()):
  591. A.append_overlap(B)
  592. elif relation == "meet":
  593. if not B.get_meet() or (B.get_meet() and A not in B.get_meet()):
  594. B.append_meet(A)
  595. if not A.get_meet() or (A.get_meet() and B not in A.get_meet()):
  596. A.append_meet(B)
  597. elif relation == "contain":
  598. if not B.get_contain() or (B.get_contain() and A not in B.get_contain()):
  599. B.append_contain(A)
  600. if not A.get_in() or (A.get_in() and B not in A.get_in()):
  601. A.append_in(B)
  602. elif relation == "in":
  603. if not B.get_in() or (B.get_in() and A not in B.get_in()):
  604. B.append_in(A)
  605. if not A.get_contain() or (A.get_contain() and B not in A.get_contain()):
  606. A.append_contain(B)
  607. elif relation == "cover":
  608. if not B.get_cover() or (B.get_cover() and A not in B.get_cover()):
  609. B.append_cover(A)
  610. if not A.get_covered() or (A.get_covered() and B not in A.get_covered()):
  611. A.append_covered(B)
  612. elif relation == "covered":
  613. if not B.get_covered() or (B.get_covered() and A not in B.get_covered()):
  614. B.append_covered(A)
  615. if not A.get_cover() or (A.get_cover() and B not in A.get_cover()):
  616. A.append_cover(B)
  617. ###############################################################################
  618. def print_temporal_topology_relationships(maps1, maps2=None, dbif=None):
  619. """Print the temporal relationships of the
  620. map lists maps1 and maps2 to stdout.
  621. :param maps1: A list of abstract_dataset
  622. objects with initiated temporal extent
  623. :param maps2: An optional list of abstract_dataset
  624. objects with initiated temporal extent
  625. :param dbif: The database interface to be used
  626. """
  627. tb = SpatioTemporalTopologyBuilder()
  628. tb.build(maps1, maps2)
  629. dbif, connection_state_changed = init_dbif(dbif)
  630. for _map in tb:
  631. _map.select(dbif)
  632. _map.print_info()
  633. if connection_state_changed:
  634. dbif.close()
  635. return
  636. ###############################################################################
  637. def print_spatio_temporal_topology_relationships(
  638. maps1, maps2=None, spatial="2D", dbif=None
  639. ):
  640. """Print the temporal relationships of the
  641. map lists maps1 and maps2 to stdout.
  642. :param maps1: A list of abstract_dataset
  643. objects with initiated temporal extent
  644. :param maps2: An optional list of abstract_dataset
  645. objects with initiated temporal extent
  646. :param spatial: The dimension of the spatial extent to be used: "2D"
  647. using west, east, south, north or "3D" using west,
  648. east, south, north, bottom, top
  649. :param dbif: The database interface to be used
  650. """
  651. tb = SpatioTemporalTopologyBuilder()
  652. tb.build(maps1, maps2, spatial)
  653. dbif, connection_state_changed = init_dbif(dbif)
  654. for _map in tb:
  655. _map.select(dbif)
  656. _map.print_info()
  657. if connection_state_changed:
  658. dbif.close()
  659. return
  660. ###############################################################################
  661. def count_temporal_topology_relationships(maps1, maps2=None, dbif=None):
  662. """Count the temporal relations of a single list of maps or between two
  663. lists of maps
  664. :param maps1: A list of abstract_dataset
  665. objects with initiated temporal extent
  666. :param maps2: A list of abstract_dataset
  667. objects with initiated temporal extent
  668. :param dbif: The database interface to be used
  669. :return: A dictionary with counted temporal relationships
  670. """
  671. tb = SpatioTemporalTopologyBuilder()
  672. tb.build(maps1, maps2)
  673. dbif, connection_state_changed = init_dbif(dbif)
  674. relations = None
  675. for _map in tb:
  676. if relations is not None:
  677. r = _map.get_number_of_relations()
  678. for k in r.keys():
  679. relations[k] += r[k]
  680. else:
  681. relations = _map.get_number_of_relations()
  682. if connection_state_changed:
  683. dbif.close()
  684. return relations
  685. ###############################################################################
  686. def create_temporal_relation_sql_where_statement(
  687. start,
  688. end,
  689. use_start=True,
  690. use_during=False,
  691. use_overlap=False,
  692. use_contain=False,
  693. use_equal=False,
  694. use_follows=False,
  695. use_precedes=False,
  696. ):
  697. """Create a SQL WHERE statement for temporal relation selection of maps in
  698. space time datasets
  699. :param start: The start time
  700. :param end: The end time
  701. :param use_start: Select maps of which the start time is located in
  702. the selection granule ::
  703. map : s
  704. granule: s-----------------e
  705. map : s--------------------e
  706. granule: s-----------------e
  707. map : s--------e
  708. granule: s-----------------e
  709. :param use_during: Select maps which are temporal during the selection
  710. granule ::
  711. map : s-----------e
  712. granule: s-----------------e
  713. :param use_overlap: Select maps which temporal overlap the selection
  714. granule ::
  715. map : s-----------e
  716. granule: s-----------------e
  717. map : s-----------e
  718. granule: s----------e
  719. :param use_contain: Select maps which temporally contain the selection
  720. granule ::
  721. map : s-----------------e
  722. granule: s-----------e
  723. :param use_equal: Select maps which temporally equal to the selection
  724. granule ::
  725. map : s-----------e
  726. granule: s-----------e
  727. :param use_follows: Select maps which temporally follow the selection
  728. granule ::
  729. map : s-----------e
  730. granule: s-----------e
  731. :param use_precedes: Select maps which temporally precedes the
  732. selection granule ::
  733. map : s-----------e
  734. granule: s-----------e
  735. Usage:
  736. .. code-block:: python
  737. >>> # Relative time
  738. >>> start = 1
  739. >>> end = 2
  740. >>> create_temporal_relation_sql_where_statement(start, end,
  741. ... use_start=False)
  742. >>> create_temporal_relation_sql_where_statement(start, end)
  743. '((start_time >= 1 and start_time < 2) )'
  744. >>> create_temporal_relation_sql_where_statement(start, end,
  745. ... use_start=True)
  746. '((start_time >= 1 and start_time < 2) )'
  747. >>> create_temporal_relation_sql_where_statement(start, end,
  748. ... use_start=False, use_during=True)
  749. '(((start_time > 1 and end_time < 2) OR (start_time >= 1 and end_time < 2) OR (start_time > 1 and end_time <= 2)))'
  750. >>> create_temporal_relation_sql_where_statement(start, end,
  751. ... use_start=False, use_overlap=True)
  752. '(((start_time < 1 and end_time > 1 and end_time < 2) OR (start_time < 2 and start_time > 1 and end_time > 2)))'
  753. >>> create_temporal_relation_sql_where_statement(start, end,
  754. ... use_start=False, use_contain=True)
  755. '(((start_time < 1 and end_time > 2) OR (start_time <= 1 and end_time > 2) OR (start_time < 1 and end_time >= 2)))'
  756. >>> create_temporal_relation_sql_where_statement(start, end,
  757. ... use_start=False, use_equal=True)
  758. '((start_time = 1 and end_time = 2))'
  759. >>> create_temporal_relation_sql_where_statement(start, end,
  760. ... use_start=False, use_follows=True)
  761. '((start_time = 2))'
  762. >>> create_temporal_relation_sql_where_statement(start, end,
  763. ... use_start=False, use_precedes=True)
  764. '((end_time = 1))'
  765. >>> create_temporal_relation_sql_where_statement(start, end,
  766. ... use_start=True, use_during=True, use_overlap=True, use_contain=True,
  767. ... use_equal=True, use_follows=True, use_precedes=True)
  768. '((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))'
  769. >>> # Absolute time
  770. >>> start = datetime(2001, 1, 1, 12, 30)
  771. >>> end = datetime(2001, 3, 31, 14, 30)
  772. >>> create_temporal_relation_sql_where_statement(start, end,
  773. ... use_start=False)
  774. >>> create_temporal_relation_sql_where_statement(start, end)
  775. "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') )"
  776. >>> create_temporal_relation_sql_where_statement(start, end,
  777. ... use_start=True)
  778. "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') )"
  779. >>> create_temporal_relation_sql_where_statement(start, end,
  780. ... use_start=False, use_during=True)
  781. "(((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')))"
  782. >>> create_temporal_relation_sql_where_statement(start, end,
  783. ... use_start=False, use_overlap=True)
  784. "(((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')))"
  785. >>> create_temporal_relation_sql_where_statement(start, end,
  786. ... use_start=False, use_contain=True)
  787. "(((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')))"
  788. >>> create_temporal_relation_sql_where_statement(start, end,
  789. ... use_start=False, use_equal=True)
  790. "((start_time = '2001-01-01 12:30:00' and end_time = '2001-03-31 14:30:00'))"
  791. >>> create_temporal_relation_sql_where_statement(start, end,
  792. ... use_start=False, use_follows=True)
  793. "((start_time = '2001-03-31 14:30:00'))"
  794. >>> create_temporal_relation_sql_where_statement(start, end,
  795. ... use_start=False, use_precedes=True)
  796. "((end_time = '2001-01-01 12:30:00'))"
  797. >>> create_temporal_relation_sql_where_statement(start, end,
  798. ... use_start=True, use_during=True, use_overlap=True, use_contain=True,
  799. ... use_equal=True, use_follows=True, use_precedes=True)
  800. "((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'))"
  801. """
  802. where = "("
  803. if use_start:
  804. if isinstance(start, datetime):
  805. where += "(start_time >= '%s' and start_time < '%s') " % (start, end)
  806. else:
  807. where += "(start_time >= %i and start_time < %i) " % (start, end)
  808. if use_during:
  809. if use_start:
  810. where += " OR "
  811. if isinstance(start, datetime):
  812. where += "((start_time > '%s' and end_time < '%s') OR " % (start, end)
  813. where += "(start_time >= '%s' and end_time < '%s') OR " % (start, end)
  814. where += "(start_time > '%s' and end_time <= '%s'))" % (start, end)
  815. else:
  816. where += "((start_time > %i and end_time < %i) OR " % (start, end)
  817. where += "(start_time >= %i and end_time < %i) OR " % (start, end)
  818. where += "(start_time > %i and end_time <= %i))" % (start, end)
  819. if use_overlap:
  820. if use_start or use_during:
  821. where += " OR "
  822. if isinstance(start, datetime):
  823. where += (
  824. "((start_time < '%s' and end_time > '%s' and end_time <"
  825. " '%s') OR " % (start, start, end)
  826. )
  827. where += (
  828. "(start_time < '%s' and start_time > '%s' and end_time "
  829. "> '%s'))" % (end, start, end)
  830. )
  831. else:
  832. where += "((start_time < %i and end_time > %i and end_time < %i)" " OR " % (
  833. start,
  834. start,
  835. end,
  836. )
  837. where += "(start_time < %i and start_time > %i and end_time > " "%i))" % (
  838. end,
  839. start,
  840. end,
  841. )
  842. if use_contain:
  843. if use_start or use_during or use_overlap:
  844. where += " OR "
  845. if isinstance(start, datetime):
  846. where += "((start_time < '%s' and end_time > '%s') OR " % (start, end)
  847. where += "(start_time <= '%s' and end_time > '%s') OR " % (start, end)
  848. where += "(start_time < '%s' and end_time >= '%s'))" % (start, end)
  849. else:
  850. where += "((start_time < %i and end_time > %i) OR " % (start, end)
  851. where += "(start_time <= %i and end_time > %i) OR " % (start, end)
  852. where += "(start_time < %i and end_time >= %i))" % (start, end)
  853. if use_equal:
  854. if use_start or use_during or use_overlap or use_contain:
  855. where += " OR "
  856. if isinstance(start, datetime):
  857. where += "(start_time = '%s' and end_time = '%s')" % (start, end)
  858. else:
  859. where += "(start_time = %i and end_time = %i)" % (start, end)
  860. if use_follows:
  861. if use_start or use_during or use_overlap or use_contain or use_equal:
  862. where += " OR "
  863. if isinstance(start, datetime):
  864. where += "(start_time = '%s')" % (end)
  865. else:
  866. where += "(start_time = %i)" % (end)
  867. if use_precedes:
  868. if (
  869. use_start
  870. or use_during
  871. or use_overlap
  872. or use_contain
  873. or use_equal
  874. or use_follows
  875. ):
  876. where += " OR "
  877. if isinstance(start, datetime):
  878. where += "(end_time = '%s')" % (start)
  879. else:
  880. where += "(end_time = %i)" % (start)
  881. where += ")"
  882. # Catch empty where statement
  883. if where == "()":
  884. where = None
  885. return where
  886. ###############################################################################
  887. if __name__ == "__main__":
  888. import doctest
  889. doctest.testmod()