spatio_temporal_relationships.py 47 KB

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