spatial_extent.py 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865
  1. """!@package grass.temporal
  2. @brief GRASS Python scripting module (temporal GIS functions)
  3. Temporal GIS related spatial extent functions to be used in Python scripts and tgis packages.
  4. Usage:
  5. @code
  6. >>> import grass.temporal as tgis
  7. >>> tgis.init()
  8. >>> extent = tgis.RasterSpatialExtent(
  9. ... ident="raster@PERMANENT", north=90, south=90, east=180, west=180,
  10. ... top=100, bottom=-20)
  11. >>> extent = tgis.Raster3DSpatialExtent(
  12. ... ident="raster3d@PERMANENT", north=90, south=90, east=180, west=180,
  13. ... top=100, bottom=-20)
  14. >>> extent = tgis.VectorSpatialExtent(
  15. ... ident="vector@PERMANENT", north=90, south=90, east=180, west=180,
  16. ... top=100, bottom=-20)
  17. >>> extent = tgis.STRDSSpatialExtent(
  18. ... ident="strds@PERMANENT", north=90, south=90, east=180, west=180,
  19. ... top=100, bottom=-20)
  20. >>> extent = tgis.STR3DSSpatialExtent(
  21. ... ident="str3ds@PERMANENT", north=90, south=90, east=180, west=180,
  22. ... top=100, bottom=-20)
  23. >>> extent = tgis.STVDSSpatialExtent(
  24. ... ident="stvds@PERMANENT", north=90, south=90, east=180, west=180,
  25. ... top=100, bottom=-20)
  26. @endcode
  27. (C) 2008-2011 by the GRASS Development Team
  28. This program is free software under the GNU General Public
  29. License (>=v2). Read the file COPYING that comes with GRASS
  30. for details.
  31. @author Soeren Gebbert
  32. """
  33. from base import *
  34. class SpatialExtent(SQLDatabaseInterface):
  35. """!This is the spatial extent base class for all maps and space time datasets
  36. This class implements a three dimensional axis aligned bounding box
  37. and functions to compute topological relationships
  38. Usage:
  39. @code
  40. >>> init()
  41. >>> extent = SpatialExtent(table="raster_spatial_extent",
  42. ... ident="soil@PERMANENT", north=90, south=90, east=180, west=180,
  43. ... top=100, bottom=-20)
  44. >>> extent.id
  45. 'soil@PERMANENT'
  46. >>> extent.north
  47. 90.0
  48. >>> extent.south
  49. 90.0
  50. >>> extent.east
  51. 180.0
  52. >>> extent.west
  53. 180.0
  54. >>> extent.top
  55. 100.0
  56. >>> extent.bottom
  57. -20.0
  58. >>> extent.print_info()
  59. +-------------------- Spatial extent ----------------------------------------+
  60. | North:...................... 90.0
  61. | South:...................... 90.0
  62. | East:.. .................... 180.0
  63. | West:....................... 180.0
  64. | Top:........................ 100.0
  65. | Bottom:..................... -20.0
  66. >>> extent.print_shell_info()
  67. north=90.0
  68. south=90.0
  69. east=180.0
  70. west=180.0
  71. top=100.0
  72. bottom=-20.0
  73. @endcode
  74. """
  75. def __init__(self, table=None, ident=None, north=None, south=None,
  76. east=None, west=None, top=None, bottom=None, proj="XY"):
  77. SQLDatabaseInterface.__init__(self, table, ident)
  78. self.set_id(ident)
  79. self.set_spatial_extent_from_values(north, south, east, west, top, bottom)
  80. self.set_projection(proj)
  81. def overlapping_2d(self, extent):
  82. """!Return True if this (A) and the provided spatial extent (B) overlaps
  83. in two dimensional space.
  84. Code is lend from wind_overlap.c in lib/gis
  85. Overlapping includes the spatial relations:
  86. - contain
  87. - in
  88. - cover
  89. - covered
  90. - equivalent
  91. @code
  92. >>> A = SpatialExtent(north=80, south=20, east=60, west=10)
  93. >>> B = SpatialExtent(north=80, south=20, east=60, west=10)
  94. >>> A.overlapping_2d(B)
  95. True
  96. @endcode
  97. @param extent The spatial extent to check overlapping with
  98. @return True or False
  99. """
  100. if self.get_projection() != extent.get_projection():
  101. core.error(_("Projections are different. Unable to compute "
  102. "overlapping_2d for spatial extents"))
  103. return False
  104. N = extent.get_north()
  105. S = extent.get_south()
  106. E = extent.get_east()
  107. W = extent.get_west()
  108. # Adjust the east and west in case of LL projection
  109. if self.get_projection() == "LL":
  110. while E < self.get_west():
  111. E += 360.0
  112. W += 360.0
  113. while W > self.get_east():
  114. E -= 360.0
  115. W -= 360.0
  116. if(self.get_north() <= S):
  117. return False
  118. if(self.get_south() >= N):
  119. return False
  120. if self.get_east() <= W:
  121. return False
  122. if self.get_west() >= E:
  123. return False
  124. return True
  125. def overlapping(self, extent):
  126. """!Return True if this (A) and the provided spatial
  127. extent (B) overlaps in three dimensional space.
  128. Overlapping includes the spatial relations:
  129. - contain
  130. - in
  131. - cover
  132. - covered
  133. - equivalent
  134. Usage:
  135. @code
  136. >>> A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
  137. >>> B = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
  138. >>> A.overlapping(B)
  139. True
  140. @endcode
  141. @param extent The spatial extent to check overlapping with
  142. @return True or False
  143. """
  144. if not self.overlapping_2d(extent):
  145. return False
  146. T = extent.get_top()
  147. B = extent.get_bottom()
  148. if self.get_top() <= B:
  149. return False
  150. if self.get_bottom() >= T:
  151. return False
  152. return True
  153. def intersect_2d(self, extent):
  154. """!Return the two dimensional intersection as spatial_extent
  155. object or None in case no intersection was found.
  156. @param extent The spatial extent to intersect with
  157. @return The intersection spatial extent
  158. """
  159. if not self.overlapping_2d(extent):
  160. return None
  161. eN = extent.get_north()
  162. eS = extent.get_south()
  163. eE = extent.get_east()
  164. eW = extent.get_west()
  165. N = self.get_north()
  166. S = self.get_south()
  167. E = self.get_east()
  168. W = self.get_west()
  169. # Adjust the east and west in case of LL projection
  170. if self.get_projection() == "LL":
  171. while eE < W:
  172. eE += 360.0
  173. eW += 360.0
  174. while eW > E:
  175. eE -= 360.0
  176. eW -= 360.0
  177. # Compute the extent
  178. nN = N
  179. nS = S
  180. nE = E
  181. nW = W
  182. if W < eW:
  183. nW = eW
  184. if E > eE:
  185. nE = eE
  186. if N > eN:
  187. nN = eN
  188. if S < eS:
  189. nS = eS
  190. new = SpatialExtent(north=nN, south=nS, east=nE, west=nW,
  191. top=0, bottom=0, proj=self.get_projection())
  192. return new
  193. def intersect(self, extent):
  194. """!Return the three dimensional intersection as spatial_extent
  195. object or None in case no intersection was found.
  196. Usage:
  197. @code
  198. >>> A = SpatialExtent(north=80, south=20, east=60, west=10,
  199. ... bottom=-50, top=50)
  200. >>> B = SpatialExtent(north=80, south=20, east=60, west=10,
  201. ... bottom=-50, top=50)
  202. >>> C = A.intersect(B)
  203. >>> C.print_info()
  204. +-------------------- Spatial extent ----------------------------------------+
  205. | North:...................... 80.0
  206. | South:...................... 20.0
  207. | East:.. .................... 60.0
  208. | West:....................... 10.0
  209. | Top:........................ 50.0
  210. | Bottom:..................... -50.0
  211. >>> B = SpatialExtent(north=40, south=30, east=60, west=10,
  212. ... bottom=-50, top=50)
  213. >>> C = A.intersect(B)
  214. >>> C.print_info()
  215. +-------------------- Spatial extent ----------------------------------------+
  216. | North:...................... 40.0
  217. | South:...................... 30.0
  218. | East:.. .................... 60.0
  219. | West:....................... 10.0
  220. | Top:........................ 50.0
  221. | Bottom:..................... -50.0
  222. >>> B = SpatialExtent(north=40, south=30, east=60, west=30,
  223. ... bottom=-50, top=50)
  224. >>> C = A.intersect(B)
  225. >>> C.print_info()
  226. +-------------------- Spatial extent ----------------------------------------+
  227. | North:...................... 40.0
  228. | South:...................... 30.0
  229. | East:.. .................... 60.0
  230. | West:....................... 30.0
  231. | Top:........................ 50.0
  232. | Bottom:..................... -50.0
  233. >>> B = SpatialExtent(north=40, south=30, east=60, west=30,
  234. ... bottom=-30, top=50)
  235. >>> C = A.intersect(B)
  236. >>> C.print_info()
  237. +-------------------- Spatial extent ----------------------------------------+
  238. | North:...................... 40.0
  239. | South:...................... 30.0
  240. | East:.. .................... 60.0
  241. | West:....................... 30.0
  242. | Top:........................ 50.0
  243. | Bottom:..................... -30.0
  244. >>> B = SpatialExtent(north=40, south=30, east=60, west=30,
  245. ... bottom=-30, top=30)
  246. >>> C = A.intersect(B)
  247. >>> C.print_info()
  248. +-------------------- Spatial extent ----------------------------------------+
  249. | North:...................... 40.0
  250. | South:...................... 30.0
  251. | East:.. .................... 60.0
  252. | West:....................... 30.0
  253. | Top:........................ 30.0
  254. | Bottom:..................... -30.0
  255. @endcode
  256. @param extent The spatial extent to intersect with
  257. @return The intersection spatial extent
  258. """
  259. if not self.overlapping(extent):
  260. return None
  261. new = self.intersect_2d(extent)
  262. eT = extent.get_top()
  263. eB = extent.get_bottom()
  264. T = self.get_top()
  265. B = self.get_bottom()
  266. nT = T
  267. nB = B
  268. if B < eB:
  269. nB = eB
  270. if T > eT:
  271. nT = eT
  272. new.set_top(nT)
  273. new.set_bottom(nB)
  274. return new
  275. def union_2d(self, extent):
  276. """!Return the two dimensional union as spatial_extent
  277. object or None in case the extents does not overlap or meet.
  278. @param extent The spatial extent to create a union with
  279. @return The union spatial extent
  280. """
  281. if not self.overlapping_2d(extent) and not self.meet_2d(extent):
  282. return None
  283. return self.disjoint_union_2d(extent)
  284. def disjoint_union_2d(self, extent):
  285. """!Return the two dimensional union as spatial_extent.
  286. @param extent The spatial extent to create a union with
  287. @return The union spatial extent
  288. """
  289. eN = extent.get_north()
  290. eS = extent.get_south()
  291. eE = extent.get_east()
  292. eW = extent.get_west()
  293. N = self.get_north()
  294. S = self.get_south()
  295. E = self.get_east()
  296. W = self.get_west()
  297. # Adjust the east and west in case of LL projection
  298. if self.get_projection() == "LL":
  299. while eE < W:
  300. eE += 360.0
  301. eW += 360.0
  302. while eW > E:
  303. eE -= 360.0
  304. eW -= 360.0
  305. # Compute the extent
  306. nN = N
  307. nS = S
  308. nE = E
  309. nW = W
  310. if W > eW:
  311. nW = eW
  312. if E < eE:
  313. nE = eE
  314. if N < eN:
  315. nN = eN
  316. if S > eS:
  317. nS = eS
  318. new = SpatialExtent(north=nN, south=nS, east=nE, west=nW,
  319. top=0, bottom=0, proj=self.get_projection())
  320. return new
  321. def union(self, extent):
  322. """!Return the three dimensional union as spatial_extent
  323. object or None in case the extents does not overlap or meet.
  324. @param extent The spatial extent to create a union with
  325. @return The union spatial extent
  326. """
  327. if not self.overlapping(extent) and not self.meet(extent):
  328. return None
  329. return self.disjoint_union(extent)
  330. def disjoint_union(self, extent):
  331. """!Return the three dimensional union as spatial_extent .
  332. Usage:
  333. @code
  334. >>> A = SpatialExtent(north=80, south=20, east=60, west=10,
  335. ... bottom=-50, top=50)
  336. >>> B = SpatialExtent(north=80, south=20, east=60, west=10,
  337. ... bottom=-50, top=50)
  338. >>> C = A.disjoint_union(B)
  339. >>> C.print_info()
  340. +-------------------- Spatial extent ----------------------------------------+
  341. | North:...................... 80.0
  342. | South:...................... 20.0
  343. | East:.. .................... 60.0
  344. | West:....................... 10.0
  345. | Top:........................ 50.0
  346. | Bottom:..................... -50.0
  347. >>> B = SpatialExtent(north=40, south=30, east=60, west=10,
  348. ... bottom=-50, top=50)
  349. >>> C = A.disjoint_union(B)
  350. >>> C.print_info()
  351. +-------------------- Spatial extent ----------------------------------------+
  352. | North:...................... 80.0
  353. | South:...................... 20.0
  354. | East:.. .................... 60.0
  355. | West:....................... 10.0
  356. | Top:........................ 50.0
  357. | Bottom:..................... -50.0
  358. >>> B = SpatialExtent(north=40, south=30, east=60, west=30,
  359. ... bottom=-50, top=50)
  360. >>> C = A.disjoint_union(B)
  361. >>> C.print_info()
  362. +-------------------- Spatial extent ----------------------------------------+
  363. | North:...................... 80.0
  364. | South:...................... 20.0
  365. | East:.. .................... 60.0
  366. | West:....................... 10.0
  367. | Top:........................ 50.0
  368. | Bottom:..................... -50.0
  369. >>> B = SpatialExtent(north=40, south=30, east=60, west=30,
  370. ... bottom=-30, top=50)
  371. >>> C = A.disjoint_union(B)
  372. >>> C.print_info()
  373. +-------------------- Spatial extent ----------------------------------------+
  374. | North:...................... 80.0
  375. | South:...................... 20.0
  376. | East:.. .................... 60.0
  377. | West:....................... 10.0
  378. | Top:........................ 50.0
  379. | Bottom:..................... -50.0
  380. >>> B = SpatialExtent(north=40, south=30, east=60, west=30,
  381. ... bottom=-30, top=30)
  382. >>> C = A.disjoint_union(B)
  383. >>> C.print_info()
  384. +-------------------- Spatial extent ----------------------------------------+
  385. | North:...................... 80.0
  386. | South:...................... 20.0
  387. | East:.. .................... 60.0
  388. | West:....................... 10.0
  389. | Top:........................ 50.0
  390. | Bottom:..................... -50.0
  391. >>> A = SpatialExtent(north=80, south=20, east=60, west=10,
  392. ... bottom=-50, top=50)
  393. >>> B = SpatialExtent(north=90, south=80, east=70, west=20,
  394. ... bottom=-30, top=60)
  395. >>> C = A.disjoint_union(B)
  396. >>> C.print_info()
  397. +-------------------- Spatial extent ----------------------------------------+
  398. | North:...................... 90.0
  399. | South:...................... 20.0
  400. | East:.. .................... 70.0
  401. | West:....................... 10.0
  402. | Top:........................ 60.0
  403. | Bottom:..................... -50.0
  404. @endcode
  405. @param extent The spatial extent to create a disjoint union with
  406. @return The union spatial extent
  407. """
  408. new = self.disjoint_union_2d(extent)
  409. eT = extent.get_top()
  410. eB = extent.get_bottom()
  411. T = self.get_top()
  412. B = self.get_bottom()
  413. nT = T
  414. nB = B
  415. if B > eB:
  416. nB = eB
  417. if T < eT:
  418. nT = eT
  419. new.set_top(nT)
  420. new.set_bottom(nB)
  421. return new
  422. def is_in_2d(self, extent):
  423. """!Return True if this extent (A) is located in the provided spatial
  424. extent (B) in two dimensions.
  425. @verbatim
  426. _____
  427. |A _ |
  428. | |_| |
  429. |_____|B
  430. @endverbatim
  431. @param extent The spatial extent
  432. @return True or False
  433. """
  434. if self.get_projection() != extent.get_projection():
  435. core.error(_("Projections are different. Unable to compute "
  436. "is_in_2d for spatial extents"))
  437. return False
  438. eN = extent.get_north()
  439. eS = extent.get_south()
  440. eE = extent.get_east()
  441. eW = extent.get_west()
  442. N = self.get_north()
  443. S = self.get_south()
  444. E = self.get_east()
  445. W = self.get_west()
  446. # Adjust the east and west in case of LL projection
  447. if self.get_projection() == "LL":
  448. while eE < W:
  449. eE += 360.0
  450. eW += 360.0
  451. while eW > E:
  452. eE -= 360.0
  453. eW -= 360.0
  454. if W <= eW:
  455. return False
  456. if E >= eE:
  457. return False
  458. if N >= eN:
  459. return False
  460. if S <= eS:
  461. return False
  462. return True
  463. def is_in(self, extent):
  464. """!Return True if this extent (A) is located in the provided spatial
  465. extent (B) in three dimensions.
  466. Usage:
  467. @code
  468. >>> A = SpatialExtent(north=79, south=21, east=59, west=11,
  469. ... bottom=-49, top=49)
  470. >>> B = SpatialExtent(north=80, south=20, east=60, west=10,
  471. ... bottom=-50, top=50)
  472. >>> A.is_in(B)
  473. True
  474. >>> B.is_in(A)
  475. False
  476. @endcode
  477. @param extent The spatial extent
  478. @return True or False
  479. """
  480. if not self.is_in_2d(extent):
  481. return False
  482. eT = extent.get_top()
  483. eB = extent.get_bottom()
  484. T = self.get_top()
  485. B = self.get_bottom()
  486. if B <= eB:
  487. return False
  488. if T >= eT:
  489. return False
  490. return True
  491. def contain_2d(self, extent):
  492. """!Return True if this extent (A) contains the provided spatial
  493. extent (B) in two dimensions.
  494. Usage:
  495. @code
  496. >>> A = SpatialExtent(north=80, south=20, east=60, west=10)
  497. >>> B = SpatialExtent(north=79, south=21, east=59, west=11)
  498. >>> A.contain_2d(B)
  499. True
  500. >>> B.contain_2d(A)
  501. False
  502. @endcode
  503. @param extent The spatial extent
  504. @return True or False
  505. """
  506. return extent.is_in_2d(self)
  507. def contain(self, extent):
  508. """!Return True if this extent (A) contains the provided spatial
  509. extent (B) in three dimensions.
  510. Usage:
  511. @code
  512. >>> A = SpatialExtent(north=80, south=20, east=60, west=10,
  513. ... bottom=-50, top=50)
  514. >>> B = SpatialExtent(north=79, south=21, east=59, west=11,
  515. ... bottom=-49, top=49)
  516. >>> A.contain(B)
  517. True
  518. >>> B.contain(A)
  519. False
  520. @endcode
  521. @param extent The spatial extent
  522. @return True or False
  523. """
  524. return extent.is_in(self)
  525. def equivalent_2d(self, extent):
  526. """!Return True if this extent (A) is equal to the provided spatial
  527. extent (B) in two dimensions.
  528. Usage:
  529. @code
  530. >>> A = SpatialExtent(north=80, south=20, east=60, west=10)
  531. >>> B = SpatialExtent(north=80, south=20, east=60, west=10)
  532. >>> A.equivalent_2d(B)
  533. True
  534. >>> B.equivalent_2d(A)
  535. True
  536. @endcode
  537. @param extent The spatial extent
  538. @return True or False
  539. """
  540. if self.get_projection() != extent.get_projection():
  541. core.error(_("Projections are different. Unable to compute "
  542. "equivalent_2d for spatial extents"))
  543. return False
  544. eN = extent.get_north()
  545. eS = extent.get_south()
  546. eE = extent.get_east()
  547. eW = extent.get_west()
  548. N = self.get_north()
  549. S = self.get_south()
  550. E = self.get_east()
  551. W = self.get_west()
  552. # Adjust the east and west in case of LL projection
  553. if self.get_projection() == "LL":
  554. while eE < W:
  555. eE += 360.0
  556. eW += 360.0
  557. while eW > E:
  558. eE -= 360.0
  559. eW -= 360.0
  560. if W != eW:
  561. return False
  562. if E != eE:
  563. return False
  564. if N != eN:
  565. return False
  566. if S != eS:
  567. return False
  568. return True
  569. def equivalent(self, extent):
  570. """!Return True if this extent (A) is equal to the provided spatial
  571. extent (B) in three dimensions.
  572. Usage:
  573. @code
  574. >>> A = SpatialExtent(north=80, south=20, east=60, west=10,
  575. ... bottom=-50, top=50)
  576. >>> B = SpatialExtent(north=80, south=20, east=60, west=10,
  577. ... bottom=-50, top=50)
  578. >>> A.equivalent(B)
  579. True
  580. >>> B.equivalent(A)
  581. True
  582. @endcode
  583. @param extent The spatial extent
  584. @return True or False
  585. """
  586. if not self.equivalent_2d(extent):
  587. return False
  588. eT = extent.get_top()
  589. eB = extent.get_bottom()
  590. T = self.get_top()
  591. B = self.get_bottom()
  592. if B != eB:
  593. return False
  594. if T != eT:
  595. return False
  596. return True
  597. def cover_2d(self, extent):
  598. """!Return True if this extent (A) covers the provided spatial
  599. extent (B) in two dimensions.
  600. @verbatim
  601. _____ _____ _____ _____
  602. |A __| |__ A| |A | B| |B | A|
  603. | |B | | B| | | |__| |__| |
  604. |__|__| |__|__| |_____| |_____|
  605. _____ _____ _____ _____
  606. |A|B| | |A __| |A _ | |__ A|
  607. | |_| | | |__|B | |B| | B|__| |
  608. |_____| |_____| |_|_|_| |_____|
  609. _____ _____ _____ _____
  610. |A|B | |_____|A |A|B|A| |_____|A
  611. | | | |B | | | | | |_____|B
  612. |_|___| |_____| |_|_|_| |_____|A
  613. @endverbatim
  614. The following cases are excluded:
  615. - contain
  616. - in
  617. - equivalent
  618. @param extent The spatial extent
  619. @return True or False
  620. """
  621. if self.get_projection() != extent.get_projection():
  622. core.error(_("Projections are different. Unable to compute cover_2d for spatial extents"))
  623. return False
  624. # Exclude equivalent_2d
  625. if self.equivalent_2d(extent):
  626. return False
  627. eN = extent.get_north()
  628. eS = extent.get_south()
  629. eE = extent.get_east()
  630. eW = extent.get_west()
  631. N = self.get_north()
  632. S = self.get_south()
  633. E = self.get_east()
  634. W = self.get_west()
  635. # Adjust the east and west in case of LL projection
  636. if self.get_projection() == "LL":
  637. while eE < W:
  638. eE += 360.0
  639. eW += 360.0
  640. while eW > E:
  641. eE -= 360.0
  642. eW -= 360.0
  643. # Edges of extent located outside of self are not allowed
  644. if E <= eW:
  645. return False
  646. if W >= eE:
  647. return False
  648. if N <= eS:
  649. return False
  650. if S >= eN:
  651. return False
  652. # First we check that at least one edge of extent meets an edge of self
  653. if W != eW and E != eE and N != eN and S != eS:
  654. return False
  655. # We check that at least one edge of extent is located in self
  656. edge_count = 0
  657. if W < eW and E > eW:
  658. edge_count += 1
  659. if E > eE and W < eE:
  660. edge_count += 1
  661. if N > eN and S < eN:
  662. edge_count += 1
  663. if S < eS and N > eS:
  664. edge_count += 1
  665. if edge_count == 0:
  666. return False
  667. return True
  668. def cover(self, extent):
  669. """!Return True if this extent covers the provided spatial
  670. extent in three dimensions.
  671. The following cases are excluded:
  672. - contain
  673. - in
  674. - equivalent
  675. @param extent The spatial extent
  676. @return True or False
  677. """
  678. if self.get_projection() != extent.get_projection():
  679. core.error(_("Projections are different. Unable to compute "
  680. "cover for spatial extents"))
  681. return False
  682. # Exclude equivalent_2d
  683. if self.equivalent_2d(extent):
  684. return False
  685. eN = extent.get_north()
  686. eS = extent.get_south()
  687. eE = extent.get_east()
  688. eW = extent.get_west()
  689. eT = extent.get_top()
  690. eB = extent.get_bottom()
  691. N = self.get_north()
  692. S = self.get_south()
  693. E = self.get_east()
  694. W = self.get_west()
  695. T = self.get_top()
  696. B = self.get_bottom()
  697. # Adjust the east and west in case of LL projection
  698. if self.get_projection() == "LL":
  699. while eE < W:
  700. eE += 360.0
  701. eW += 360.0
  702. while eW > E:
  703. eE -= 360.0
  704. eW -= 360.0
  705. # Edges of extent located outside of self are not allowed
  706. if E <= eW:
  707. return False
  708. if W >= eE:
  709. return False
  710. if N <= eS:
  711. return False
  712. if S >= eN:
  713. return False
  714. if T <= eB:
  715. return False
  716. if B >= eT:
  717. return False
  718. # First we check that at least one edge of extent meets an edge of self
  719. if W != eW and E != eE and N != eN and S != eS and B != eB and T != eT:
  720. return False
  721. # We check that at least one edge of extent is located in self
  722. edge_count = 0
  723. if W < eW and E > eW:
  724. edge_count += 1
  725. if E > eE and W < eE:
  726. edge_count += 1
  727. if N > eN and S < eN:
  728. edge_count += 1
  729. if S < eS and N > eS:
  730. edge_count += 1
  731. if N > eN and S < eN:
  732. edge_count += 1
  733. if S < eS and N > eS:
  734. edge_count += 1
  735. if T > eT and B < eT:
  736. edge_count += 1
  737. if B < eB and T > eB:
  738. edge_count += 1
  739. if edge_count == 0:
  740. return False
  741. return True
  742. def covered_2d(self, extent):
  743. """!Return True if this extent is covered by the provided spatial
  744. extent in two dimensions.
  745. The following cases are excluded:
  746. - contain
  747. - in
  748. - equivalent
  749. @param extent The spatial extent
  750. @return True or False
  751. """
  752. return extent.cover_2d(self)
  753. def covered(self, extent):
  754. """!Return True if this extent is covered by the provided spatial
  755. extent in three dimensions.
  756. The following cases are excluded:
  757. - contain
  758. - in
  759. - equivalent
  760. @param extent The spatial extent
  761. @return True or False
  762. """
  763. return extent.cover(self)
  764. def overlap_2d(self, extent):
  765. """!Return True if this extent (A) overlaps with the provided spatial
  766. extent (B) in two dimensions.
  767. Code is lend from wind_overlap.c in lib/gis
  768. @verbatim
  769. _____
  770. |A __|__
  771. | | | B|
  772. |__|__| |
  773. |_____|
  774. @endverbatim
  775. The following cases are excluded:
  776. - contain
  777. - in
  778. - cover
  779. - covered
  780. - equivalent
  781. @param extent The spatial extent
  782. @return True or False
  783. """
  784. if self.contain_2d(extent):
  785. return False
  786. if self.is_in_2d(extent):
  787. return False
  788. if self.cover_2d(extent):
  789. return False
  790. if self.covered_2d(extent):
  791. return False
  792. if self.equivalent_2d(extent):
  793. return False
  794. N = extent.get_north()
  795. S = extent.get_south()
  796. E = extent.get_east()
  797. W = extent.get_west()
  798. # Adjust the east and west in case of LL projection
  799. if self.get_projection() == "LL":
  800. while E < self.get_west():
  801. E += 360.0
  802. W += 360.0
  803. while W > self.get_east():
  804. E -= 360.0
  805. W -= 360.0
  806. if(self.get_north() <= S):
  807. return False
  808. if(self.get_south() >= N):
  809. return False
  810. if self.get_east() <= W:
  811. return False
  812. if self.get_west() >= E:
  813. return False
  814. return True
  815. def overlap(self, extent):
  816. """!Return True if this extent overlaps with the provided spatial
  817. extent in three dimensions.
  818. The following cases are excluded:
  819. - contain
  820. - in
  821. - cover
  822. - covered
  823. - equivalent
  824. @param extent The spatial extent
  825. @return True or False
  826. """
  827. if self.is_in(extent):
  828. return False
  829. if self.contain(extent):
  830. return False
  831. if self.cover(extent):
  832. return False
  833. if self.covered(extent):
  834. return False
  835. if self.equivalent(extent):
  836. return False
  837. N = extent.get_north()
  838. S = extent.get_south()
  839. E = extent.get_east()
  840. W = extent.get_west()
  841. T = extent.get_top()
  842. B = extent.get_bottom()
  843. # Adjust the east and west in case of LL projection
  844. if self.get_projection() == "LL":
  845. while E < self.get_west():
  846. E += 360.0
  847. W += 360.0
  848. while W > self.get_east():
  849. E -= 360.0
  850. W -= 360.0
  851. if(self.get_north() <= S):
  852. return False
  853. if(self.get_south() >= N):
  854. return False
  855. if self.get_east() <= W:
  856. return False
  857. if self.get_west() >= E:
  858. return False
  859. if self.get_top() <= B:
  860. return False
  861. if self.get_bottom() >= T:
  862. return False
  863. return True
  864. def meet_2d(self, extent):
  865. """!Return True if this extent (A) meets with the provided spatial
  866. extent (B) in two dimensions.
  867. @verbatim
  868. _____ _____
  869. | A | B |
  870. |_____| |
  871. |_____|
  872. _____ _____
  873. | B | A |
  874. | | |
  875. |_____|_____|
  876. ___
  877. | A |
  878. | |
  879. |___|
  880. | B |
  881. | |
  882. |_____|
  883. _____
  884. | B |
  885. | |
  886. |_____|_
  887. | A |
  888. | |
  889. |_____|
  890. @endverbatim
  891. @param extent The spatial extent
  892. @return True or False
  893. """
  894. eN = extent.get_north()
  895. eS = extent.get_south()
  896. eE = extent.get_east()
  897. eW = extent.get_west()
  898. N = self.get_north()
  899. S = self.get_south()
  900. E = self.get_east()
  901. W = self.get_west()
  902. # Adjust the east and west in case of LL projection
  903. if self.get_projection() == "LL":
  904. while eE < W:
  905. eE += 360.0
  906. eW += 360.0
  907. while eW > E:
  908. eE -= 360.0
  909. eW -= 360.0
  910. edge = None
  911. edge_count = 0
  912. if E == eW:
  913. edge = "E"
  914. edge_count += 1
  915. if W == eE:
  916. edge = "W"
  917. edge_count += 1
  918. if N == eS:
  919. edge = "N"
  920. edge_count += 1
  921. if S == eN:
  922. edge = "S"
  923. edge_count += 1
  924. # Meet a a single edge only
  925. if edge_count != 1:
  926. return False
  927. # Check boundaries of the faces
  928. if edge == "E" or edge == "W":
  929. if N < eS or S > eN:
  930. return False
  931. if edge == "N" or edge == "S":
  932. if E < eW or W > eE:
  933. return False
  934. return True
  935. def meet(self, extent):
  936. """!Return True if this extent meets with the provided spatial
  937. extent in three dimensions.
  938. @param extent The spatial extent
  939. @return True or False
  940. """
  941. eN = extent.get_north()
  942. eS = extent.get_south()
  943. eE = extent.get_east()
  944. eW = extent.get_west()
  945. eT = extent.get_top()
  946. eB = extent.get_bottom()
  947. N = self.get_north()
  948. S = self.get_south()
  949. E = self.get_east()
  950. W = self.get_west()
  951. T = self.get_top()
  952. B = self.get_bottom()
  953. # Adjust the east and west in case of LL projection
  954. if self.get_projection() == "LL":
  955. while eE < W:
  956. eE += 360.0
  957. eW += 360.0
  958. while eW > E:
  959. eE -= 360.0
  960. eW -= 360.0
  961. edge = None
  962. edge_count = 0
  963. if E == eW:
  964. edge = "E"
  965. edge_count += 1
  966. if W == eE:
  967. edge = "W"
  968. edge_count += 1
  969. if N == eS:
  970. edge = "N"
  971. edge_count += 1
  972. if S == eN:
  973. edge = "S"
  974. edge_count += 1
  975. if T == eB:
  976. edge = "T"
  977. edge_count += 1
  978. if B == eT:
  979. edge = "B"
  980. edge_count += 1
  981. # Meet a single edge only
  982. if edge_count != 1:
  983. return False
  984. # Check boundaries of the faces
  985. if edge == "E" or edge == "W":
  986. if N < eS or S > eN:
  987. return False
  988. if T < eB or B > eT:
  989. return False
  990. if edge == "N" or edge == "S":
  991. if E < eW or W > eE:
  992. return False
  993. if T < eB or B > eT:
  994. return False
  995. if edge == "T" or edge == "B":
  996. if E < eW or W > eE:
  997. return False
  998. if N < eS or S > eN:
  999. return False
  1000. return True
  1001. def disjoint_2d(self, extent):
  1002. """!Return True if this extent (A) is disjoint with the provided spatial
  1003. extent (B) in three dimensions.
  1004. @verbatim
  1005. _____
  1006. | A |
  1007. |_____|
  1008. _______
  1009. | B |
  1010. |_______|
  1011. @endverbatim
  1012. @param extent The spatial extent
  1013. @return True or False
  1014. """
  1015. if self.is_in_2d(extent):
  1016. return False
  1017. if self.contain_2d(extent):
  1018. return False
  1019. if self.cover_2d(extent):
  1020. return False
  1021. if self.covered_2d(extent):
  1022. return False
  1023. if self.equivalent_2d(extent):
  1024. return False
  1025. if self.overlapping_2d(extent):
  1026. return False
  1027. if self.meet_2d(extent):
  1028. return False
  1029. return True
  1030. def disjoint(self, extent):
  1031. """!Return True if this extent is disjoint with the provided spatial
  1032. extent in three dimensions.
  1033. @param extent The spatial extent
  1034. @return True or False
  1035. """
  1036. if self.is_in(extent):
  1037. return False
  1038. if self.contain(extent):
  1039. return False
  1040. if self.cover(extent):
  1041. return False
  1042. if self.covered(extent):
  1043. return False
  1044. if self.equivalent(extent):
  1045. return False
  1046. if self.overlapping(extent):
  1047. return False
  1048. if self.meet(extent):
  1049. return False
  1050. return True
  1051. def spatial_relation_2d(self, extent):
  1052. """!Returns the two dimensional spatial relation between this
  1053. extent and the provided spatial extent in two dimensions.
  1054. Spatial relations are:
  1055. - disjoint
  1056. - meet
  1057. - overlap
  1058. - cover
  1059. - covered
  1060. - in
  1061. - contain
  1062. - equivalent
  1063. Usage: see self.spatial_relation()
  1064. """
  1065. if self.equivalent_2d(extent):
  1066. return "equivalent"
  1067. if self.contain_2d(extent):
  1068. return "contain"
  1069. if self.is_in_2d(extent):
  1070. return "in"
  1071. if self.cover_2d(extent):
  1072. return "cover"
  1073. if self.covered_2d(extent):
  1074. return "covered"
  1075. if self.overlap_2d(extent):
  1076. return "overlap"
  1077. if self.meet_2d(extent):
  1078. return "meet"
  1079. if self.disjoint_2d(extent):
  1080. return "disjoint"
  1081. return "unknown"
  1082. def spatial_relation(self, extent):
  1083. """!Returns the two dimensional spatial relation between this
  1084. extent and the provided spatial extent in three dimensions.
  1085. Spatial relations are:
  1086. - disjoint
  1087. - meet
  1088. - overlap
  1089. - cover
  1090. - covered
  1091. - in
  1092. - contain
  1093. - equivalent
  1094. Usage:
  1095. @code
  1096. >>> A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
  1097. >>> B = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
  1098. >>> A.spatial_relation(B)
  1099. 'equivalent'
  1100. >>> B.spatial_relation(A)
  1101. 'equivalent'
  1102. >>> B = SpatialExtent(north=70, south=20, east=60, west=10, bottom=-50, top=50)
  1103. >>> A.spatial_relation_2d(B)
  1104. 'cover'
  1105. >>> A.spatial_relation(B)
  1106. 'cover'
  1107. >>> B = SpatialExtent(north=70, south=30, east=60, west=10, bottom=-50, top=50)
  1108. >>> A.spatial_relation_2d(B)
  1109. 'cover'
  1110. >>> A.spatial_relation(B)
  1111. 'cover'
  1112. >>> B.spatial_relation_2d(A)
  1113. 'covered'
  1114. >>> B.spatial_relation(A)
  1115. 'covered'
  1116. >>> B = SpatialExtent(north=70, south=30, east=50, west=10, bottom=-50, top=50)
  1117. >>> A.spatial_relation_2d(B)
  1118. 'cover'
  1119. >>> B.spatial_relation_2d(A)
  1120. 'covered'
  1121. >>> A.spatial_relation(B)
  1122. 'cover'
  1123. >>> B = SpatialExtent(north=70, south=30, east=50, west=20, bottom=-50, top=50)
  1124. >>> B.spatial_relation(A)
  1125. 'covered'
  1126. >>> B = SpatialExtent(north=70, south=30, east=50, west=20, bottom=-50, top=50)
  1127. >>> A.spatial_relation_2d(B)
  1128. 'contain'
  1129. >>> A.spatial_relation(B)
  1130. 'cover'
  1131. >>> B = SpatialExtent(north=70, south=30, east=50, west=20, bottom=-40, top=50)
  1132. >>> A.spatial_relation(B)
  1133. 'cover'
  1134. >>> B = SpatialExtent(north=70, south=30, east=50, west=20, bottom=-40, top=40)
  1135. >>> A.spatial_relation(B)
  1136. 'contain'
  1137. >>> B.spatial_relation(A)
  1138. 'in'
  1139. >>> B = SpatialExtent(north=90, south=30, east=50, west=20, bottom=-40, top=40)
  1140. >>> A.spatial_relation_2d(B)
  1141. 'overlap'
  1142. >>> A.spatial_relation(B)
  1143. 'overlap'
  1144. >>> B = SpatialExtent(north=90, south=5, east=70, west=5, bottom=-40, top=40)
  1145. >>> A.spatial_relation_2d(B)
  1146. 'in'
  1147. >>> A.spatial_relation(B)
  1148. 'overlap'
  1149. >>> B = SpatialExtent(north=90, south=5, east=70, west=5, bottom=-40, top=60)
  1150. >>> A.spatial_relation(B)
  1151. 'overlap'
  1152. >>> B = SpatialExtent(north=90, south=5, east=70, west=5, bottom=-60, top=60)
  1153. >>> A.spatial_relation(B)
  1154. 'in'
  1155. >>> A = SpatialExtent(north=80, south=60, east=60, west=10, bottom=-50, top=50)
  1156. >>> B = SpatialExtent(north=60, south=20, east=60, west=10, bottom=-50, top=50)
  1157. >>> A.spatial_relation_2d(B)
  1158. 'meet'
  1159. >>> A.spatial_relation(B)
  1160. 'meet'
  1161. >>> A = SpatialExtent(north=60, south=40, east=60, west=10, bottom=-50, top=50)
  1162. >>> B = SpatialExtent(north=80, south=60, east=60, west=10, bottom=-50, top=50)
  1163. >>> A.spatial_relation_2d(B)
  1164. 'meet'
  1165. >>> A.spatial_relation(B)
  1166. 'meet'
  1167. >>> A = SpatialExtent(north=80, south=40, east=60, west=40, bottom=-50, top=50)
  1168. >>> B = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
  1169. >>> A.spatial_relation_2d(B)
  1170. 'meet'
  1171. >>> A.spatial_relation(B)
  1172. 'meet'
  1173. >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
  1174. >>> B = SpatialExtent(north=90, south=30, east=60, west=40, bottom=-50, top=50)
  1175. >>> A.spatial_relation_2d(B)
  1176. 'meet'
  1177. >>> A.spatial_relation(B)
  1178. 'meet'
  1179. >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
  1180. >>> B = SpatialExtent(north=70, south=50, east=60, west=40, bottom=-50, top=50)
  1181. >>> A.spatial_relation_2d(B)
  1182. 'meet'
  1183. >>> A.spatial_relation(B)
  1184. 'meet'
  1185. >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
  1186. >>> B = SpatialExtent(north=60, south=20, east=60, west=40, bottom=-50, top=50)
  1187. >>> A.spatial_relation_2d(B)
  1188. 'meet'
  1189. >>> A.spatial_relation(B)
  1190. 'meet'
  1191. >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
  1192. >>> B = SpatialExtent(north=40, south=20, east=60, west=40, bottom=-50, top=50)
  1193. >>> A.spatial_relation_2d(B)
  1194. 'disjoint'
  1195. >>> A.spatial_relation(B)
  1196. 'disjoint'
  1197. >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
  1198. >>> B = SpatialExtent(north=60, south=20, east=60, west=40, bottom=-60, top=60)
  1199. >>> A.spatial_relation(B)
  1200. 'meet'
  1201. >>> A = SpatialExtent(north=80, south=40, east=40, west=20, bottom=-50, top=50)
  1202. >>> B = SpatialExtent(north=90, south=30, east=60, west=40, bottom=-40, top=40)
  1203. >>> A.spatial_relation(B)
  1204. 'meet'
  1205. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50)
  1206. >>> B = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
  1207. >>> A.spatial_relation(B)
  1208. 'meet'
  1209. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50)
  1210. >>> B = SpatialExtent(north=80, south=50, east=60, west=30, bottom=-50, top=0)
  1211. >>> A.spatial_relation(B)
  1212. 'meet'
  1213. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50)
  1214. >>> B = SpatialExtent(north=70, south=50, east=50, west=30, bottom=-50, top=0)
  1215. >>> A.spatial_relation(B)
  1216. 'meet'
  1217. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50)
  1218. >>> B = SpatialExtent(north=90, south=30, east=70, west=10, bottom=-50, top=0)
  1219. >>> A.spatial_relation(B)
  1220. 'meet'
  1221. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50)
  1222. >>> B = SpatialExtent(north=70, south=30, east=50, west=10, bottom=-50, top=0)
  1223. >>> A.spatial_relation(B)
  1224. 'meet'
  1225. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
  1226. >>> B = SpatialExtent(north=80, south=40, east=60, west=20, bottom=0, top=50)
  1227. >>> A.spatial_relation(B)
  1228. 'meet'
  1229. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
  1230. >>> B = SpatialExtent(north=80, south=50, east=60, west=30, bottom=0, top=50)
  1231. >>> A.spatial_relation(B)
  1232. 'meet'
  1233. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
  1234. >>> B = SpatialExtent(north=70, south=50, east=50, west=30, bottom=0, top=50)
  1235. >>> A.spatial_relation(B)
  1236. 'meet'
  1237. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
  1238. >>> B = SpatialExtent(north=90, south=30, east=70, west=10, bottom=0, top=50)
  1239. >>> A.spatial_relation(B)
  1240. 'meet'
  1241. >>> A = SpatialExtent(north=80, south=40, east=60, west=20, bottom=-50, top=0)
  1242. >>> B = SpatialExtent(north=70, south=30, east=50, west=10, bottom=0, top=50)
  1243. >>> A.spatial_relation(B)
  1244. 'meet'
  1245. >>> A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
  1246. >>> B = SpatialExtent(north=90, south=81, east=60, west=10, bottom=-50, top=50)
  1247. >>> A.spatial_relation(B)
  1248. 'disjoint'
  1249. >>> A = SpatialExtent(north=80, south=20, east=60, west=10, bottom=-50, top=50)
  1250. >>> B = SpatialExtent(north=90, south=80, east=60, west=10, bottom=-50, top=50)
  1251. >>> A.spatial_relation(B)
  1252. 'meet'
  1253. @endcode
  1254. """
  1255. if self.equivalent(extent):
  1256. return "equivalent"
  1257. if self.contain(extent):
  1258. return "contain"
  1259. if self.is_in(extent):
  1260. return "in"
  1261. if self.cover(extent):
  1262. return "cover"
  1263. if self.covered(extent):
  1264. return "covered"
  1265. if self.overlap(extent):
  1266. return "overlap"
  1267. if self.meet(extent):
  1268. return "meet"
  1269. if self.disjoint(extent):
  1270. return "disjoint"
  1271. return "unknown"
  1272. def set_spatial_extent_from_values(self, north, south, east, west, top, bottom):
  1273. """!Set the three dimensional spatial extent
  1274. @param north The northern edge
  1275. @param south The southern edge
  1276. @param east The eastern edge
  1277. @param west The western edge
  1278. @param top The top edge
  1279. @param bottom The bottom edge
  1280. """
  1281. self.set_north(north)
  1282. self.set_south(south)
  1283. self.set_east(east)
  1284. self.set_west(west)
  1285. self.set_top(top)
  1286. self.set_bottom(bottom)
  1287. def set_spatial_extent(self, spatial_extent):
  1288. """!Set the three dimensional spatial extent
  1289. @param spatial_extent An object of type SpatialExtent or its subclasses
  1290. """
  1291. self.set_north(spatial_extent.get_north())
  1292. self.set_south(spatial_extent.get_south())
  1293. self.set_east(spatial_extent.get_east())
  1294. self.set_west(spatial_extent.get_west())
  1295. self.set_top(spatial_extent.get_top())
  1296. self.set_bottom(spatial_extent.get_bottom())
  1297. def set_projection(self, proj):
  1298. """!Set the projection of the spatial extent it should be XY or LL.
  1299. As default the projection is XY
  1300. """
  1301. if proj is None or (proj != "XY" and proj != "LL"):
  1302. self.D["proj"] = "XY"
  1303. else:
  1304. self.D["proj"] = proj
  1305. def set_spatial_extent_from_values_2d(self, north, south, east, west):
  1306. """!Set the two dimensional spatial extent from values
  1307. @param north The northern edge
  1308. @param south The southern edge
  1309. @param east The eastern edge
  1310. @param west The western edge
  1311. """
  1312. self.set_north(north)
  1313. self.set_south(south)
  1314. self.set_east(east)
  1315. self.set_west(west)
  1316. def set_spatial_extent_2d(self, spatial_extent):
  1317. """!Set the three dimensional spatial extent
  1318. @param spatial_extent An object of type SpatialExtent or its subclasses
  1319. """
  1320. self.set_north(spatial_extent.north)
  1321. self.set_south(spatial_extent.south)
  1322. self.set_east(spatial_extent.east)
  1323. self.set_west(spatial_extent.west)
  1324. def set_id(self, ident):
  1325. """!Convenient method to set the unique identifier (primary key)"""
  1326. self.ident = ident
  1327. self.D["id"] = ident
  1328. def set_north(self, north):
  1329. """!Set the northern edge of the map"""
  1330. if north is not None:
  1331. self.D["north"] = float(north)
  1332. else:
  1333. self.D["north"] = None
  1334. def set_south(self, south):
  1335. """!Set the southern edge of the map"""
  1336. if south is not None:
  1337. self.D["south"] = float(south)
  1338. else:
  1339. self.D["south"] = None
  1340. def set_west(self, west):
  1341. """!Set the western edge of the map"""
  1342. if west is not None:
  1343. self.D["west"] = float(west)
  1344. else:
  1345. self.D["west"] = None
  1346. def set_east(self, east):
  1347. """!Set the eastern edge of the map"""
  1348. if east is not None:
  1349. self.D["east"] = float(east)
  1350. else:
  1351. self.D["east"] = None
  1352. def set_top(self, top):
  1353. """!Set the top edge of the map"""
  1354. if top is not None:
  1355. self.D["top"] = float(top)
  1356. else:
  1357. self.D["top"] = None
  1358. def set_bottom(self, bottom):
  1359. """!Set the bottom edge of the map"""
  1360. if bottom is not None:
  1361. self.D["bottom"] = float(bottom)
  1362. else:
  1363. self.D["bottom"] = None
  1364. def get_id(self):
  1365. """!Convenient method to get the unique identifier (primary key)
  1366. @return None if not found
  1367. """
  1368. if "id" in self.D:
  1369. return self.D["id"]
  1370. else:
  1371. return None
  1372. def get_projection(self):
  1373. """!Get the projection of the spatial extent"""
  1374. return self.D["proj"]
  1375. def get_volume(self):
  1376. """!Compute the volume of the extent, in case z is zero
  1377. (top == bottom or top - bottom = 1) the area is returned"""
  1378. if self.get_projection() == "LL":
  1379. core.error(_("Volume computation is not supported "
  1380. "for LL projections"))
  1381. area = self.get_area()
  1382. bbox = self.get_spatial_extent_as_tuple()
  1383. z = abs(bbox[4] - bbox[5])
  1384. if z == 0:
  1385. z = 1.0
  1386. return area * z
  1387. def get_area(self):
  1388. """!Compute the area of the extent, extent in z direction is ignored"""
  1389. if self.get_projection() == "LL":
  1390. core.error(_("Area computation is not supported "
  1391. "for LL projections"))
  1392. bbox = self.get_spatial_extent_as_tuple()
  1393. y = abs(bbox[0] - bbox[1])
  1394. x = abs(bbox[2] - bbox[3])
  1395. return x * y
  1396. def get_spatial_extent_as_tuple(self):
  1397. """!Return a tuple (north, south, east, west, top, bottom)
  1398. of the spatial extent"""
  1399. return (
  1400. self.north, self.south, self.east, self.west,
  1401. self.top, self.bottom)
  1402. def get_spatial_extent_as_tuple_2d(self):
  1403. """!Return a tuple (north, south, east, west,) of the 2d spatial extent
  1404. """
  1405. return (self.north, self.south, self.east, self.west)
  1406. def get_north(self):
  1407. """!Get the northern edge of the map
  1408. @return None if not found"""
  1409. if "north" in self.D:
  1410. return self.D["north"]
  1411. else:
  1412. return None
  1413. def get_south(self):
  1414. """!Get the southern edge of the map
  1415. @return None if not found"""
  1416. if "south" in self.D:
  1417. return self.D["south"]
  1418. else:
  1419. return None
  1420. def get_east(self):
  1421. """!Get the eastern edge of the map
  1422. @return None if not found"""
  1423. if "east" in self.D:
  1424. return self.D["east"]
  1425. else:
  1426. return None
  1427. def get_west(self):
  1428. """!Get the western edge of the map
  1429. @return None if not found"""
  1430. if "west" in self.D:
  1431. return self.D["west"]
  1432. else:
  1433. return None
  1434. def get_top(self):
  1435. """!Get the top edge of the map
  1436. @return None if not found"""
  1437. if "top" in self.D:
  1438. return self.D["top"]
  1439. else:
  1440. return None
  1441. def get_bottom(self):
  1442. """!Get the bottom edge of the map
  1443. @return None if not found"""
  1444. if "bottom" in self.D:
  1445. return self.D["bottom"]
  1446. else:
  1447. return None
  1448. id = property(fget=get_id, fset=set_id)
  1449. north = property(fget=get_north, fset=set_north)
  1450. south = property(fget=get_south, fset=set_south)
  1451. east = property(fget=get_east, fset=set_east)
  1452. west = property(fget=get_west, fset=set_west)
  1453. top = property(fget=get_top, fset=set_top)
  1454. bottom= property(fget=get_bottom, fset=set_bottom)
  1455. def print_info(self):
  1456. """!Print information about this class in human readable style"""
  1457. # 0123456789012345678901234567890
  1458. print " +-------------------- Spatial extent ----------------------------------------+"
  1459. print " | North:...................... " + str(self.get_north())
  1460. print " | South:...................... " + str(self.get_south())
  1461. print " | East:.. .................... " + str(self.get_east())
  1462. print " | West:....................... " + str(self.get_west())
  1463. print " | Top:........................ " + str(self.get_top())
  1464. print " | Bottom:..................... " + str(self.get_bottom())
  1465. def print_shell_info(self):
  1466. """Print information about this class in shell style"""
  1467. print "north=" + str(self.get_north())
  1468. print "south=" + str(self.get_south())
  1469. print "east=" + str(self.get_east())
  1470. print "west=" + str(self.get_west())
  1471. print "top=" + str(self.get_top())
  1472. print "bottom=" + str(self.get_bottom())
  1473. ###############################################################################
  1474. class RasterSpatialExtent(SpatialExtent):
  1475. def __init__(self, ident=None, north=None, south=None, east=None,
  1476. west=None, top=None, bottom=None):
  1477. SpatialExtent.__init__(self, "raster_spatial_extent",
  1478. ident, north, south, east, west, top, bottom)
  1479. class Raster3DSpatialExtent(SpatialExtent):
  1480. def __init__(self, ident=None, north=None, south=None, east=None,
  1481. west=None, top=None, bottom=None):
  1482. SpatialExtent.__init__(self, "raster3d_spatial_extent",
  1483. ident, north, south, east, west, top, bottom)
  1484. class VectorSpatialExtent(SpatialExtent):
  1485. def __init__(self, ident=None, north=None, south=None, east=None,
  1486. west=None, top=None, bottom=None):
  1487. SpatialExtent.__init__(self, "vector_spatial_extent",
  1488. ident, north, south, east, west, top, bottom)
  1489. class STRDSSpatialExtent(SpatialExtent):
  1490. def __init__(self, ident=None, north=None, south=None, east=None,
  1491. west=None, top=None, bottom=None):
  1492. SpatialExtent.__init__(self, "strds_spatial_extent",
  1493. ident, north, south, east, west, top, bottom)
  1494. class STR3DSSpatialExtent(SpatialExtent):
  1495. def __init__(self, ident=None, north=None, south=None, east=None,
  1496. west=None, top=None, bottom=None):
  1497. SpatialExtent.__init__(self, "str3ds_spatial_extent",
  1498. ident, north, south, east, west, top, bottom)
  1499. class STVDSSpatialExtent(SpatialExtent):
  1500. def __init__(self, ident=None, north=None, south=None, east=None,
  1501. west=None, top=None, bottom=None):
  1502. SpatialExtent.__init__(self, "stvds_spatial_extent",
  1503. ident, north, south, east, west, top, bottom)
  1504. ###############################################################################
  1505. if __name__ == "__main__":
  1506. import doctest
  1507. doctest.testmod()