spatio_temporal_relationships.py 48 KB

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