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