spatio_temporal_relationships.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077
  1. """!@package grass.temporal
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS related functions to be used in temporal GIS Python library package.
  4. Usage:
  5. @code
  6. import grass.temporal as tgis
  7. tgis.print_temporal_relations(maps)
  8. ...
  9. @endcode
  10. (C) 2012-2013 by the GRASS Development Team
  11. This program is free software under the GNU General Public
  12. License (>=v2). Read the file COPYING that comes with GRASS
  13. for details.
  14. @author Soeren Gebbert
  15. """
  16. from abstract_dataset import *
  17. from datetime_math import *
  18. import grass.lib.vector as vector
  19. import grass.lib.rtree as rtree
  20. import grass.lib.gis as gis
  21. from ctypes import *
  22. ###############################################################################
  23. class SpatioTemporalTopologyBuilder(object):
  24. """!This class is designed to build the spatio-temporal topology
  25. of spatio-temporally related abstract dataset objects.
  26. The abstract dataset objects must be provided as a single list, or in two lists.
  27. Example:
  28. @code
  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, connected = 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. @endcode
  327. """
  328. def __init__(self):
  329. self._reset()
  330. # 0001-01-01 00:00:00
  331. self._timeref = datetime(1,1,1)
  332. def _reset(self):
  333. self._store = {}
  334. self._first = None
  335. self._iteratable = False
  336. def _set_first(self, first):
  337. self._first = first
  338. self._insert(first)
  339. def _detect_first(self):
  340. if len(self) > 0:
  341. prev_ = self._store.values()[0]
  342. while prev_ is not None:
  343. self._first = prev_
  344. prev_ = prev_.prev()
  345. def _insert(self, t):
  346. self._store[t.get_id()] = t
  347. def get_first(self):
  348. """!Return the first map with the earliest start time
  349. @return The map with the earliest start time
  350. """
  351. return self._first
  352. def _build_internal_iteratable(self, maps, spatial):
  353. """!Build an iteratable temporal topology structure for all maps in
  354. the list and store the maps internally
  355. Basically the "next" and "prev" relations will be set in the
  356. temporal topology structure of each map
  357. The maps will be added to the object, so they can be
  358. accessed using the iterator of this class
  359. @param maps A sorted (by start_time)list of abstract_dataset
  360. objects with initiated temporal extent
  361. """
  362. self._build_iteratable(maps, spatial)
  363. for _map in maps:
  364. self._insert(_map)
  365. # Detect the first map
  366. self._detect_first()
  367. def _build_iteratable(self, maps, spatial):
  368. """!Build an iteratable temporal topology structure for
  369. all maps in the list
  370. Basically the "next" and "prev" relations will be set in
  371. the temporal topology structure of each map.
  372. @param maps A sorted (by start_time)list of abstract_dataset
  373. objects with initiated temporal extent
  374. """
  375. # for i in xrange(len(maps)):
  376. # offset = i + 1
  377. # for j in xrange(offset, len(maps)):
  378. # # Get the temporal relationship
  379. # relation = maps[j].temporal_relation(maps[i])
  380. #
  381. # # Build the next reference
  382. # if relation != "equal" and relation != "started":
  383. # maps[i].set_next(maps[j])
  384. # break
  385. # First we need to order the map list chronologically
  386. sorted_maps = sorted(
  387. maps, key=AbstractDatasetComparisonKeyStartTime)
  388. for i in xrange(len(sorted_maps) - 1):
  389. sorted_maps[i].set_next(sorted_maps[i + 1])
  390. for map_ in sorted_maps:
  391. next_ = map_.next()
  392. if next_:
  393. next_.set_prev(map_)
  394. map_.set_temporal_topology_build_true()
  395. if spatial is not None:
  396. map_.set_spatial_topology_build_true()
  397. def _map_to_rect(self, tree, map_, spatial=None):
  398. """!Use the spatio-temporal extent of a map to create and
  399. return a RTree rectange
  400. @param spatial This indicates if the spatial topology is created as well:
  401. spatial can be None (no spatial topology), "2D" using west, east,
  402. #south, north or "3D" using west, east, south, north, bottom, top
  403. """
  404. rect = rtree.RTreeAllocRect(tree)
  405. start, end = map_.get_temporal_extent_as_tuple()
  406. if not end:
  407. end = start
  408. if map_.is_time_absolute():
  409. start = time_delta_to_relative_time_seconds(start - self._timeref)
  410. end = time_delta_to_relative_time_seconds(end - self._timeref)
  411. if spatial is None:
  412. rtree.RTreeSetRect1D(rect, tree, float(start), float(end))
  413. elif spatial == "2D":
  414. north, south, east, west, top, bottom = map_.get_spatial_extent_as_tuple()
  415. rtree.RTreeSetRect3D(rect, tree, west, east, south, north,
  416. float(start), float(end))
  417. elif spatial == "3D":
  418. north, south, east, west, top, bottom = map_.get_spatial_extent_as_tuple()
  419. rtree.RTreeSetRect4D(rect, tree, west, east, south, north,
  420. bottom, top, float(start), float(end))
  421. return rect
  422. def _build_rtree(self, maps, spatial=None):
  423. """!Build and return the 1-4 dimensional R*-Tree
  424. @param spatial This indicates if the spatial topology is created as well:
  425. spatial can be None (no spatial topology), "2D" using west, east,
  426. south, north or "3D" using 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 xrange(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 mapsA to
  442. mapsB and vice verse. The spatio-temporal topology structure of each map
  443. will be reseted and rebuild for mapsA and mapsB.
  444. After building the temporal or spatio-temporal topology the modified
  445. map objects of mapsA can be accessed
  446. in the same way as a dictionary using there id.
  447. The implemented iterator assures
  448. the chronological iteration over the mapsA.
  449. @param mapsA A list of abstract_dataset
  450. objects with initiated spatio-temporal extent
  451. @param mapsB An optional list of abstract_dataset
  452. objects with initiated spatio-temporal extent
  453. @param spatial This indicates if the spatial topology is created as well:
  454. spatial can be None (no spatial topology), "2D" using west, east,
  455. south, north or "3D" using west, east, south, north, bottom, top
  456. """
  457. identical = False
  458. if mapsA == mapsB:
  459. identical = True
  460. if mapsB == None:
  461. mapsB = mapsA
  462. identical = True
  463. for map_ in mapsA:
  464. map_.reset_topology()
  465. if not identical:
  466. for map_ in mapsB:
  467. map_.reset_topology()
  468. tree = self. _build_rtree(mapsA, spatial)
  469. list_ = gis.G_new_ilist()
  470. for j in xrange(len(mapsB)):
  471. rect = self._map_to_rect(tree, mapsB[j], spatial)
  472. vector.RTreeSearch2(tree, rect, list_)
  473. rtree.RTreeFreeRect(rect)
  474. for k in xrange(list_.contents.n_values):
  475. i = list_.contents.value[k] - 1
  476. # Get the temporal relationship
  477. relation = mapsB[j].temporal_relation(mapsA[i])
  478. A = mapsA[i]
  479. B = mapsB[j]
  480. set_temoral_relationship(A, B, relation)
  481. if spatial is not None:
  482. relation = mapsB[j].spatial_relation(mapsA[i])
  483. set_spatial_relationship(A, B, relation)
  484. self._build_internal_iteratable(mapsA, spatial)
  485. if not identical and mapsB != None:
  486. self._build_iteratable(mapsB, spatial)
  487. gis.G_free_ilist(list_)
  488. rtree.RTreeDestroyTree(tree)
  489. def __iter__(self):
  490. start_ = self._first
  491. while start_ is not None:
  492. yield start_
  493. start_ = start_.next()
  494. def __getitem__(self, index):
  495. return self._store[index.get_id()]
  496. def __len__(self):
  497. return len(self._store)
  498. def __contains__(self, _map):
  499. return _map in self._store.values()
  500. ###############################################################################
  501. def set_temoral_relationship(A, B, relation):
  502. if relation == "equal" or relation == "equals":
  503. if A != B:
  504. if not B.get_equal() or \
  505. (B.get_equal() and \
  506. A not in B.get_equal()):
  507. B.append_equal(A)
  508. if not A.get_equal() or \
  509. (A.get_equal() and \
  510. B not in A.get_equal()):
  511. A.append_equal(B)
  512. elif relation == "follows":
  513. if not B.get_follows() or \
  514. (B.get_follows() and \
  515. A not in B.get_follows()):
  516. B.append_follows(A)
  517. if not A.get_precedes() or \
  518. (A.get_precedes() and
  519. B not in A.get_precedes()):
  520. A.append_precedes(B)
  521. elif relation == "precedes":
  522. if not B.get_precedes() or \
  523. (B.get_precedes() and \
  524. A not in B.get_precedes()):
  525. B.append_precedes(A)
  526. if not A.get_follows() or \
  527. (A.get_follows() and \
  528. B not in A.get_follows()):
  529. A.append_follows(B)
  530. elif relation == "during" or relation == "starts" or \
  531. relation == "finishes":
  532. if not B.get_during() or \
  533. (B.get_during() and \
  534. A not in B.get_during()):
  535. B.append_during(A)
  536. if not A.get_contains() or \
  537. (A.get_contains() and \
  538. B not in A.get_contains()):
  539. A.append_contains(B)
  540. if relation == "starts":
  541. if not B.get_starts() or \
  542. (B.get_starts() and \
  543. A not in B.get_starts()):
  544. B.append_starts(A)
  545. if not A.get_started() or \
  546. (A.get_started() and \
  547. B not in A.get_started()):
  548. A.append_started(B)
  549. if relation == "finishes":
  550. if not B.get_finishes() or \
  551. (B.get_finishes() and \
  552. A not in B.get_finishes()):
  553. B.append_finishes(A)
  554. if not A.get_finished() or \
  555. (A.get_finished() and \
  556. B not in A.get_finished()):
  557. A.append_finished(B)
  558. elif relation == "contains" or relation == "started" or \
  559. relation == "finished":
  560. if not B.get_contains() or \
  561. (B.get_contains() and \
  562. A not in B.get_contains()):
  563. B.append_contains(A)
  564. if not A.get_during() or \
  565. (A.get_during() and \
  566. B not in A.get_during()):
  567. A.append_during(B)
  568. if relation == "started":
  569. if not B.get_started() or \
  570. (B.get_started() and \
  571. A not in B.get_started()):
  572. B.append_started(A)
  573. if not A.get_starts() or \
  574. (A.get_starts() and \
  575. B not in A.get_starts()):
  576. A.append_starts(B)
  577. if relation == "finished":
  578. if not B.get_finished() or \
  579. (B.get_finished() and \
  580. A not in B.get_finished()):
  581. B.append_finished(A)
  582. if not A.get_finishes() or \
  583. (A.get_finishes() and \
  584. B not in A.get_finishes()):
  585. A.append_finishes(B)
  586. elif relation == "overlaps":
  587. if not B.get_overlaps() or \
  588. (B.get_overlaps() and \
  589. A not in B.get_overlaps()):
  590. B.append_overlaps(A)
  591. if not A.get_overlapped() or \
  592. (A.get_overlapped() and \
  593. B not in A.get_overlapped()):
  594. A.append_overlapped(B)
  595. elif relation == "overlapped":
  596. if not B.get_overlapped() or \
  597. (B.get_overlapped() and \
  598. A not in B.get_overlapped()):
  599. B.append_overlapped(A)
  600. if not A.get_overlaps() or \
  601. (A.get_overlaps() and \
  602. B not in A.get_overlaps()):
  603. A.append_overlaps(B)
  604. ###############################################################################
  605. def set_spatial_relationship(A, B, relation):
  606. if relation == "equivalent":
  607. if A != B:
  608. if not B.get_equivalent() or \
  609. (B.get_equivalent() and \
  610. A not in B.get_equivalent()):
  611. B.append_equivalent(A)
  612. if not A.get_equivalent() or \
  613. (A.get_equivalent() and \
  614. B not in A.get_equivalent()):
  615. A.append_equivalent(B)
  616. elif relation == "overlap":
  617. if not B.get_overlap() or \
  618. (B.get_overlap() and \
  619. A not in B.get_overlap()):
  620. B.append_overlap(A)
  621. if not A.get_overlap() or \
  622. (A.get_overlap() and
  623. B not in A.get_overlap()):
  624. A.append_overlap(B)
  625. elif relation == "meet":
  626. if not B.get_meet() or \
  627. (B.get_meet() and \
  628. A not in B.get_meet()):
  629. B.append_meet(A)
  630. if not A.get_meet() or \
  631. (A.get_meet() and
  632. B not in A.get_meet()):
  633. A.append_meet(B)
  634. elif relation == "contain":
  635. if not B.get_contain() or \
  636. (B.get_contain() and \
  637. A not in B.get_contain()):
  638. B.append_contain(A)
  639. if not A.get_in() or \
  640. (A.get_in() and \
  641. B not in A.get_in()):
  642. A.append_in(B)
  643. elif relation == "in":
  644. if not B.get_in() or \
  645. (B.get_in() and \
  646. A not in B.get_in()):
  647. B.append_in(A)
  648. if not A.get_contain() or \
  649. (A.get_contain() and \
  650. B not in A.get_contain()):
  651. A.append_contain(B)
  652. elif relation == "cover":
  653. if not B.get_cover() or \
  654. (B.get_cover() and \
  655. A not in B.get_cover()):
  656. B.append_cover(A)
  657. if not A.get_covered() or \
  658. (A.get_covered() and \
  659. B not in A.get_covered()):
  660. A.append_covered(B)
  661. elif relation == "covered":
  662. if not B.get_covered() or \
  663. (B.get_covered() and \
  664. A not in B.get_covered()):
  665. B.append_covered(A)
  666. if not A.get_cover() or \
  667. (A.get_cover() and \
  668. B not in A.get_cover()):
  669. A.append_cover(B)
  670. ###############################################################################
  671. def print_temporal_topology_relationships(maps1, maps2=None, dbif=None):
  672. """!Print the temporal relationships of the
  673. map lists maps1 and maps2 to stdout.
  674. @param maps1 A list of abstract_dataset
  675. objects with initiated temporal extent
  676. @param maps2 An optional list of abstract_dataset
  677. objects with initiated temporal extent
  678. @param dbif The database interface to be used
  679. """
  680. tb = SpatioTemporalTopologyBuilder()
  681. tb.build(maps1, maps2)
  682. dbif, connected = init_dbif(dbif)
  683. for _map in tb:
  684. _map.select(dbif)
  685. _map.print_info()
  686. if connected:
  687. dbif.close()
  688. return
  689. ###############################################################################
  690. def print_spatio_temporal_topology_relationships(maps1, maps2=None,
  691. spatial="2D", dbif=None):
  692. """!Print the temporal relationships of the
  693. map lists maps1 and maps2 to stdout.
  694. @param maps1 A list of abstract_dataset
  695. objects with initiated temporal extent
  696. @param maps2 An optional list of abstract_dataset
  697. objects with initiated temporal extent
  698. @param spatial The dimension of the spatial extent to be used: "2D" using west, east,
  699. south, north or "3D" using west, east, south, north, bottom, top
  700. @param dbif The database interface to be used
  701. """
  702. tb = SpatioTemporalTopologyBuilder()
  703. tb.build(maps1, maps2, spatial)
  704. dbif, connected = init_dbif(dbif)
  705. for _map in tb:
  706. _map.select(dbif)
  707. _map.print_info()
  708. if connected:
  709. dbif.close()
  710. return
  711. ###############################################################################
  712. def count_temporal_topology_relationships(maps1, maps2=None, dbif=None):
  713. """!Count the temporal relations of a single list of maps or between two lists of maps
  714. @param maps1 A list of abstract_dataset
  715. objects with initiated temporal extent
  716. @param maps2 A list of abstract_dataset
  717. objects with initiated temporal extent
  718. @param dbif The database interface to be used
  719. @return A dictionary with counted temporal relationships
  720. """
  721. tb = SpatioTemporalTopologyBuilder()
  722. tb.build(maps1, maps2)
  723. dbif, connected = init_dbif(dbif)
  724. relations = None
  725. for _map in tb:
  726. if relations is not None:
  727. r = _map.get_number_of_relations()
  728. for k in r.keys():
  729. relations[k] += r[k]
  730. else:
  731. relations = _map.get_number_of_relations()
  732. if connected:
  733. dbif.close()
  734. return relations
  735. ###############################################################################
  736. def create_temporal_relation_sql_where_statement(
  737. start, end, use_start=True, use_during=False,
  738. use_overlap=False, use_contain=False, use_equal=False,
  739. use_follows=False, use_precedes=False):
  740. """!Create a SQL WHERE statement for temporal relation selection of maps in space time datasets
  741. @param start The start time
  742. @param end The end time
  743. @param use_start Select maps of which the start time is located in the selection granule
  744. @verbatim
  745. map : s
  746. granule: s-----------------e
  747. map : s--------------------e
  748. granule: s-----------------e
  749. map : s--------e
  750. granule: s-----------------e
  751. @endverbatim
  752. @param use_during Select maps which are temporal during the selection granule
  753. @verbatim
  754. map : s-----------e
  755. granule: s-----------------e
  756. @endverbatim
  757. @param use_overlap Select maps which temporal overlap the selection granule
  758. @verbatim
  759. map : s-----------e
  760. granule: s-----------------e
  761. map : s-----------e
  762. granule: s----------e
  763. @endverbatim
  764. @param use_contain Select maps which temporally contain the selection granule
  765. @verbatim
  766. map : s-----------------e
  767. granule: s-----------e
  768. @endverbatim
  769. @param use_equal Select maps which temporally equal to the selection granule
  770. @verbatim
  771. map : s-----------e
  772. granule: s-----------e
  773. @endverbatim
  774. @param use_follows Select maps which temporally follow the selection granule
  775. @verbatim
  776. map : s-----------e
  777. granule: s-----------e
  778. @endverbatim
  779. @param use_precedes Select maps which temporally precedes the selection granule
  780. @verbatim
  781. map : s-----------e
  782. granule: s-----------e
  783. @endverbatim
  784. Usage:
  785. @code
  786. >>> # Relative time
  787. >>> start = 1
  788. >>> end = 2
  789. >>> create_temporal_relation_sql_where_statement(start, end,
  790. ... use_start=False)
  791. >>> create_temporal_relation_sql_where_statement(start, end)
  792. '((start_time >= 1 and start_time < 2) )'
  793. >>> create_temporal_relation_sql_where_statement(start, end,
  794. ... use_start=True)
  795. '((start_time >= 1 and start_time < 2) )'
  796. >>> create_temporal_relation_sql_where_statement(start, end,
  797. ... use_start=False, use_during=True)
  798. '(((start_time > 1 and end_time < 2) OR (start_time >= 1 and end_time < 2) OR (start_time > 1 and end_time <= 2)))'
  799. >>> create_temporal_relation_sql_where_statement(start, end,
  800. ... use_start=False, use_overlap=True)
  801. '(((start_time < 1 and end_time > 1 and end_time < 2) OR (start_time < 2 and start_time > 1 and end_time > 2)))'
  802. >>> create_temporal_relation_sql_where_statement(start, end,
  803. ... use_start=False, use_contain=True)
  804. '(((start_time < 1 and end_time > 2) OR (start_time <= 1 and end_time > 2) OR (start_time < 1 and end_time >= 2)))'
  805. >>> create_temporal_relation_sql_where_statement(start, end,
  806. ... use_start=False, use_equal=True)
  807. '((start_time = 1 and end_time = 2))'
  808. >>> create_temporal_relation_sql_where_statement(start, end,
  809. ... use_start=False, use_follows=True)
  810. '((start_time = 2))'
  811. >>> create_temporal_relation_sql_where_statement(start, end,
  812. ... use_start=False, use_precedes=True)
  813. '((end_time = 1))'
  814. >>> create_temporal_relation_sql_where_statement(start, end,
  815. ... use_start=True, use_during=True, use_overlap=True, use_contain=True,
  816. ... use_equal=True, use_follows=True, use_precedes=True)
  817. '((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))'
  818. >>> # Absolute time
  819. >>> start = datetime(2001, 1, 1, 12, 30)
  820. >>> end = datetime(2001, 3, 31, 14, 30)
  821. >>> create_temporal_relation_sql_where_statement(start, end,
  822. ... use_start=False)
  823. >>> create_temporal_relation_sql_where_statement(start, end)
  824. "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') )"
  825. >>> create_temporal_relation_sql_where_statement(start, end,
  826. ... use_start=True)
  827. "((start_time >= '2001-01-01 12:30:00' and start_time < '2001-03-31 14:30:00') )"
  828. >>> create_temporal_relation_sql_where_statement(start, end,
  829. ... use_start=False, use_during=True)
  830. "(((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')))"
  831. >>> create_temporal_relation_sql_where_statement(start, end,
  832. ... use_start=False, use_overlap=True)
  833. "(((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')))"
  834. >>> create_temporal_relation_sql_where_statement(start, end,
  835. ... use_start=False, use_contain=True)
  836. "(((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')))"
  837. >>> create_temporal_relation_sql_where_statement(start, end,
  838. ... use_start=False, use_equal=True)
  839. "((start_time = '2001-01-01 12:30:00' and end_time = '2001-03-31 14:30:00'))"
  840. >>> create_temporal_relation_sql_where_statement(start, end,
  841. ... use_start=False, use_follows=True)
  842. "((start_time = '2001-03-31 14:30:00'))"
  843. >>> create_temporal_relation_sql_where_statement(start, end,
  844. ... use_start=False, use_precedes=True)
  845. "((end_time = '2001-01-01 12:30:00'))"
  846. >>> create_temporal_relation_sql_where_statement(start, end,
  847. ... use_start=True, use_during=True, use_overlap=True, use_contain=True,
  848. ... use_equal=True, use_follows=True, use_precedes=True)
  849. "((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'))"
  850. @endcode
  851. """
  852. where = "("
  853. if use_start:
  854. if isinstance(start, datetime):
  855. where += "(start_time >= '%s' and start_time < '%s') " % (start, end)
  856. else:
  857. where += "(start_time >= %i and start_time < %i) " % (start, end)
  858. if use_during:
  859. if use_start:
  860. where += " OR "
  861. if isinstance(start, datetime):
  862. where += "((start_time > '%s' and end_time < '%s') OR " % (start, end)
  863. where += "(start_time >= '%s' and end_time < '%s') OR " % (start, end)
  864. where += "(start_time > '%s' and end_time <= '%s'))" % (start, end)
  865. else:
  866. where += "((start_time > %i and end_time < %i) OR " % (start, end)
  867. where += "(start_time >= %i and end_time < %i) OR " % (start, end)
  868. where += "(start_time > %i and end_time <= %i))" % (start, end)
  869. if use_overlap:
  870. if use_start or use_during:
  871. where += " OR "
  872. if isinstance(start, datetime):
  873. where += "((start_time < '%s' and end_time > '%s' and end_time < '%s') OR " % (start, start, end)
  874. where += "(start_time < '%s' and start_time > '%s' and end_time > '%s'))" % (end, start, end)
  875. else:
  876. where += "((start_time < %i and end_time > %i and end_time < %i) OR " % (start, start, end)
  877. where += "(start_time < %i and start_time > %i and end_time > %i))" % (end, start, end)
  878. if use_contain:
  879. if use_start or use_during or use_overlap:
  880. where += " OR "
  881. if isinstance(start, datetime):
  882. where += "((start_time < '%s' and end_time > '%s') OR " % (start, end)
  883. where += "(start_time <= '%s' and end_time > '%s') OR " % (start, end)
  884. where += "(start_time < '%s' and end_time >= '%s'))" % (start, end)
  885. else:
  886. where += "((start_time < %i and end_time > %i) OR " % (start, end)
  887. where += "(start_time <= %i and end_time > %i) OR " % (start, end)
  888. where += "(start_time < %i and end_time >= %i))" % (start, end)
  889. if use_equal:
  890. if use_start or use_during or use_overlap or use_contain:
  891. where += " OR "
  892. if isinstance(start, datetime):
  893. where += "(start_time = '%s' and end_time = '%s')" % (start, end)
  894. else:
  895. where += "(start_time = %i and end_time = %i)" % (start, end)
  896. if use_follows:
  897. if use_start or use_during or use_overlap or use_contain or use_equal:
  898. where += " OR "
  899. if isinstance(start, datetime):
  900. where += "(start_time = '%s')" % (end)
  901. else:
  902. where += "(start_time = %i)" % (end)
  903. if use_precedes:
  904. if use_start or use_during or use_overlap or use_contain or use_equal \
  905. or use_follows:
  906. where += " OR "
  907. if isinstance(start, datetime):
  908. where += "(end_time = '%s')" % (start)
  909. else:
  910. where += "(end_time = %i)" % (start)
  911. where += ")"
  912. # Catch empty where statement
  913. if where == "()":
  914. where = None
  915. return where
  916. ###############################################################################
  917. if __name__ == "__main__":
  918. import doctest
  919. doctest.testmod()