structure saas with tools
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
"""Geometry classes and factories."""
|
||||
|
||||
from shapely.geometry.base import CAP_STYLE, JOIN_STYLE
|
||||
from shapely.geometry.collection import GeometryCollection
|
||||
from shapely.geometry.geo import box, mapping, shape
|
||||
from shapely.geometry.linestring import LineString
|
||||
from shapely.geometry.multilinestring import MultiLineString
|
||||
from shapely.geometry.multipoint import MultiPoint
|
||||
from shapely.geometry.multipolygon import MultiPolygon
|
||||
from shapely.geometry.point import Point
|
||||
from shapely.geometry.polygon import LinearRing, Polygon
|
||||
|
||||
__all__ = [
|
||||
"CAP_STYLE",
|
||||
"JOIN_STYLE",
|
||||
"GeometryCollection",
|
||||
"LineString",
|
||||
"LinearRing",
|
||||
"MultiLineString",
|
||||
"MultiPoint",
|
||||
"MultiPolygon",
|
||||
"Point",
|
||||
"Polygon",
|
||||
"box",
|
||||
"mapping",
|
||||
"shape",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1138
.venv/lib/python3.10/site-packages/shapely/geometry/base.py
Normal file
1138
.venv/lib/python3.10/site-packages/shapely/geometry/base.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
"""Multi-part collections of geometries."""
|
||||
|
||||
import shapely
|
||||
from shapely.geometry.base import BaseGeometry, BaseMultipartGeometry
|
||||
|
||||
|
||||
class GeometryCollection(BaseMultipartGeometry):
|
||||
"""Collection of one or more geometries that can be of different types.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
geoms : list
|
||||
A list of shapely geometry instances, which may be of varying geometry
|
||||
types.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
geoms : sequence
|
||||
A sequence of Shapely geometry instances
|
||||
|
||||
Examples
|
||||
--------
|
||||
Create a GeometryCollection with a Point and a LineString
|
||||
|
||||
>>> from shapely import GeometryCollection, LineString, Point
|
||||
>>> p = Point(51, -1)
|
||||
>>> l = LineString([(52, -1), (49, 2)])
|
||||
>>> gc = GeometryCollection([p, l])
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = []
|
||||
|
||||
def __new__(self, geoms=None):
|
||||
"""Create a new GeometryCollection."""
|
||||
if isinstance(geoms, BaseGeometry):
|
||||
# TODO(shapely-2.0) do we actually want to split Multi-part geometries?
|
||||
# this is needed for the split() tests
|
||||
if hasattr(geoms, "geoms"):
|
||||
geoms = geoms.geoms
|
||||
else:
|
||||
geoms = [geoms]
|
||||
elif geoms is None or len(geoms) == 0:
|
||||
# TODO better empty constructor
|
||||
return shapely.from_wkt("GEOMETRYCOLLECTION EMPTY")
|
||||
|
||||
return shapely.geometrycollections(geoms)
|
||||
|
||||
@property
|
||||
def __geo_interface__(self):
|
||||
"""Return a GeoJSON-like mapping of the geometry collection."""
|
||||
geometries = []
|
||||
for geom in self.geoms:
|
||||
geometries.append(geom.__geo_interface__)
|
||||
return dict(type="GeometryCollection", geometries=geometries)
|
||||
|
||||
|
||||
shapely.lib.registry[7] = GeometryCollection
|
||||
143
.venv/lib/python3.10/site-packages/shapely/geometry/geo.py
Normal file
143
.venv/lib/python3.10/site-packages/shapely/geometry/geo.py
Normal file
@@ -0,0 +1,143 @@
|
||||
"""Geometry factories based on the geo interface."""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from shapely.errors import GeometryTypeError
|
||||
from shapely.geometry.collection import GeometryCollection
|
||||
from shapely.geometry.linestring import LineString
|
||||
from shapely.geometry.multilinestring import MultiLineString
|
||||
from shapely.geometry.multipoint import MultiPoint
|
||||
from shapely.geometry.multipolygon import MultiPolygon
|
||||
from shapely.geometry.point import Point
|
||||
from shapely.geometry.polygon import LinearRing, Polygon
|
||||
|
||||
|
||||
def _is_coordinates_empty(coordinates):
|
||||
"""Identify if coordinates or subset of coordinates are empty."""
|
||||
if coordinates is None:
|
||||
return True
|
||||
|
||||
if isinstance(coordinates, (list, tuple, np.ndarray)):
|
||||
if len(coordinates) == 0:
|
||||
return True
|
||||
return all(map(_is_coordinates_empty, coordinates))
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def _empty_shape_for_no_coordinates(geom_type):
|
||||
"""Return empty counterpart for geom_type."""
|
||||
if geom_type == "point":
|
||||
return Point()
|
||||
elif geom_type == "multipoint":
|
||||
return MultiPoint()
|
||||
elif geom_type == "linestring":
|
||||
return LineString()
|
||||
elif geom_type == "multilinestring":
|
||||
return MultiLineString()
|
||||
elif geom_type == "polygon":
|
||||
return Polygon()
|
||||
elif geom_type == "multipolygon":
|
||||
return MultiPolygon()
|
||||
else:
|
||||
raise GeometryTypeError(f"Unknown geometry type: {geom_type!r}")
|
||||
|
||||
|
||||
def box(minx, miny, maxx, maxy, ccw=True):
|
||||
"""Return a rectangular polygon with configurable normal vector."""
|
||||
coords = [(maxx, miny), (maxx, maxy), (minx, maxy), (minx, miny)]
|
||||
if not ccw:
|
||||
coords = coords[::-1]
|
||||
return Polygon(coords)
|
||||
|
||||
|
||||
def shape(context):
|
||||
"""Return a new, independent geometry with coordinates copied from the context.
|
||||
|
||||
Changes to the original context will not be reflected in the geometry
|
||||
object.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
context :
|
||||
a GeoJSON-like dict, which provides a "type" member describing the type
|
||||
of the geometry and "coordinates" member providing a list of coordinates,
|
||||
or an object which implements __geo_interface__.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Geometry object
|
||||
|
||||
Examples
|
||||
--------
|
||||
Create a Point from GeoJSON, and then create a copy using __geo_interface__.
|
||||
|
||||
>>> from shapely.geometry import shape
|
||||
>>> context = {'type': 'Point', 'coordinates': [0, 1]}
|
||||
>>> geom = shape(context)
|
||||
>>> geom.geom_type == 'Point'
|
||||
True
|
||||
>>> geom.wkt
|
||||
'POINT (0 1)'
|
||||
>>> geom2 = shape(geom)
|
||||
>>> geom == geom2
|
||||
True
|
||||
|
||||
"""
|
||||
if hasattr(context, "__geo_interface__"):
|
||||
ob = context.__geo_interface__
|
||||
else:
|
||||
ob = context
|
||||
geom_type = ob.get("type").lower()
|
||||
|
||||
if geom_type == "feature":
|
||||
# GeoJSON features must have a 'geometry' field.
|
||||
ob = ob["geometry"]
|
||||
geom_type = ob.get("type").lower()
|
||||
|
||||
if "coordinates" in ob and _is_coordinates_empty(ob["coordinates"]):
|
||||
return _empty_shape_for_no_coordinates(geom_type)
|
||||
elif geom_type == "point":
|
||||
return Point(ob["coordinates"])
|
||||
elif geom_type == "linestring":
|
||||
return LineString(ob["coordinates"])
|
||||
elif geom_type == "linearring":
|
||||
return LinearRing(ob["coordinates"])
|
||||
elif geom_type == "polygon":
|
||||
return Polygon(ob["coordinates"][0], ob["coordinates"][1:])
|
||||
elif geom_type == "multipoint":
|
||||
return MultiPoint(ob["coordinates"])
|
||||
elif geom_type == "multilinestring":
|
||||
return MultiLineString(ob["coordinates"])
|
||||
elif geom_type == "multipolygon":
|
||||
return MultiPolygon([[c[0], c[1:]] for c in ob["coordinates"]])
|
||||
elif geom_type == "geometrycollection":
|
||||
geoms = [shape(g) for g in ob.get("geometries", [])]
|
||||
return GeometryCollection(geoms)
|
||||
else:
|
||||
raise GeometryTypeError(f"Unknown geometry type: {geom_type!r}")
|
||||
|
||||
|
||||
def mapping(ob):
|
||||
"""Return a GeoJSON-like mapping.
|
||||
|
||||
Input should be a Geometry or an object which implements __geo_interface__.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ob : geometry or object
|
||||
An object which implements __geo_interface__.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from shapely.geometry import mapping, Point
|
||||
>>> pt = Point(0, 0)
|
||||
>>> mapping(pt)
|
||||
{'type': 'Point', 'coordinates': (0.0, 0.0)}
|
||||
|
||||
"""
|
||||
return ob.__geo_interface__
|
||||
@@ -0,0 +1,211 @@
|
||||
"""Line strings and related utilities."""
|
||||
|
||||
import numpy as np
|
||||
|
||||
import shapely
|
||||
from shapely.decorators import deprecate_positional
|
||||
from shapely.geometry.base import JOIN_STYLE, BaseGeometry
|
||||
from shapely.geometry.point import Point
|
||||
|
||||
__all__ = ["LineString"]
|
||||
|
||||
|
||||
class LineString(BaseGeometry):
|
||||
"""A geometry type composed of one or more line segments.
|
||||
|
||||
A LineString is a one-dimensional feature and has a non-zero length but
|
||||
zero area. It may approximate a curve and need not be straight. A LineString may
|
||||
be closed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
coordinates : sequence
|
||||
A sequence of (x, y, [,z]) numeric coordinate pairs or triples, or
|
||||
an array-like with shape (N, 2) or (N, 3).
|
||||
Also can be a sequence of Point objects, or combination of both.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Create a LineString with two segments
|
||||
|
||||
>>> from shapely import LineString
|
||||
>>> a = LineString([[0, 0], [1, 0], [1, 1]])
|
||||
>>> a.length
|
||||
2.0
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = []
|
||||
|
||||
def __new__(self, coordinates=None):
|
||||
"""Create a new LineString geometry."""
|
||||
if coordinates is None:
|
||||
# empty geometry
|
||||
# TODO better constructor
|
||||
return shapely.from_wkt("LINESTRING EMPTY")
|
||||
elif isinstance(coordinates, LineString):
|
||||
if type(coordinates) is LineString:
|
||||
# return original objects since geometries are immutable
|
||||
return coordinates
|
||||
else:
|
||||
# LinearRing
|
||||
# TODO convert LinearRing to LineString more directly
|
||||
coordinates = coordinates.coords
|
||||
else:
|
||||
if hasattr(coordinates, "__array__"):
|
||||
coordinates = np.asarray(coordinates)
|
||||
if isinstance(coordinates, np.ndarray) and np.issubdtype(
|
||||
coordinates.dtype, np.number
|
||||
):
|
||||
pass
|
||||
else:
|
||||
# check coordinates on points
|
||||
def _coords(o):
|
||||
if isinstance(o, Point):
|
||||
return o.coords[0]
|
||||
else:
|
||||
return [float(c) for c in o]
|
||||
|
||||
coordinates = [_coords(o) for o in coordinates]
|
||||
|
||||
if len(coordinates) == 0:
|
||||
# empty geometry
|
||||
# TODO better constructor + should shapely.linestrings handle this?
|
||||
return shapely.from_wkt("LINESTRING EMPTY")
|
||||
|
||||
geom = shapely.linestrings(coordinates)
|
||||
if not isinstance(geom, LineString):
|
||||
raise ValueError("Invalid values passed to LineString constructor")
|
||||
return geom
|
||||
|
||||
@property
|
||||
def __geo_interface__(self):
|
||||
"""Return a GeoJSON-like mapping of the LineString geometry."""
|
||||
return {"type": "LineString", "coordinates": tuple(self.coords)}
|
||||
|
||||
def svg(self, scale_factor=1.0, stroke_color=None, opacity=None):
|
||||
"""Return SVG polyline element for the LineString geometry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scale_factor : float
|
||||
Multiplication factor for the SVG stroke-width. Default is 1.
|
||||
stroke_color : str, optional
|
||||
Hex string for stroke color. Default is to use "#66cc99" if
|
||||
geometry is valid, and "#ff3333" if invalid.
|
||||
opacity : float
|
||||
Float number between 0 and 1 for color opacity. Default value is 0.8
|
||||
|
||||
"""
|
||||
if self.is_empty:
|
||||
return "<g />"
|
||||
if stroke_color is None:
|
||||
stroke_color = "#66cc99" if self.is_valid else "#ff3333"
|
||||
if opacity is None:
|
||||
opacity = 0.8
|
||||
pnt_format = " ".join(["{},{}".format(*c) for c in self.coords])
|
||||
return (
|
||||
f'<polyline fill="none" stroke="{stroke_color}" '
|
||||
f'stroke-width="{2.0 * scale_factor}" '
|
||||
f'points="{pnt_format}" opacity="{opacity}" />'
|
||||
)
|
||||
|
||||
@property
|
||||
def xy(self):
|
||||
"""Separate arrays of X and Y coordinate values.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from shapely import LineString
|
||||
>>> x, y = LineString([(0, 0), (1, 1)]).xy
|
||||
>>> list(x)
|
||||
[0.0, 1.0]
|
||||
>>> list(y)
|
||||
[0.0, 1.0]
|
||||
|
||||
"""
|
||||
return self.coords.xy
|
||||
|
||||
# Note: future plan is to change this signature over a few releases:
|
||||
# shapely 2.0:
|
||||
# offset_curve(self, distance, quad_segs=16, ...)
|
||||
# shapely 2.1: shows deprecation warning about positional 'quad_segs', etc.
|
||||
# same signature as 2.0
|
||||
# shapely 2.2(?): enforce keyword-only arguments after 'distance'
|
||||
# offset_curve(self, distance, *, quad_segs=16, ...)
|
||||
|
||||
@deprecate_positional(
|
||||
["quad_segs", "join_style", "mitre_limit"], category=DeprecationWarning
|
||||
)
|
||||
def offset_curve(
|
||||
self,
|
||||
distance,
|
||||
quad_segs=16,
|
||||
join_style=JOIN_STYLE.round,
|
||||
mitre_limit=5.0,
|
||||
):
|
||||
"""Return a (Multi)LineString at a distance from the object.
|
||||
|
||||
The side, left or right, is determined by the sign of the `distance`
|
||||
parameter (negative for right side offset, positive for left side
|
||||
offset). The resolution of the buffer around each vertex of the object
|
||||
increases by increasing the `quad_segs` keyword parameter.
|
||||
|
||||
The join style is for outside corners between line segments. Accepted
|
||||
values are JOIN_STYLE.round (1), JOIN_STYLE.mitre (2), and
|
||||
JOIN_STYLE.bevel (3).
|
||||
|
||||
The mitre ratio limit is used for very sharp corners. It is the ratio
|
||||
of the distance from the corner to the end of the mitred offset corner.
|
||||
When two line segments meet at a sharp angle, a miter join will extend
|
||||
far beyond the original geometry. To prevent unreasonable geometry, the
|
||||
mitre limit allows controlling the maximum length of the join corner.
|
||||
Corners with a ratio which exceed the limit will be beveled.
|
||||
|
||||
Note: the behaviour regarding orientation of the resulting line
|
||||
depends on the GEOS version. With GEOS < 3.11, the line retains the
|
||||
same direction for a left offset (positive distance) or has reverse
|
||||
direction for a right offset (negative distance), and this behaviour
|
||||
was documented as such in previous Shapely versions. Starting with
|
||||
GEOS 3.11, the function tries to preserve the orientation of the
|
||||
original line.
|
||||
"""
|
||||
if mitre_limit == 0.0:
|
||||
raise ValueError("Cannot compute offset from zero-length line segment")
|
||||
elif not np.isfinite(distance):
|
||||
raise ValueError("offset_curve distance must be finite")
|
||||
return shapely.offset_curve(
|
||||
self,
|
||||
distance,
|
||||
quad_segs=quad_segs,
|
||||
join_style=join_style,
|
||||
mitre_limit=mitre_limit,
|
||||
)
|
||||
|
||||
def parallel_offset(
|
||||
self,
|
||||
distance,
|
||||
side="right",
|
||||
resolution=16,
|
||||
join_style=JOIN_STYLE.round,
|
||||
mitre_limit=5.0,
|
||||
):
|
||||
"""Alternative method to :meth:`offset_curve` method.
|
||||
|
||||
Older alternative method to the :meth:`offset_curve` method, but uses
|
||||
``resolution`` instead of ``quad_segs`` and a ``side`` keyword
|
||||
('left' or 'right') instead of sign of the distance. This method is
|
||||
kept for backwards compatibility for now, but is is recommended to
|
||||
use :meth:`offset_curve` instead.
|
||||
"""
|
||||
if side == "right":
|
||||
distance *= -1
|
||||
return self.offset_curve(
|
||||
distance,
|
||||
quad_segs=resolution,
|
||||
join_style=join_style,
|
||||
mitre_limit=mitre_limit,
|
||||
)
|
||||
|
||||
|
||||
shapely.lib.registry[1] = LineString
|
||||
@@ -0,0 +1,95 @@
|
||||
"""Collections of linestrings and related utilities."""
|
||||
|
||||
import shapely
|
||||
from shapely.errors import EmptyPartError
|
||||
from shapely.geometry import linestring
|
||||
from shapely.geometry.base import BaseMultipartGeometry
|
||||
|
||||
__all__ = ["MultiLineString"]
|
||||
|
||||
|
||||
class MultiLineString(BaseMultipartGeometry):
|
||||
"""A collection of one or more LineStrings.
|
||||
|
||||
A MultiLineString has non-zero length and zero area.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lines : sequence
|
||||
A sequence LineStrings, or a sequence of line-like coordinate
|
||||
sequences or array-likes (see accepted input for LineString).
|
||||
|
||||
Attributes
|
||||
----------
|
||||
geoms : sequence
|
||||
A sequence of LineStrings
|
||||
|
||||
Examples
|
||||
--------
|
||||
Construct a MultiLineString containing two LineStrings.
|
||||
|
||||
>>> from shapely import MultiLineString
|
||||
>>> lines = MultiLineString([[[0, 0], [1, 2]], [[4, 4], [5, 6]]])
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = []
|
||||
|
||||
def __new__(self, lines=None):
|
||||
"""Create a new MultiLineString geometry."""
|
||||
if not lines:
|
||||
# allow creation of empty multilinestrings, to support unpickling
|
||||
# TODO better empty constructor
|
||||
return shapely.from_wkt("MULTILINESTRING EMPTY")
|
||||
elif isinstance(lines, MultiLineString):
|
||||
return lines
|
||||
|
||||
lines = getattr(lines, "geoms", lines)
|
||||
subs = []
|
||||
for item in lines:
|
||||
line = linestring.LineString(item)
|
||||
if line.is_empty:
|
||||
raise EmptyPartError(
|
||||
"Can't create MultiLineString with empty component"
|
||||
)
|
||||
subs.append(line)
|
||||
|
||||
if len(lines) == 0:
|
||||
return shapely.from_wkt("MULTILINESTRING EMPTY")
|
||||
|
||||
return shapely.multilinestrings(subs)
|
||||
|
||||
@property
|
||||
def __geo_interface__(self):
|
||||
"""Return a GeoJSON-like mapping interface for this MultiLineString."""
|
||||
return {
|
||||
"type": "MultiLineString",
|
||||
"coordinates": tuple(tuple(c for c in g.coords) for g in self.geoms),
|
||||
}
|
||||
|
||||
def svg(self, scale_factor=1.0, stroke_color=None, opacity=None):
|
||||
"""Return a group of SVG polyline elements for the LineString geometry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scale_factor : float
|
||||
Multiplication factor for the SVG stroke-width. Default is 1.
|
||||
stroke_color : str, optional
|
||||
Hex string for stroke color. Default is to use "#66cc99" if
|
||||
geometry is valid, and "#ff3333" if invalid.
|
||||
opacity : float
|
||||
Float number between 0 and 1 for color opacity. Default value is 0.8
|
||||
|
||||
"""
|
||||
if self.is_empty:
|
||||
return "<g />"
|
||||
if stroke_color is None:
|
||||
stroke_color = "#66cc99" if self.is_valid else "#ff3333"
|
||||
return (
|
||||
"<g>"
|
||||
+ "".join(p.svg(scale_factor, stroke_color, opacity) for p in self.geoms)
|
||||
+ "</g>"
|
||||
)
|
||||
|
||||
|
||||
shapely.lib.registry[5] = MultiLineString
|
||||
@@ -0,0 +1,104 @@
|
||||
"""Collections of points and related utilities."""
|
||||
|
||||
import numpy as np
|
||||
|
||||
import shapely
|
||||
from shapely.errors import EmptyPartError
|
||||
from shapely.geometry import point
|
||||
from shapely.geometry.base import BaseMultipartGeometry
|
||||
|
||||
__all__ = ["MultiPoint"]
|
||||
|
||||
|
||||
class MultiPoint(BaseMultipartGeometry):
|
||||
"""A collection of one or more Points.
|
||||
|
||||
A MultiPoint has zero area and zero length.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
points : sequence
|
||||
A sequence of Points, or a sequence of (x, y [,z]) numeric coordinate
|
||||
pairs or triples, or an array-like of shape (N, 2) or (N, 3).
|
||||
|
||||
Attributes
|
||||
----------
|
||||
geoms : sequence
|
||||
A sequence of Points
|
||||
|
||||
Examples
|
||||
--------
|
||||
Construct a MultiPoint containing two Points
|
||||
|
||||
>>> from shapely import MultiPoint, Point
|
||||
>>> ob = MultiPoint([[0.0, 0.0], [1.0, 2.0]])
|
||||
>>> len(ob.geoms)
|
||||
2
|
||||
>>> type(ob.geoms[0]) == Point
|
||||
True
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = []
|
||||
|
||||
def __new__(self, points=None):
|
||||
"""Create a new MultiPoint geometry."""
|
||||
if points is None:
|
||||
# allow creation of empty multipoints, to support unpickling
|
||||
# TODO better empty constructor
|
||||
return shapely.from_wkt("MULTIPOINT EMPTY")
|
||||
elif isinstance(points, MultiPoint):
|
||||
return points
|
||||
elif len(points) == 0:
|
||||
return shapely.from_wkt("MULTIPOINT EMPTY")
|
||||
|
||||
if isinstance(points, np.ndarray) and np.issubdtype(points.dtype, np.number):
|
||||
subs = shapely.points(points)
|
||||
if not subs.ndim == 1:
|
||||
raise ValueError("Invalid values passed to MultiPoint constructor")
|
||||
if shapely.is_empty(subs).any():
|
||||
raise EmptyPartError("Can't create MultiPoint with empty component")
|
||||
else:
|
||||
subs = []
|
||||
for item in points:
|
||||
p = point.Point(item)
|
||||
if p.is_empty:
|
||||
raise EmptyPartError("Can't create MultiPoint with empty component")
|
||||
subs.append(p)
|
||||
|
||||
return shapely.multipoints(subs)
|
||||
|
||||
@property
|
||||
def __geo_interface__(self):
|
||||
"""Return a GeoJSON-like mapping interface for this MultiPoint."""
|
||||
return {
|
||||
"type": "MultiPoint",
|
||||
"coordinates": tuple(g.coords[0] for g in self.geoms),
|
||||
}
|
||||
|
||||
def svg(self, scale_factor=1.0, fill_color=None, opacity=None):
|
||||
"""Return a group of SVG circle elements for the MultiPoint geometry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scale_factor : float
|
||||
Multiplication factor for the SVG circle diameters. Default is 1.
|
||||
fill_color : str, optional
|
||||
Hex string for fill color. Default is to use "#66cc99" if
|
||||
geometry is valid, and "#ff3333" if invalid.
|
||||
opacity : float
|
||||
Float number between 0 and 1 for color opacity. Default value is 0.6
|
||||
|
||||
"""
|
||||
if self.is_empty:
|
||||
return "<g />"
|
||||
if fill_color is None:
|
||||
fill_color = "#66cc99" if self.is_valid else "#ff3333"
|
||||
return (
|
||||
"<g>"
|
||||
+ "".join(p.svg(scale_factor, fill_color, opacity) for p in self.geoms)
|
||||
+ "</g>"
|
||||
)
|
||||
|
||||
|
||||
shapely.lib.registry[4] = MultiPoint
|
||||
@@ -0,0 +1,125 @@
|
||||
"""Collections of polygons and related utilities."""
|
||||
|
||||
import shapely
|
||||
from shapely.geometry import polygon
|
||||
from shapely.geometry.base import BaseMultipartGeometry
|
||||
|
||||
__all__ = ["MultiPolygon"]
|
||||
|
||||
|
||||
class MultiPolygon(BaseMultipartGeometry):
|
||||
"""A collection of one or more Polygons.
|
||||
|
||||
If component polygons overlap the collection is invalid and some
|
||||
operations on it may fail.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
polygons : sequence
|
||||
A sequence of Polygons, or a sequence of (shell, holes) tuples
|
||||
where shell is the sequence representation of a linear ring
|
||||
(see LinearRing) and holes is a sequence of such linear rings.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
geoms : sequence
|
||||
A sequence of `Polygon` instances
|
||||
|
||||
Examples
|
||||
--------
|
||||
Construct a MultiPolygon from a sequence of coordinate tuples
|
||||
|
||||
>>> from shapely import MultiPolygon, Polygon
|
||||
>>> ob = MultiPolygon([
|
||||
... (
|
||||
... ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)),
|
||||
... [((0.1,0.1), (0.1,0.2), (0.2,0.2), (0.2,0.1))]
|
||||
... )
|
||||
... ])
|
||||
>>> len(ob.geoms)
|
||||
1
|
||||
>>> type(ob.geoms[0]) == Polygon
|
||||
True
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = []
|
||||
|
||||
def __new__(self, polygons=None):
|
||||
"""Create a new MultiPolygon geometry."""
|
||||
if polygons is None:
|
||||
# allow creation of empty multipolygons, to support unpickling
|
||||
# TODO better empty constructor
|
||||
return shapely.from_wkt("MULTIPOLYGON EMPTY")
|
||||
elif isinstance(polygons, MultiPolygon):
|
||||
return polygons
|
||||
|
||||
polygons = getattr(polygons, "geoms", polygons)
|
||||
# remove None and empty polygons from list of Polygons
|
||||
polygons = [p for p in polygons if p]
|
||||
|
||||
L = len(polygons)
|
||||
|
||||
# Bail immediately if we have no input points.
|
||||
if L == 0:
|
||||
return shapely.from_wkt("MULTIPOLYGON EMPTY")
|
||||
|
||||
# This function does not accept sequences of MultiPolygons: there is
|
||||
# no implicit flattening.
|
||||
if any(isinstance(p, MultiPolygon) for p in polygons):
|
||||
raise ValueError("Sequences of multi-polygons are not valid arguments")
|
||||
|
||||
subs = []
|
||||
for i in range(L):
|
||||
ob = polygons[i]
|
||||
if not isinstance(ob, polygon.Polygon):
|
||||
shell = ob[0]
|
||||
if len(ob) > 1:
|
||||
holes = ob[1]
|
||||
else:
|
||||
holes = None
|
||||
p = polygon.Polygon(shell, holes)
|
||||
else:
|
||||
p = polygon.Polygon(ob)
|
||||
subs.append(p)
|
||||
|
||||
return shapely.multipolygons(subs)
|
||||
|
||||
@property
|
||||
def __geo_interface__(self):
|
||||
"""Return a GeoJSON-like mapping of the MultiPolygon geometry."""
|
||||
allcoords = []
|
||||
for geom in self.geoms:
|
||||
coords = []
|
||||
coords.append(tuple(geom.exterior.coords))
|
||||
for hole in geom.interiors:
|
||||
coords.append(tuple(hole.coords))
|
||||
allcoords.append(tuple(coords))
|
||||
return {"type": "MultiPolygon", "coordinates": allcoords}
|
||||
|
||||
def svg(self, scale_factor=1.0, fill_color=None, opacity=None):
|
||||
"""Return group of SVG path elements for the MultiPolygon geometry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scale_factor : float
|
||||
Multiplication factor for the SVG stroke-width. Default is 1.
|
||||
fill_color : str, optional
|
||||
Hex string for fill color. Default is to use "#66cc99" if
|
||||
geometry is valid, and "#ff3333" if invalid.
|
||||
opacity : float
|
||||
Float number between 0 and 1 for color opacity. Default value is 0.6
|
||||
|
||||
"""
|
||||
if self.is_empty:
|
||||
return "<g />"
|
||||
if fill_color is None:
|
||||
fill_color = "#66cc99" if self.is_valid else "#ff3333"
|
||||
return (
|
||||
"<g>"
|
||||
+ "".join(p.svg(scale_factor, fill_color, opacity) for p in self.geoms)
|
||||
+ "</g>"
|
||||
)
|
||||
|
||||
|
||||
shapely.lib.registry[6] = MultiPolygon
|
||||
166
.venv/lib/python3.10/site-packages/shapely/geometry/point.py
Normal file
166
.venv/lib/python3.10/site-packages/shapely/geometry/point.py
Normal file
@@ -0,0 +1,166 @@
|
||||
"""Points and related utilities."""
|
||||
|
||||
import numpy as np
|
||||
|
||||
import shapely
|
||||
from shapely.errors import DimensionError
|
||||
from shapely.geometry.base import BaseGeometry
|
||||
|
||||
__all__ = ["Point"]
|
||||
|
||||
|
||||
class Point(BaseGeometry):
|
||||
"""A geometry type that represents a single coordinate.
|
||||
|
||||
Each coordinate has x, y and possibly z and/or m values.
|
||||
|
||||
A point is a zero-dimensional feature and has zero length and zero area.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
args : float, or sequence of floats
|
||||
The coordinates can either be passed as a single parameter, or as
|
||||
individual float values using multiple parameters:
|
||||
|
||||
1) 1 parameter: a sequence or array-like of with 2 or 3 values.
|
||||
2) 2 or 3 parameters (float): x, y, and possibly z.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
x, y, z, m : float
|
||||
Coordinate values
|
||||
|
||||
Examples
|
||||
--------
|
||||
Constructing the Point using separate parameters for x and y:
|
||||
|
||||
>>> from shapely import Point
|
||||
>>> p = Point(1.0, -1.0)
|
||||
|
||||
Constructing the Point using a list of x, y coordinates:
|
||||
|
||||
>>> p = Point([1.0, -1.0])
|
||||
>>> print(p)
|
||||
POINT (1 -1)
|
||||
>>> p.y
|
||||
-1.0
|
||||
>>> p.x
|
||||
1.0
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = []
|
||||
|
||||
def __new__(self, *args):
|
||||
"""Create a new Point geometry."""
|
||||
if len(args) == 0:
|
||||
# empty geometry
|
||||
# TODO better constructor
|
||||
return shapely.from_wkt("POINT EMPTY")
|
||||
elif len(args) > 3:
|
||||
raise TypeError(f"Point() takes at most 3 arguments ({len(args)} given)")
|
||||
elif len(args) == 1:
|
||||
coords = args[0]
|
||||
if isinstance(coords, Point):
|
||||
return coords
|
||||
|
||||
# Accept either (x, y) or [(x, y)]
|
||||
if not hasattr(coords, "__getitem__"): # generators
|
||||
coords = list(coords)
|
||||
coords = np.asarray(coords).squeeze()
|
||||
else:
|
||||
# 2 or 3 args
|
||||
coords = np.array(args).squeeze()
|
||||
|
||||
if coords.ndim > 1:
|
||||
raise ValueError(
|
||||
f"Point() takes only scalar or 1-size vector arguments, got {args}"
|
||||
)
|
||||
if not np.issubdtype(coords.dtype, np.number):
|
||||
coords = [float(c) for c in coords]
|
||||
geom = shapely.points(coords)
|
||||
if not isinstance(geom, Point):
|
||||
raise ValueError("Invalid values passed to Point constructor")
|
||||
return geom
|
||||
|
||||
# Coordinate getters and setters
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
"""Return x coordinate."""
|
||||
return float(shapely.get_x(self))
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
"""Return y coordinate."""
|
||||
return float(shapely.get_y(self))
|
||||
|
||||
@property
|
||||
def z(self):
|
||||
"""Return z coordinate."""
|
||||
z = shapely.get_z(self)
|
||||
if np.isnan(z) and not shapely.has_z(self):
|
||||
raise DimensionError("This point has no z coordinate.")
|
||||
return float(z)
|
||||
|
||||
@property
|
||||
def m(self):
|
||||
"""Return m coordinate.
|
||||
|
||||
.. versionadded:: 2.1.0
|
||||
Also requires GEOS 3.12.0 or later.
|
||||
"""
|
||||
if not shapely.has_m(self):
|
||||
raise DimensionError("This point has no m coordinate.")
|
||||
return float(shapely.get_m(self))
|
||||
|
||||
@property
|
||||
def __geo_interface__(self):
|
||||
"""Return a GeoJSON-like mapping of the Point geometry."""
|
||||
coords = self.coords
|
||||
return {"type": "Point", "coordinates": coords[0] if len(coords) > 0 else ()}
|
||||
|
||||
def svg(self, scale_factor=1.0, fill_color=None, opacity=None):
|
||||
"""Return SVG circle element for the Point geometry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scale_factor : float
|
||||
Multiplication factor for the SVG circle diameter. Default is 1.
|
||||
fill_color : str, optional
|
||||
Hex string for fill color. Default is to use "#66cc99" if
|
||||
geometry is valid, and "#ff3333" if invalid.
|
||||
opacity : float
|
||||
Float number between 0 and 1 for color opacity. Default value is 0.6
|
||||
|
||||
"""
|
||||
if self.is_empty:
|
||||
return "<g />"
|
||||
if fill_color is None:
|
||||
fill_color = "#66cc99" if self.is_valid else "#ff3333"
|
||||
if opacity is None:
|
||||
opacity = 0.6
|
||||
return (
|
||||
f'<circle cx="{self.x}" cy="{self.y}" r="{3.0 * scale_factor}" '
|
||||
f'stroke="#555555" stroke-width="{1.0 * scale_factor}" fill="{fill_color}" '
|
||||
f'opacity="{opacity}" />'
|
||||
)
|
||||
|
||||
@property
|
||||
def xy(self):
|
||||
"""Separate arrays of X and Y coordinate values.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from shapely import Point
|
||||
>>> x, y = Point(0, 0).xy
|
||||
>>> list(x)
|
||||
[0.0]
|
||||
>>> list(y)
|
||||
[0.0]
|
||||
|
||||
"""
|
||||
return self.coords.xy
|
||||
|
||||
|
||||
shapely.lib.registry[0] = Point
|
||||
345
.venv/lib/python3.10/site-packages/shapely/geometry/polygon.py
Normal file
345
.venv/lib/python3.10/site-packages/shapely/geometry/polygon.py
Normal file
@@ -0,0 +1,345 @@
|
||||
"""Polygons and their linear ring components."""
|
||||
|
||||
import numpy as np
|
||||
|
||||
import shapely
|
||||
from shapely import _geometry_helpers
|
||||
from shapely.algorithms.cga import signed_area # noqa
|
||||
from shapely.errors import TopologicalError
|
||||
from shapely.geometry.base import BaseGeometry
|
||||
from shapely.geometry.linestring import LineString
|
||||
from shapely.geometry.point import Point
|
||||
|
||||
__all__ = ["LinearRing", "Polygon", "orient"]
|
||||
|
||||
|
||||
def _unpickle_linearring(wkb):
|
||||
linestring = shapely.from_wkb(wkb)
|
||||
srid = shapely.get_srid(linestring)
|
||||
linearring = _geometry_helpers.linestring_to_linearring(linestring)
|
||||
if srid:
|
||||
linearring = shapely.set_srid(linearring, srid)
|
||||
return linearring
|
||||
|
||||
|
||||
class LinearRing(LineString):
|
||||
"""Geometry type composed of one or more line segments that forms a closed loop.
|
||||
|
||||
A LinearRing is a closed, one-dimensional feature.
|
||||
A LinearRing that crosses itself or touches itself at a single point is
|
||||
invalid and operations on it may fail.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
coordinates : sequence
|
||||
A sequence of (x, y [,z]) numeric coordinate pairs or triples, or
|
||||
an array-like with shape (N, 2) or (N, 3).
|
||||
Also can be a sequence of Point objects.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Rings are automatically closed. There is no need to specify a final
|
||||
coordinate pair identical to the first.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Construct a square ring.
|
||||
|
||||
>>> from shapely import LinearRing
|
||||
>>> ring = LinearRing( ((0, 0), (0, 1), (1 ,1 ), (1 , 0)) )
|
||||
>>> ring.is_closed
|
||||
True
|
||||
>>> list(ring.coords)
|
||||
[(0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)]
|
||||
>>> ring.length
|
||||
4.0
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = []
|
||||
|
||||
def __new__(self, coordinates=None):
|
||||
"""Create a new LinearRing geometry."""
|
||||
if coordinates is None:
|
||||
# empty geometry
|
||||
# TODO better way?
|
||||
return shapely.from_wkt("LINEARRING EMPTY")
|
||||
elif isinstance(coordinates, LineString):
|
||||
if type(coordinates) is LinearRing:
|
||||
# return original objects since geometries are immutable
|
||||
return coordinates
|
||||
elif not coordinates.is_valid:
|
||||
raise TopologicalError("An input LineString must be valid.")
|
||||
else:
|
||||
# LineString
|
||||
# TODO convert LineString to LinearRing more directly?
|
||||
coordinates = coordinates.coords
|
||||
|
||||
else:
|
||||
if hasattr(coordinates, "__array__"):
|
||||
coordinates = np.asarray(coordinates)
|
||||
if isinstance(coordinates, np.ndarray) and np.issubdtype(
|
||||
coordinates.dtype, np.number
|
||||
):
|
||||
pass
|
||||
else:
|
||||
# check coordinates on points
|
||||
def _coords(o):
|
||||
if isinstance(o, Point):
|
||||
return o.coords[0]
|
||||
else:
|
||||
return [float(c) for c in o]
|
||||
|
||||
coordinates = np.array([_coords(o) for o in coordinates])
|
||||
if not np.issubdtype(coordinates.dtype, np.number):
|
||||
# conversion of coords to 2D array failed, this might be due
|
||||
# to inconsistent coordinate dimensionality
|
||||
raise ValueError("Inconsistent coordinate dimensionality")
|
||||
|
||||
if len(coordinates) == 0:
|
||||
# empty geometry
|
||||
# TODO better constructor + should shapely.linearrings handle this?
|
||||
return shapely.from_wkt("LINEARRING EMPTY")
|
||||
|
||||
geom = shapely.linearrings(coordinates)
|
||||
if not isinstance(geom, LinearRing):
|
||||
raise ValueError("Invalid values passed to LinearRing constructor")
|
||||
return geom
|
||||
|
||||
@property
|
||||
def __geo_interface__(self):
|
||||
"""Return a GeoJSON-like mapping of the LinearRing geometry."""
|
||||
return {"type": "LinearRing", "coordinates": tuple(self.coords)}
|
||||
|
||||
def __reduce__(self):
|
||||
"""Pickle support.
|
||||
|
||||
WKB doesn't differentiate between LineString and LinearRing so we
|
||||
need to move the coordinate sequence into the correct geometry type
|
||||
"""
|
||||
return (_unpickle_linearring, (shapely.to_wkb(self, include_srid=True),))
|
||||
|
||||
@property
|
||||
def is_ccw(self):
|
||||
"""True if the ring is oriented counter clock-wise."""
|
||||
return bool(shapely.is_ccw(self))
|
||||
|
||||
@property
|
||||
def is_simple(self):
|
||||
"""True if the geometry is simple.
|
||||
|
||||
Simple means that any self-intersections are only at boundary points.
|
||||
"""
|
||||
return bool(shapely.is_simple(self))
|
||||
|
||||
|
||||
shapely.lib.registry[2] = LinearRing
|
||||
|
||||
|
||||
class InteriorRingSequence:
|
||||
_parent = None
|
||||
_ndim = None
|
||||
_index = 0
|
||||
_length = 0
|
||||
|
||||
def __init__(self, parent):
|
||||
self._parent = parent
|
||||
self._ndim = parent._ndim
|
||||
|
||||
def __iter__(self):
|
||||
self._index = 0
|
||||
self._length = self.__len__()
|
||||
return self
|
||||
|
||||
def __next__(self):
|
||||
if self._index < self._length:
|
||||
ring = self._get_ring(self._index)
|
||||
self._index += 1
|
||||
return ring
|
||||
else:
|
||||
raise StopIteration
|
||||
|
||||
def __len__(self):
|
||||
return shapely.get_num_interior_rings(self._parent)
|
||||
|
||||
def __getitem__(self, key):
|
||||
m = self.__len__()
|
||||
if isinstance(key, int):
|
||||
if key + m < 0 or key >= m:
|
||||
raise IndexError("index out of range")
|
||||
if key < 0:
|
||||
i = m + key
|
||||
else:
|
||||
i = key
|
||||
return self._get_ring(i)
|
||||
elif isinstance(key, slice):
|
||||
res = []
|
||||
start, stop, stride = key.indices(m)
|
||||
for i in range(start, stop, stride):
|
||||
res.append(self._get_ring(i))
|
||||
return res
|
||||
else:
|
||||
raise TypeError("key must be an index or slice")
|
||||
|
||||
def _get_ring(self, i):
|
||||
return shapely.get_interior_ring(self._parent, i)
|
||||
|
||||
|
||||
class Polygon(BaseGeometry):
|
||||
"""A geometry type representing an area that is enclosed by a linear ring.
|
||||
|
||||
A polygon is a two-dimensional feature and has a non-zero area. It may
|
||||
have one or more negative-space "holes" which are also bounded by linear
|
||||
rings. If any rings cross each other, the feature is invalid and
|
||||
operations on it may fail.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
shell : sequence
|
||||
A sequence of (x, y [,z]) numeric coordinate pairs or triples, or
|
||||
an array-like with shape (N, 2) or (N, 3).
|
||||
Also can be a sequence of Point objects.
|
||||
holes : sequence
|
||||
A sequence of objects which satisfy the same requirements as the
|
||||
shell parameters above
|
||||
|
||||
Attributes
|
||||
----------
|
||||
exterior : LinearRing
|
||||
The ring which bounds the positive space of the polygon.
|
||||
interiors : sequence
|
||||
A sequence of rings which bound all existing holes.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Create a square polygon with no holes
|
||||
|
||||
>>> from shapely import Polygon
|
||||
>>> coords = ((0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.))
|
||||
>>> polygon = Polygon(coords)
|
||||
>>> polygon.area
|
||||
1.0
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = []
|
||||
|
||||
def __new__(self, shell=None, holes=None):
|
||||
"""Create a new Polygon geometry."""
|
||||
if shell is None:
|
||||
# empty geometry
|
||||
# TODO better way?
|
||||
return shapely.from_wkt("POLYGON EMPTY")
|
||||
elif isinstance(shell, Polygon):
|
||||
# return original objects since geometries are immutable
|
||||
return shell
|
||||
else:
|
||||
shell = LinearRing(shell)
|
||||
|
||||
if holes is not None:
|
||||
if len(holes) == 0:
|
||||
# shapely constructor cannot handle holes=[]
|
||||
holes = None
|
||||
else:
|
||||
holes = [LinearRing(ring) for ring in holes]
|
||||
|
||||
geom = shapely.polygons(shell, holes=holes)
|
||||
if not isinstance(geom, Polygon):
|
||||
raise ValueError("Invalid values passed to Polygon constructor")
|
||||
return geom
|
||||
|
||||
@property
|
||||
def exterior(self):
|
||||
"""Return the exterior ring of the polygon."""
|
||||
return shapely.get_exterior_ring(self)
|
||||
|
||||
@property
|
||||
def interiors(self):
|
||||
"""Return the sequence of interior rings of the polygon."""
|
||||
if self.is_empty:
|
||||
return []
|
||||
return InteriorRingSequence(self)
|
||||
|
||||
@property
|
||||
def coords(self):
|
||||
"""Not implemented for polygons."""
|
||||
raise NotImplementedError(
|
||||
"Component rings have coordinate sequences, but the polygon does not"
|
||||
)
|
||||
|
||||
@property
|
||||
def __geo_interface__(self):
|
||||
"""Return a GeoJSON-like mapping of the Polygon geometry."""
|
||||
if self.exterior == LinearRing():
|
||||
coords = []
|
||||
else:
|
||||
coords = [tuple(self.exterior.coords)]
|
||||
for hole in self.interiors:
|
||||
coords.append(tuple(hole.coords))
|
||||
return {"type": "Polygon", "coordinates": tuple(coords)}
|
||||
|
||||
def svg(self, scale_factor=1.0, fill_color=None, opacity=None):
|
||||
"""Return SVG path element for the Polygon geometry.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
scale_factor : float
|
||||
Multiplication factor for the SVG stroke-width. Default is 1.
|
||||
fill_color : str, optional
|
||||
Hex string for fill color. Default is to use "#66cc99" if
|
||||
geometry is valid, and "#ff3333" if invalid.
|
||||
opacity : float
|
||||
Float number between 0 and 1 for color opacity. Default value is 0.6
|
||||
|
||||
"""
|
||||
if self.is_empty:
|
||||
return "<g />"
|
||||
if fill_color is None:
|
||||
fill_color = "#66cc99" if self.is_valid else "#ff3333"
|
||||
if opacity is None:
|
||||
opacity = 0.6
|
||||
exterior_coords = [["{},{}".format(*c) for c in self.exterior.coords]]
|
||||
interior_coords = [
|
||||
["{},{}".format(*c) for c in interior.coords] for interior in self.interiors
|
||||
]
|
||||
path = " ".join(
|
||||
[
|
||||
"M {} L {} z".format(coords[0], " L ".join(coords[1:]))
|
||||
for coords in exterior_coords + interior_coords
|
||||
]
|
||||
)
|
||||
return (
|
||||
f'<path fill-rule="evenodd" fill="{fill_color}" stroke="#555555" '
|
||||
f'stroke-width="{2.0 * scale_factor}" opacity="{opacity}" d="{path}" />'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_bounds(cls, xmin, ymin, xmax, ymax):
|
||||
"""Construct a `Polygon()` from spatial bounds."""
|
||||
return cls([(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)])
|
||||
|
||||
|
||||
shapely.lib.registry[3] = Polygon
|
||||
|
||||
|
||||
def orient(polygon, sign=1.0):
|
||||
"""Return an oriented polygon.
|
||||
|
||||
It is recommended to use :func:`shapely.orient_polygons` instead.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
polygon : shapely.Polygon
|
||||
sign : float, default 1.
|
||||
The sign of the result's signed area.
|
||||
A non-negative sign means that the coordinates of the geometry's exterior
|
||||
rings will be oriented counter-clockwise.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Geometry or array_like
|
||||
|
||||
Refer to :func:`shapely.orient_polygons` for full documentation.
|
||||
|
||||
"""
|
||||
return shapely.orient_polygons(polygon, exterior_cw=sign < 0.0)
|
||||
Reference in New Issue
Block a user