"""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
Memory