Source code for temporal.spatial_extent

"""
Spatial extents classes for map layer and space time datasets

Usage:

.. code-block:: python

    >>> import grass.temporal as tgis
    >>> tgis.init()
    >>> extent = tgis.RasterSpatialExtent(
    ...     ident="raster@PERMANENT",
    ...     north=90,
    ...     south=90,
    ...     east=180,
    ...     west=180,
    ...     top=100,
    ...     bottom=-20,
    ... )
    >>> extent = tgis.Raster3DSpatialExtent(
    ...     ident="raster3d@PERMANENT",
    ...     north=90,
    ...     south=90,
    ...     east=180,
    ...     west=180,
    ...     top=100,
    ...     bottom=-20,
    ... )
    >>> extent = tgis.VectorSpatialExtent(
    ...     ident="vector@PERMANENT",
    ...     north=90,
    ...     south=90,
    ...     east=180,
    ...     west=180,
    ...     top=100,
    ...     bottom=-20,
    ... )
    >>> extent = tgis.STRDSSpatialExtent(
    ...     ident="strds@PERMANENT",
    ...     north=90,
    ...     south=90,
    ...     east=180,
    ...     west=180,
    ...     top=100,
    ...     bottom=-20,
    ... )
    >>> extent = tgis.STR3DSSpatialExtent(
    ...     ident="str3ds@PERMANENT",
    ...     north=90,
    ...     south=90,
    ...     east=180,
    ...     west=180,
    ...     top=100,
    ...     bottom=-20,
    ... )
    >>> extent = tgis.STVDSSpatialExtent(
    ...     ident="stvds@PERMANENT",
    ...     north=90,
    ...     south=90,
    ...     east=180,
    ...     west=180,
    ...     top=100,
    ...     bottom=-20,
    ... )

(C) 2012-2013 by the GRASS Development Team
This program is free software under the GNU General Public
License (>=v2). Read the file COPYING that comes with GRASS
for details.

:authors: Soeren Gebbert
"""

from .base import SQLDatabaseInterface


