spatio_temporal_relationships.py 48 KB

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