spatial_extent.py 55 KB

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