[docs]class SpatialExtent(SQLDatabaseInterface): """This is the spatial extent base class for all maps and space time datasets This class implements a three dimensional axis aligned bounding box and functions to compute topological relationships Usage: .. code-block:: python >>> init() >>> extent = SpatialExtent( ... table="raster_spatial_extent", ... ident="soil@PERMANENT", ... north=90, ... south=90, ... east=180, ... west=180, ... top=100, ... bottom=-20, ... ) >>> extent.id 'soil@PERMANENT' >>> extent.north 90.0 >>> extent.south 90.0 >>> extent.east 180.0 >>> extent.west 180.0 >>> extent.top 100.0 >>> extent.bottom -20.0 >>> extent.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 90.0 | South:...................... 90.0 | East:.. .................... 180.0 | West:....................... 180.0 | Top:........................ 100.0 | Bottom:..................... -20.0 >>> extent.print_shell_info() north=90.0 south=90.0 east=180.0 west=180.0 top=100.0 bottom=-20.0 """ def __init__( self, table=None, ident=None, north=None, south=None, east=None, west=None, top=None, bottom=None, proj="XY", ): SQLDatabaseInterface.__init__(self, table, ident) self.set_id(ident) self.set_spatial_extent_from_values(north, south, east, west, top, bottom) self.set_projection(proj)
[docs] def overlapping_2d(self, extent): """Return True if this (A) and the provided spatial extent (B) overlaps in two dimensional space. Code is lend from wind_overlap.c in lib/gis Overlapping includes the spatial relations: - contain - in - cover - covered - equivalent .. code-block:: python >>> A = SpatialExtent(north=80, south=20, east=60, west=10) >>> B = SpatialExtent(north=80, south=20, east=60, west=10) >>> A.overlapping_2d(B) True :param extent: The spatial extent to check overlapping with :return: True or False """ if self.get_projection() != extent.get_projection(): self.msgr.error( _( "Projections are different. Unable to compute " "overlapping_2d for spatial extents" ) ) return False N = extent.get_north() S = extent.get_south() E = extent.get_east() W = extent.get_west() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while E < self.get_west(): E += 360.0 W += 360.0 while W > self.get_east(): E -= 360.0 W -= 360.0 if self.get_north() <= S: return False if self.get_south() >= N: return False if self.get_east() <= W: return False if self.get_west() >= E: return False return True
[docs] def overlapping(self, extent): """Return True if this (A) and the provided spatial extent (B) overlaps in three dimensional space. Overlapping includes the spatial relations: - contain - in - cover - covered - equivalent Usage: .. code-block:: python >>> A = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> A.overlapping(B) True :param extent: The spatial extent to check overlapping with :return: True or False """ if not self.overlapping_2d(extent): return False T = extent.get_top() B = extent.get_bottom() if self.get_top() <= B: return False if self.get_bottom() >= T: return False return True
[docs] def intersect_2d(self, extent): """Return the two dimensional intersection as spatial_extent object or None in case no intersection was found. :param extent: The spatial extent to intersect with :return: The intersection spatial extent """ if not self.overlapping_2d(extent): return None eN = extent.get_north() eS = extent.get_south() eE = extent.get_east() eW = extent.get_west() N = self.get_north() S = self.get_south() E = self.get_east() W = self.get_west() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while eE < W: eE += 360.0 eW += 360.0 while eW > E: eE -= 360.0 eW -= 360.0 # Compute the extent nN = N nS = S nE = E nW = W if W < eW: nW = eW if E > eE: nE = eE if N > eN: nN = eN if S < eS: nS = eS new = SpatialExtent( north=nN, south=nS, east=nE, west=nW, top=0, bottom=0, proj=self.get_projection(), ) return new
[docs] def intersect(self, extent): """Return the three dimensional intersection as spatial_extent object or None in case no intersection was found. Usage: .. code-block:: python >>> A = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 80.0 | South:...................... 20.0 | East:.. .................... 60.0 | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 >>> B = SpatialExtent( ... north=40, south=30, east=60, west=10, bottom=-50, top=50 ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 40.0 | South:...................... 30.0 | East:.. .................... 60.0 | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 >>> B = SpatialExtent( ... north=40, south=30, east=60, west=30, bottom=-50, top=50 ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 40.0 | South:...................... 30.0 | East:.. .................... 60.0 | West:....................... 30.0 | Top:........................ 50.0 | Bottom:..................... -50.0 >>> B = SpatialExtent( ... north=40, south=30, east=60, west=30, bottom=-30, top=50 ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 40.0 | South:...................... 30.0 | East:.. .................... 60.0 | West:....................... 30.0 | Top:........................ 50.0 | Bottom:..................... -30.0 >>> B = SpatialExtent( ... north=40, south=30, east=60, west=30, bottom=-30, top=30 ... ) >>> C = A.intersect(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 40.0 | South:...................... 30.0 | East:.. .................... 60.0 | West:....................... 30.0 | Top:........................ 30.0 | Bottom:..................... -30.0 :param extent: The spatial extent to intersect with :return: The intersection spatial extent """ # noqa: E501 if not self.overlapping(extent): return None new = self.intersect_2d(extent) eT = extent.get_top() eB = extent.get_bottom() T = self.get_top() B = self.get_bottom() nT = T nB = B if B < eB: nB = eB if T > eT: nT = eT new.set_top(nT) new.set_bottom(nB) return new
[docs] def union_2d(self, extent): """Return the two dimensional union as spatial_extent object or None in case the extents does not overlap or meet. :param extent: The spatial extent to create a union with :return: The union spatial extent """ if not self.overlapping_2d(extent) and not self.meet_2d(extent): return None return self.disjoint_union_2d(extent)
[docs] def disjoint_union_2d(self, extent): """Return the two dimensional union as spatial_extent. :param extent: The spatial extent to create a union with :return: The union spatial extent """ eN = extent.get_north() eS = extent.get_south() eE = extent.get_east() eW = extent.get_west() N = self.get_north() S = self.get_south() E = self.get_east() W = self.get_west() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while eE < W: eE += 360.0 eW += 360.0 while eW > E: eE -= 360.0 eW -= 360.0 # Compute the extent nN = N nS = S nE = E nW = W if W > eW: nW = eW if E < eE: nE = eE if N < eN: nN = eN if S > eS: nS = eS new = SpatialExtent( north=nN, south=nS, east=nE, west=nW, top=0, bottom=0, proj=self.get_projection(), ) return new
[docs] def union(self, extent): """Return the three dimensional union as spatial_extent object or None in case the extents does not overlap or meet. :param extent: The spatial extent to create a union with :return: The union spatial extent """ if not self.overlapping(extent) and not self.meet(extent): return None return self.disjoint_union(extent)
[docs] def disjoint_union(self, extent): """Return the three dimensional union as spatial_extent . Usage: .. code-block:: python >>> A = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 80.0 | South:...................... 20.0 | East:.. .................... 60.0 | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 >>> B = SpatialExtent( ... north=40, south=30, east=60, west=10, bottom=-50, top=50 ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 80.0 | South:...................... 20.0 | East:.. .................... 60.0 | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 >>> B = SpatialExtent( ... north=40, south=30, east=60, west=30, bottom=-50, top=50 ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 80.0 | South:...................... 20.0 | East:.. .................... 60.0 | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 >>> B = SpatialExtent( ... north=40, south=30, east=60, west=30, bottom=-30, top=50 ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 80.0 | South:...................... 20.0 | East:.. .................... 60.0 | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 >>> B = SpatialExtent( ... north=40, south=30, east=60, west=30, bottom=-30, top=30 ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 80.0 | South:...................... 20.0 | East:.. .................... 60.0 | West:....................... 10.0 | Top:........................ 50.0 | Bottom:..................... -50.0 >>> A = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=90, south=80, east=70, west=20, bottom=-30, top=60 ... ) >>> C = A.disjoint_union(B) >>> C.print_info() +-------------------- Spatial extent ----------------------------------------+ | North:...................... 90.0 | South:...................... 20.0 | East:.. .................... 70.0 | West:....................... 10.0 | Top:........................ 60.0 | Bottom:..................... -50.0 :param extent: The spatial extent to create a disjoint union with :return: The union spatial extent """ # noqa: E501 new = self.disjoint_union_2d(extent) eT = extent.get_top() eB = extent.get_bottom() T = self.get_top() B = self.get_bottom() nT = T nB = B if B > eB: nB = eB if T < eT: nT = eT new.set_top(nT) new.set_bottom(nB) return new
[docs] def is_in_2d(self, extent): """Return True if this extent (A) is located in the provided spatial extent (B) in two dimensions. :: _____ |A _ | | |_| | |_____|B :param extent: The spatial extent :return: True or False """ if self.get_projection() != extent.get_projection(): self.msgr.error( _( "Projections are different. Unable to compute " "is_in_2d for spatial extents" ) ) return False eN = extent.get_north() eS = extent.get_south() eE = extent.get_east() eW = extent.get_west() N = self.get_north() S = self.get_south() E = self.get_east() W = self.get_west() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while eE < W: eE += 360.0 eW += 360.0 while eW > E: eE -= 360.0 eW -= 360.0 if W <= eW: return False if E >= eE: return False if N >= eN: return False if S <= eS: return False return True
[docs] def is_in(self, extent): """Return True if this extent (A) is located in the provided spatial extent (B) in three dimensions. Usage: .. code-block:: python >>> A = SpatialExtent( ... north=79, south=21, east=59, west=11, bottom=-49, top=49 ... ) >>> B = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> A.is_in(B) True >>> B.is_in(A) False :param extent: The spatial extent :return: True or False """ if not self.is_in_2d(extent): return False eT = extent.get_top() eB = extent.get_bottom() T = self.get_top() B = self.get_bottom() if B <= eB: return False if T >= eT: return False return True
[docs] def contain_2d(self, extent): """Return True if this extent (A) contains the provided spatial extent (B) in two dimensions. Usage: .. code-block:: python >>> A = SpatialExtent(north=80, south=20, east=60, west=10) >>> B = SpatialExtent(north=79, south=21, east=59, west=11) >>> A.contain_2d(B) True >>> B.contain_2d(A) False :param extent: The spatial extent :return: True or False """ return extent.is_in_2d(self)
[docs] def contain(self, extent): """Return True if this extent (A) contains the provided spatial extent (B) in three dimensions. Usage: .. code-block:: python >>> A = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=79, south=21, east=59, west=11, bottom=-49, top=49 ... ) >>> A.contain(B) True >>> B.contain(A) False :param extent: The spatial extent :return: True or False """ return extent.is_in(self)
[docs] def equivalent_2d(self, extent): """Return True if this extent (A) is equal to the provided spatial extent (B) in two dimensions. Usage: .. code-block:: python >>> A = SpatialExtent(north=80, south=20, east=60, west=10) >>> B = SpatialExtent(north=80, south=20, east=60, west=10) >>> A.equivalent_2d(B) True >>> B.equivalent_2d(A) True :param extent: The spatial extent :return: True or False """ if self.get_projection() != extent.get_projection(): self.msgr.error( _( "Projections are different. Unable to compute " "equivalent_2d for spatial extents" ) ) return False eN = extent.get_north() eS = extent.get_south() eE = extent.get_east() eW = extent.get_west() N = self.get_north() S = self.get_south() E = self.get_east() W = self.get_west() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while eE < W: eE += 360.0 eW += 360.0 while eW > E: eE -= 360.0 eW -= 360.0 if W != eW: return False if E != eE: return False if N != eN: return False if S != eS: return False return True
[docs] def equivalent(self, extent): """Return True if this extent (A) is equal to the provided spatial extent (B) in three dimensions. Usage: .. code-block:: python >>> A = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> A.equivalent(B) True >>> B.equivalent(A) True :param extent: The spatial extent :return: True or False """ if not self.equivalent_2d(extent): return False eT = extent.get_top() eB = extent.get_bottom() T = self.get_top() B = self.get_bottom() if B != eB: return False if T != eT: return False return True
[docs] def cover_2d(self, extent): """Return True if this extent (A) covers the provided spatial extent (B) in two dimensions. :: _____ _____ _____ _____ |A __| |__ A| |A | B| |B | A| | |B | | B| | | |__| |__| | |__|__| |__|__| |_____| |_____| _____ _____ _____ _____ |A|B| | |A __| |A _ | |__ A| | |_| | | |__|B | |B| | B|__| | |_____| |_____| |_|_|_| |_____| _____ _____ _____ _____ |A|B | |_____|A |A|B|A| |_____|A | | | |B | | | | | |_____|B |_|___| |_____| |_|_|_| |_____|A The following cases are excluded: - contain - in - equivalent :param extent: The spatial extent :return: True or False """ if self.get_projection() != extent.get_projection(): self.msgr.error( _( "Projections are different. Unable to compute" " cover_2d for spatial extents" ) ) return False # Exclude equivalent_2d if self.equivalent_2d(extent): return False eN = extent.get_north() eS = extent.get_south() eE = extent.get_east() eW = extent.get_west() N = self.get_north() S = self.get_south() E = self.get_east() W = self.get_west() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while eE < W: eE += 360.0 eW += 360.0 while eW > E: eE -= 360.0 eW -= 360.0 # Edges of extent located outside of self are not allowed if E <= eW: return False if W >= eE: return False if N <= eS: return False if S >= eN: return False # First we check that at least one edge of extent meets an edge of self if W != eW and E != eE and N != eN and S != eS: return False # We check that at least one edge of extent is located in self edge_count = 0 if W < eW and E > eW: edge_count += 1 if E > eE and W < eE: edge_count += 1 if N > eN and S < eN: edge_count += 1 if S < eS and N > eS: edge_count += 1 if edge_count == 0: return False return True
[docs] def cover(self, extent): """Return True if this extent covers the provided spatial extent in three dimensions. The following cases are excluded: - contain - in - equivalent :param extent: The spatial extent :return: True or False """ if self.get_projection() != extent.get_projection(): self.msgr.error( _( "Projections are different. Unable to compute " "cover for spatial extents" ) ) return False # Exclude equivalent_2d if self.equivalent_2d(extent): return False eN = extent.get_north() eS = extent.get_south() eE = extent.get_east() eW = extent.get_west() eT = extent.get_top() eB = extent.get_bottom() N = self.get_north() S = self.get_south() E = self.get_east() W = self.get_west() T = self.get_top() B = self.get_bottom() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while eE < W: eE += 360.0 eW += 360.0 while eW > E: eE -= 360.0 eW -= 360.0 # Edges of extent located outside of self are not allowed if E <= eW: return False if W >= eE: return False if N <= eS: return False if S >= eN: return False if T <= eB: return False if B >= eT: return False # First we check that at least one edge of extent meets an edge of self if W != eW and E != eE and N != eN and S != eS and B != eB and T != eT: return False # We check that at least one edge of extent is located in self edge_count = 0 if W < eW and E > eW: edge_count += 1 if E > eE and W < eE: edge_count += 1 if N > eN and S < eN: edge_count += 1 if S < eS and N > eS: edge_count += 1 if N > eN and S < eN: edge_count += 1 if S < eS and N > eS: edge_count += 1 if T > eT and B < eT: edge_count += 1 if B < eB and T > eB: edge_count += 1 if edge_count == 0: return False return True
[docs] def covered_2d(self, extent): """Return True if this extent is covered by the provided spatial extent in two dimensions. The following cases are excluded: - contain - in - equivalent :param extent: The spatial extent :return: True or False """ return extent.cover_2d(self)
[docs] def covered(self, extent): """Return True if this extent is covered by the provided spatial extent in three dimensions. The following cases are excluded: - contain - in - equivalent :param extent: The spatial extent :return: True or False """ return extent.cover(self)
[docs] def overlap_2d(self, extent): """Return True if this extent (A) overlaps with the provided spatial extent (B) in two dimensions. Code is lend from wind_overlap.c in lib/gis :: _____ |A __|__ | | | B| |__|__| | |_____| The following cases are excluded: - contain - in - cover - covered - equivalent :param extent: The spatial extent :return: True or False """ if self.contain_2d(extent): return False if self.is_in_2d(extent): return False if self.cover_2d(extent): return False if self.covered_2d(extent): return False if self.equivalent_2d(extent): return False N = extent.get_north() S = extent.get_south() E = extent.get_east() W = extent.get_west() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while E < self.get_west(): E += 360.0 W += 360.0 while W > self.get_east(): E -= 360.0 W -= 360.0 if self.get_north() <= S: return False if self.get_south() >= N: return False if self.get_east() <= W: return False if self.get_west() >= E: return False return True
[docs] def overlap(self, extent): """Return True if this extent overlaps with the provided spatial extent in three dimensions. The following cases are excluded: - contain - in - cover - covered - equivalent :param extent: The spatial extent :return: True or False """ if self.is_in(extent): return False if self.contain(extent): return False if self.cover(extent): return False if self.covered(extent): return False if self.equivalent(extent): return False N = extent.get_north() S = extent.get_south() E = extent.get_east() W = extent.get_west() T = extent.get_top() B = extent.get_bottom() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while E < self.get_west(): E += 360.0 W += 360.0 while W > self.get_east(): E -= 360.0 W -= 360.0 if self.get_north() <= S: return False if self.get_south() >= N: return False if self.get_east() <= W: return False if self.get_west() >= E: return False if self.get_top() <= B: return False if self.get_bottom() >= T: return False return True
[docs] def meet_2d(self, extent): """Return True if this extent (A) meets with the provided spatial extent (B) in two dimensions. :: _____ _____ | A | B | |_____| | |_____| _____ _____ | B | A | | | | |_____|_____| ___ | A | | | |___| | B | | | |_____| _____ | B | | | |_____|_ | A | | | |_____| :param extent: The spatial extent :return: True or False """ eN = extent.get_north() eS = extent.get_south() eE = extent.get_east() eW = extent.get_west() N = self.get_north() S = self.get_south() E = self.get_east() W = self.get_west() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while eE < W: eE += 360.0 eW += 360.0 while eW > E: eE -= 360.0 eW -= 360.0 edge = None edge_count = 0 if E == eW: edge = "E" edge_count += 1 if W == eE: edge = "W" edge_count += 1 if N == eS: edge = "N" edge_count += 1 if S == eN: edge = "S" edge_count += 1 # Meet a a single edge only if edge_count != 1: return False # Check boundaries of the faces if edge == "E" or edge == "W": if N < eS or S > eN: return False if edge == "N" or edge == "S": if E < eW or W > eE: return False return True
[docs] def meet(self, extent): """Return True if this extent meets with the provided spatial extent in three dimensions. :param extent: The spatial extent :return: True or False """ eN = extent.get_north() eS = extent.get_south() eE = extent.get_east() eW = extent.get_west() eT = extent.get_top() eB = extent.get_bottom() N = self.get_north() S = self.get_south() E = self.get_east() W = self.get_west() T = self.get_top() B = self.get_bottom() # Adjust the east and west in case of LL projection if self.get_projection() == "LL": while eE < W: eE += 360.0 eW += 360.0 while eW > E: eE -= 360.0 eW -= 360.0 edge = None edge_count = 0 if E == eW: edge = "E" edge_count += 1 if W == eE: edge = "W" edge_count += 1 if N == eS: edge = "N" edge_count += 1 if S == eN: edge = "S" edge_count += 1 if T == eB: edge = "T" edge_count += 1 if B == eT: edge = "B" edge_count += 1 # Meet a single edge only if edge_count != 1: return False # Check boundaries of the faces if edge == "E" or edge == "W": if N < eS or S > eN: return False if T < eB or B > eT: return False if edge == "N" or edge == "S": if E < eW or W > eE: return False if T < eB or B > eT: return False if edge == "T" or edge == "B": if E < eW or W > eE: return False if N < eS or S > eN: return False return True
[docs] def disjoint_2d(self, extent): """Return True if this extent (A) is disjoint with the provided spatial extent (B) in three dimensions. :: _____ | A | |_____| _______ | B | |_______| :param extent: The spatial extent :return: True or False """ if self.is_in_2d(extent): return False if self.contain_2d(extent): return False if self.cover_2d(extent): return False if self.covered_2d(extent): return False if self.equivalent_2d(extent): return False if self.overlapping_2d(extent): return False if self.meet_2d(extent): return False return True
[docs] def disjoint(self, extent): """Return True if this extent is disjoint with the provided spatial extent in three dimensions. :param extent: The spatial extent :return: True or False """ if self.is_in(extent): return False if self.contain(extent): return False if self.cover(extent): return False if self.covered(extent): return False if self.equivalent(extent): return False if self.overlapping(extent): return False if self.meet(extent): return False return True
[docs] def spatial_relation_2d(self, extent): """Returns the two dimensional spatial relation between this extent and the provided spatial extent in two dimensions. Spatial relations are: - disjoint - meet - overlap - cover - covered - in - contain - equivalent Usage: see self.spatial_relation() """ if self.equivalent_2d(extent): return "equivalent" if self.contain_2d(extent): return "contain" if self.is_in_2d(extent): return "in" if self.cover_2d(extent): return "cover" if self.covered_2d(extent): return "covered" if self.overlap_2d(extent): return "overlap" if self.meet_2d(extent): return "meet" if self.disjoint_2d(extent): return "disjoint" return "unknown"
[docs] def spatial_relation(self, extent): """Returns the two dimensional spatial relation between this extent and the provided spatial extent in three dimensions. Spatial relations are: - disjoint - meet - overlap - cover - covered - in - contain - equivalent Usage: .. code-block:: python >>> A = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> A.spatial_relation(B) 'equivalent' >>> B.spatial_relation(A) 'equivalent' >>> B = SpatialExtent( ... north=70, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'cover' >>> A.spatial_relation(B) 'cover' >>> B = SpatialExtent( ... north=70, south=30, east=60, west=10, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'cover' >>> A.spatial_relation(B) 'cover' >>> B.spatial_relation_2d(A) 'covered' >>> B.spatial_relation(A) 'covered' >>> B = SpatialExtent( ... north=70, south=30, east=50, west=10, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'cover' >>> B.spatial_relation_2d(A) 'covered' >>> A.spatial_relation(B) 'cover' >>> B = SpatialExtent( ... north=70, south=30, east=50, west=20, bottom=-50, top=50 ... ) >>> B.spatial_relation(A) 'covered' >>> B = SpatialExtent( ... north=70, south=30, east=50, west=20, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'contain' >>> A.spatial_relation(B) 'cover' >>> B = SpatialExtent( ... north=70, south=30, east=50, west=20, bottom=-40, top=50 ... ) >>> A.spatial_relation(B) 'cover' >>> B = SpatialExtent( ... north=70, south=30, east=50, west=20, bottom=-40, top=40 ... ) >>> A.spatial_relation(B) 'contain' >>> B.spatial_relation(A) 'in' >>> B = SpatialExtent( ... north=90, south=30, east=50, west=20, bottom=-40, top=40 ... ) >>> A.spatial_relation_2d(B) 'overlap' >>> A.spatial_relation(B) 'overlap' >>> B = SpatialExtent( ... north=90, south=5, east=70, west=5, bottom=-40, top=40 ... ) >>> A.spatial_relation_2d(B) 'in' >>> A.spatial_relation(B) 'overlap' >>> B = SpatialExtent( ... north=90, south=5, east=70, west=5, bottom=-40, top=60 ... ) >>> A.spatial_relation(B) 'overlap' >>> B = SpatialExtent( ... north=90, south=5, east=70, west=5, bottom=-60, top=60 ... ) >>> A.spatial_relation(B) 'in' >>> A = SpatialExtent( ... north=80, south=60, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=60, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=60, south=40, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=80, south=60, east=60, west=10, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=40, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=80, south=40, east=40, west=20, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=40, west=20, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=90, south=30, east=60, west=40, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=40, west=20, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=70, south=50, east=60, west=40, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=40, west=20, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=60, south=20, east=60, west=40, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'meet' >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=40, west=20, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=40, south=20, east=60, west=40, bottom=-50, top=50 ... ) >>> A.spatial_relation_2d(B) 'disjoint' >>> A.spatial_relation(B) 'disjoint' >>> A = SpatialExtent( ... north=80, south=40, east=40, west=20, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=60, south=20, east=60, west=40, bottom=-60, top=60 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=40, west=20, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=90, south=30, east=60, west=40, bottom=-40, top=40 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=0, top=50 ... ) >>> B = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=-50, top=0 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=0, top=50 ... ) >>> B = SpatialExtent( ... north=80, south=50, east=60, west=30, bottom=-50, top=0 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=0, top=50 ... ) >>> B = SpatialExtent( ... north=70, south=50, east=50, west=30, bottom=-50, top=0 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=0, top=50 ... ) >>> B = SpatialExtent( ... north=90, south=30, east=70, west=10, bottom=-50, top=0 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=0, top=50 ... ) >>> B = SpatialExtent( ... north=70, south=30, east=50, west=10, bottom=-50, top=0 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=-50, top=0 ... ) >>> B = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=0, top=50 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=-50, top=0 ... ) >>> B = SpatialExtent( ... north=80, south=50, east=60, west=30, bottom=0, top=50 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=-50, top=0 ... ) >>> B = SpatialExtent( ... north=70, south=50, east=50, west=30, bottom=0, top=50 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=-50, top=0 ... ) >>> B = SpatialExtent( ... north=90, south=30, east=70, west=10, bottom=0, top=50 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=40, east=60, west=20, bottom=-50, top=0 ... ) >>> B = SpatialExtent( ... north=70, south=30, east=50, west=10, bottom=0, top=50 ... ) >>> A.spatial_relation(B) 'meet' >>> A = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=90, south=81, east=60, west=10, bottom=-50, top=50 ... ) >>> A.spatial_relation(B) 'disjoint' >>> A = SpatialExtent( ... north=80, south=20, east=60, west=10, bottom=-50, top=50 ... ) >>> B = SpatialExtent( ... north=90, south=80, east=60, west=10, bottom=-50, top=50 ... ) >>> A.spatial_relation(B) 'meet' """ if self.equivalent(extent): return "equivalent" if self.contain(extent): return "contain" if self.is_in(extent): return "in" if self.cover(extent): return "cover" if self.covered(extent): return "covered" if self.overlap(extent): return "overlap" if self.meet(extent): return "meet" if self.disjoint(extent): return "disjoint" return "unknown"
[docs] def set_spatial_extent_from_values(self, north, south, east, west, top, bottom): """Set the three dimensional spatial extent :param north: The northern edge :param south: The southern edge :param east: The eastern edge :param west: The western edge :param top: The top edge :param bottom: The bottom edge """ self.set_north(north) self.set_south(south) self.set_east(east) self.set_west(west) self.set_top(top) self.set_bottom(bottom)
[docs] def set_spatial_extent(self, spatial_extent): """Set the three dimensional spatial extent :param spatial_extent: An object of type SpatialExtent or its subclasses """ self.set_north(spatial_extent.get_north()) self.set_south(spatial_extent.get_south()) self.set_east(spatial_extent.get_east()) self.set_west(spatial_extent.get_west()) self.set_top(spatial_extent.get_top()) self.set_bottom(spatial_extent.get_bottom())
[docs] def set_projection(self, proj): """Set the projection of the spatial extent it should be XY or LL. As default the projection is XY """ if proj is None or (proj != "XY" and proj != "LL"): self.D["proj"] = "XY" else: self.D["proj"] = proj
[docs] def set_spatial_extent_from_values_2d(self, north, south, east, west): """Set the two dimensional spatial extent from values :param north: The northern edge :param south: The southern edge :param east: The eastern edge :param west: The western edge """ self.set_north(north) self.set_south(south) self.set_east(east) self.set_west(west)
[docs] def set_spatial_extent_2d(self, spatial_extent): """Set the three dimensional spatial extent :param spatial_extent: An object of type SpatialExtent or its subclasses """ self.set_north(spatial_extent.north) self.set_south(spatial_extent.south) self.set_east(spatial_extent.east) self.set_west(spatial_extent.west)
[docs] def set_id(self, ident): """Convenient method to set the unique identifier (primary key)""" self.ident = ident self.D["id"] = ident
[docs] def set_north(self, north): """Set the northern edge of the map""" if north is not None: self.D["north"] = float(north) else: self.D["north"] = None
[docs] def set_south(self, south): """Set the southern edge of the map""" if south is not None: self.D["south"] = float(south) else: self.D["south"] = None
[docs] def set_west(self, west): """Set the western edge of the map""" if west is not None: self.D["west"] = float(west) else: self.D["west"] = None
[docs] def set_east(self, east): """Set the eastern edge of the map""" if east is not None: self.D["east"] = float(east) else: self.D["east"] = None
[docs] def set_top(self, top): """Set the top edge of the map""" if top is not None: self.D["top"] = float(top) else: self.D["top"] = None
[docs] def set_bottom(self, bottom): """Set the bottom edge of the map""" if bottom is not None: self.D["bottom"] = float(bottom) else: self.D["bottom"] = None
[docs] def get_id(self): """Convenient method to get the unique identifier (primary key) :return: None if not found """ if "id" in self.D: return self.D["id"] else: return None
[docs] def get_projection(self): """Get the projection of the spatial extent""" return self.D["proj"]
[docs] def get_volume(self): """Compute the volume of the extent, in case z is zero (top == bottom or top - bottom = 1) the area is returned""" if self.get_projection() == "LL": self.msgr.error( _("Volume computation is not supported " "for LL projections") ) area = self.get_area() bbox = self.get_spatial_extent_as_tuple() z = abs(bbox[4] - bbox[5]) if z == 0: z = 1.0 return area * z
[docs] def get_area(self): """Compute the area of the extent, extent in z direction is ignored""" if self.get_projection() == "LL": self.msgr.error( _("Area computation is not supported " "for LL projections") ) bbox = self.get_spatial_extent_as_tuple() y = abs(bbox[0] - bbox[1]) x = abs(bbox[2] - bbox[3]) return x * y
[docs] def get_spatial_extent_as_tuple(self): """Return a tuple (north, south, east, west, top, bottom) of the spatial extent""" return (self.north, self.south, self.east, self.west, self.top, self.bottom)
[docs] def get_spatial_extent_as_tuple_2d(self): """Return a tuple (north, south, east, west,) of the 2d spatial extent""" return (self.north, self.south, self.east, self.west)
[docs] def get_north(self): """Get the northern edge of the map :return: None if not found""" if "north" in self.D: return self.D["north"] else: return None
[docs] def get_south(self): """Get the southern edge of the map :return: None if not found""" if "south" in self.D: return self.D["south"] else: return None
[docs] def get_east(self): """Get the eastern edge of the map :return: None if not found""" if "east" in self.D: return self.D["east"] else: return None
[docs] def get_west(self): """Get the western edge of the map :return: None if not found""" if "west" in self.D: return self.D["west"] else: return None
[docs] def get_top(self): """Get the top edge of the map :return: None if not found""" if "top" in self.D: return self.D["top"] else: return None
[docs] def get_bottom(self): """Get the bottom edge of the map :return: None if not found""" if "bottom" in self.D: return self.D["bottom"] else: return None
id = property(fget=get_id, fset=set_id) north = property(fget=get_north, fset=set_north) south = property(fget=get_south, fset=set_south) east = property(fget=get_east, fset=set_east) west = property(fget=get_west, fset=set_west) top = property(fget=get_top, fset=set_top) bottom = property(fget=get_bottom, fset=set_bottom)
[docs] def print_info(self): """Print information about this class in human readable style""" # 0123456789012345678901234567890 print( " +-------------------- Spatial extent ----------------------------------------+" # noqa: E501 ) print(" | North:...................... " + str(self.get_north())) print(" | South:...................... " + str(self.get_south())) print(" | East:.. .................... " + str(self.get_east())) print(" | West:....................... " + str(self.get_west())) print(" | Top:........................ " + str(self.get_top())) print(" | Bottom:..................... " + str(self.get_bottom()))
[docs] def print_shell_info(self): """Print information about this class in shell style""" print("north=" + str(self.get_north())) print("south=" + str(self.get_south())) print("east=" + str(self.get_east())) print("west=" + str(self.get_west())) print("top=" + str(self.get_top())) print("bottom=" + str(self.get_bottom()))
###############################################################################
[docs]class RasterSpatialExtent(SpatialExtent): def __init__( self, ident=None, north=None, south=None, east=None, west=None, top=None, bottom=None, ): SpatialExtent.__init__( self, "raster_spatial_extent", ident, north, south, east, west, top, bottom )
[docs]class Raster3DSpatialExtent(SpatialExtent): def __init__( self, ident=None, north=None, south=None, east=None, west=None, top=None, bottom=None, ): SpatialExtent.__init__( self, "raster3d_spatial_extent", ident, north, south, east, west, top, bottom, )
[docs]class VectorSpatialExtent(SpatialExtent): def __init__( self, ident=None, north=None, south=None, east=None, west=None, top=None, bottom=None, ): SpatialExtent.__init__( self, "vector_spatial_extent", ident, north, south, east, west, top, bottom )
[docs]class STRDSSpatialExtent(SpatialExtent): def __init__( self, ident=None, north=None, south=None, east=None, west=None, top=None, bottom=None, ): SpatialExtent.__init__( self, "strds_spatial_extent", ident, north, south, east, west, top, bottom )
[docs]class STR3DSSpatialExtent(SpatialExtent): def __init__( self, ident=None, north=None, south=None, east=None, west=None, top=None, bottom=None, ): SpatialExtent.__init__( self, "str3ds_spatial_extent", ident, north, south, east, west, top, bottom )
[docs]class STVDSSpatialExtent(SpatialExtent): def __init__( self, ident=None, north=None, south=None, east=None, west=None, top=None, bottom=None, ): SpatialExtent.__init__( self, "stvds_spatial_extent", ident, north, south, east, west, top, bottom )
############################################################################### if __name__ == "__main__": import doctest doctest.testmod()