spatio_temporal_relationships.py 48 KB

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