def __init__(self, shell=None, holes=None): """ Parameters ---------- shell : sequence A sequence of (x, y [,z]) numeric coordinate pairs or triples holes : sequence A sequence of objects which satisfy the same requirements as the shell parameters above Example ------- Create a square polygon with no holes >>> coords = ((0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.)) >>> polygon = Polygon(coords) >>> polygon.area 1.0 """ BaseGeometry.__init__(self) if shell is not None: ret = geos_polygon_from_py(shell, holes) if ret is not None: self._geom, self._ndim = ret else: self.empty()
def __init__(self, coordinates=None): """Initialize. Parameters ---------- coordinates : sequence Contains coordinate sequences or objects that provide the numpy array protocol, providing an M x 2 or M x 3 (with z) array. Example ------- >>> geom = MultiLineString( [[[0.0, 0.0], [1.0, 2.0]]] ) >>> geom = MultiLineString( [ array([[0.0, 0.0], [1.0, 2.0]]) ] ) Each result in a collection containing one line string. """ BaseGeometry.__init__(self) if coordinates is None: # allow creation of null lines, to support unpickling pass else: self._geom, self._ndim = geos_multilinestring_from_py(coordinates)
def __init__(self, coordinates=None): """Initialize. Parameters ---------- coordinates : sequence or array This may be an object that satisfies the numpy array protocol, providing an M x 2 or M x 3 (with z) array, or it may be a sequence of x, y (,z) coordinate sequences. Example ------- >>> geom = MultiPoint([[0.0, 0.0], [1.0, 2.0]]) >>> geom = MultiPoint(array([[0.0, 0.0], [1.0, 2.0]])) Each result in a line string from (0.0, 0.0) to (1.0, 2.0). """ BaseGeometry.__init__(self) if coordinates is None: # allow creation of null lines, to support unpickling pass else: self._geom, self._ndim = geos_multipoint_from_py(coordinates)
def assert_shapes_mostly_equal( shape1: BaseGeometry, shape2: BaseGeometry, threshold: float ): __tracebackhide__ = operator.methodcaller("errisinstance", AssertionError) # Check area first, as it's a nicer error message when they're wildly different. assert shape1.area == pytest.approx( shape2.area, abs=threshold ), "Shapes have different areas" s1 = shape1.simplify(tolerance=threshold) s2 = shape2.simplify(tolerance=threshold) assert (s1 - s2).area < threshold, f"{s1} is not mostly equal to {s2}"
def __init__(self, *args): """ Parameters ---------- There are 2 cases: 1) 1 parameter: this must satisfy the numpy array protocol. 2) 2 or more parameters: x, y, z : float Easting, northing, and elevation. """ BaseGeometry.__init__(self) if len(args) > 0: self._set_coords(*args)
def target(x, pattern: BaseGeometry, pos: BaseGeometry): params = _TargetTransformParams(x[0], x[1], x[2], x[3]) pos_trans = _target_affine_transform(pos, params) neg = box(*pos_trans.bounds).difference(pos_trans) # neg = box(*pos.bounds).difference(pos) # neg_trans = _target_affine_transform(neg, params) pos_overlap = pattern.intersection(pos_trans).area neg_overlap = pattern.intersection(neg).area false_pos_overlap = pos_trans.difference(pattern).area # return neg_overlap+false_pos_overlap-pos_overlap return false_pos_overlap - 2.0 * pos_overlap + neg_overlap + 0.1 * abs( x[0]) + 0.1 * abs(x[1])
def polygon_into_geohash(self, geo: BaseGeometry, accuracy: int = 7) -> list: """ 将多边形切割成固定精度的多个geohash块,将其按照位置输出成矩阵 Parameters ---------- geo : shapely.geometry.base.BaseGeometry 目标多边形 accuracy : int, optional Geohash的精度,默认为7 Returns ---------- list 分割出的geohash字符串列表 Examples ---------- >>> g = GeohashOperator() >>> p = Polygon([[116.40233516693117, 39.95442126877703], [116.40233516693117, 39.95744689749303], [116.4070386902313, 39.95744689749303], [116.4070386902313, 39.95442126877703]]) >>> g.polygon_into_geohash(p) [['wx4g2f1', 'wx4g2f4', 'wx4g2f5', 'wx4g2fh', 'wx4g2fj'], ['wx4g2cc', 'wx4g2cf', 'wx4g2cg', 'wx4g2cu', 'wx4g2cv'], ['wx4g2c9', 'wx4g2cd', 'wx4g2ce', 'wx4g2cs', 'wx4g2ct'], ['wx4g2c3', 'wx4g2c6', 'wx4g2c7', 'wx4g2ck', 'wx4g2cm']] See Also ---------- nearby_geohash : 求解周边的geohash块编码 geohash_to_polygon : 将Geohash字符串转成矩形 geohash_lonlac : 求geohash字符串的边界经度/维度 """ boundary = geo.bounds geo_list, line_geohash = [], [] horizontal_geohash = vertical_geohash = geohash.encode(boundary[1], boundary[0], accuracy) while True: vertical_geohash_polygon = self.geohash_to_polygon(vertical_geohash) if geo.contains(vertical_geohash_polygon) or geo.intersects(vertical_geohash_polygon): line_geohash.append(vertical_geohash) vertical_geohash = self.nearby_geohash(str(vertical_geohash), 3) elif self.geohash_lonlac(vertical_geohash, 'w') < boundary[2]: vertical_geohash = self.nearby_geohash(str(vertical_geohash), 3) else: if line_geohash: geo_list.append(line_geohash) line_geohash = [] horizontal_geohash = vertical_geohash = self.nearby_geohash(horizontal_geohash, 1) horizontal_geohash_polygon = self.geohash_to_polygon(horizontal_geohash) if not (geo.contains(horizontal_geohash_polygon) or geo.intersects(horizontal_geohash_polygon) or ( self.geohash_lonlac(horizontal_geohash, 's') < boundary[3])): return geo_list[::-1]
def make_geom(geo_frame, voronoi_frame): #new columns to add voronoi_frame['area'] = None #create full continent of europe euro_geoms = [ geo_frame.loc[index]['geometry'] for index in range(len(geo_frame)) ] all_europe = unary_union(euro_geoms) #test to see if voronoi shapes intersect with the europe shape for index in range(len(voronoi_frame)): current_shape = voronoi_frame.loc[index]['points'] intersect = BaseGeometry.intersection(all_europe.buffer(0), current_shape.buffer(0)) voronoi_frame.loc[index, 'geometry'] = intersect voronoi_frame.loc[index, 'area'] = intersect.area #there is always an error where index 39 should be a part of norway (index 40) nshape = voronoi_frame.loc[40]['geometry'] missing_part = voronoi_frame.loc[39]['geometry'] voronoi_frame.loc[40]['geometry'] = unary_union([nshape, missing_part]) voronoi_frame.loc[39] = None return voronoi_frame
def test_missing_values_empty_warning(): s = GeoSeries([Point(1, 1), None, np.nan, BaseGeometry(), Polygon()]) with pytest.warns(UserWarning): s.isna() with pytest.warns(UserWarning): s.notna()
def flatten_geometry(geometry: BaseGeometry) -> BaseGeometry: """ :param geometry: Shapely geometry object :return: geometry with Z values removed """ geometry_type = type(geometry) # strip 3rd dimension if 'POLYGON Z' in geometry.wkt: polygons = ([polygon for polygon in geometry] if geometry_type is MultiPolygon else [geometry]) for polygon_index, polygon in enumerate(polygons): exterior_2d = LinearRing( [vertex[:2] for vertex in polygon.exterior.coords]) interiors_2d = [ LinearRing([vertex[:2] for vertex in interior.coords]) for interior in polygon.interiors ] polygons[polygon_index] = Polygon(exterior_2d, interiors_2d) geometry = (MultiPolygon(polygons) if geometry_type is MultiPolygon else Polygon(polygons[0])) if not geometry.is_valid: geometry = geometry.buffer(0) return geometry
def decompose(self, geometry: BaseGeometry) -> List[LineString]: geometry = geometry.simplify(self._simplify_distance) if isinstance(geometry, Polygon): return self.decompose_polygon(polygon=geometry) elif isinstance(geometry, MultiPolygon): lines_list: List[List[LineString]] = [ self.decompose_polygon(polygon=sub_polygon) for sub_polygon in list(geometry) ] return list(chain.from_iterable(lines_list)) elif isinstance(geometry, LinearRing): return self.decompose_linearRing(ring=geometry) elif isinstance(geometry, LineString): return self.decompose_lineString(lineString=geometry) elif isinstance(geometry, MultiLineString): lines_list: List[List[LineString]] = [ self.decompose_lineString(lineString=sub_lineString) for sub_lineString in list(geometry) ] return list(chain.from_iterable(lines_list)) elif isinstance(geometry, GeometryCollection): lines_list: List[List[LineString]] = [ self.decompose(geometry=sub_geometry) for sub_geometry in list(geometry) ] return list(chain.from_iterable(lines_list)) else: return []
def find_shape_in_index(shape: BaseGeometry, index): # (minx, miny, maxx, maxy) bounds = shape.bounds lon = [] lat = [] weights = [] for result in index.intersection(bounds, objects="raw"): point = result['point'] rect = result['bbox'] poly = Polygon([(r[0], r[1]) for r in rect]) inters = shape.intersection(poly) # Intersection with bounds might not intersect with detailed poly if inters: weights.append(inters.area) lon.append(point[0]) lat.append(point[1]) lon = np.array(lon) lat = np.array(lat) weights = np.array(weights) weights = weights / np.sum(weights) return GridLookupResults(lon, lat, weights)
def stretch_contour(geom: BaseGeometry, width: float = 1) -> BaseGeometry: """ Stretch geometry (expected to be a geometry contour) to given width scale. """ if width > 1 and geom: buf = 1 + (width - 1) / 10 return geom.buffer(buf) return geom
def fillna(self, value=None): """ Fill NA/NaN values with a geometry (empty polygon by default) """ if value is None: value = BaseGeometry() return GeoSeries(self._geometry_array.fillna(value), index=self.index, crs=self.crs, name=self.name)
def test_align_mixed(self): a1 = self.a1 s2 = pd.Series([1, 2], index=['B', 'C']) res1, res2 = a1.align(s2) exp2 = pd.Series([BaseGeometry(), 1, 2], dtype=object, index=['A', 'B', 'C']) assert_series_equal(res2, exp2)
def to_bytes(cls, geom: BaseGeometry) -> List[int]: geom_name = str(geom.__class__.__name__).lower() try: appr_parser = PARSERS[geom_name] geom.__UDT__ = GeometryType() except KeyError: raise KeyError(f"Parser for geometry {geom_name} is not available") return appr_parser.serialize(geom, BinaryBuffer())
def align(self, other, join='outer', level=None, copy=True, fill_value=None, **kwargs): if fill_value is None: fill_value = BaseGeometry() left, right = super(GeoSeries, self).align(other, join=join, level=level, copy=copy, fill_value=fill_value, **kwargs) return left, right
def __get_tmp_res(self, res: set, intersect_geohash: str, test_poly: BaseGeometry, tmp_precision: int, stop_precision: int, intersect: bool): geohash_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] tmp_precision += 1 for add_on in geohash_list: tmp_poly = self.geohash_to_polygon(intersect_geohash + add_on) if test_poly.contains(tmp_poly): res.add(intersect_geohash + add_on) elif test_poly.intersects(tmp_poly): if tmp_precision == stop_precision: if intersect is True: res.add(intersect_geohash + add_on) else: res = res.union( self.__get_tmp_res(res, intersect_geohash + add_on, test_poly, tmp_precision, stop_precision, intersect) ) return res
def __init__(self, shell=None, holes=None): """Initialize. Parameters ---------- exterior : sequence or array This may be an object that satisfies the numpy array protocol, providing an M x 2 or M x 3 (with z) array, or it may be a sequence of x, y (,z) coordinate sequences. Example ------- >>> coords = ((0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.)) >>> polygon = Polygon(coords) """ BaseGeometry.__init__(self) if shell is not None: self._geom, self._ndim = geos_polygon_from_py(shell, holes)
def unary_union(self): attr = "unary_union" meta = BaseGeometry() return self.reduction( lambda x: getattr(x, attr), token=f"{self._name}-{attr}", aggregate=lambda x: getattr(geopandas.GeoSeries(x), attr), meta=meta, )
def convex_hull(self): """Convex hull of union of all objects in the field.""" field = BaseGeometry() if self.obstacles: field |= self.obstacles if self.targets: field |= union(*self.targets) if self.spawns: field |= union(*self.spawns) return field.convex_hull
def fillna(self, value=None, method=None, inplace=False, **kwargs): """Fill NA/NaN values with a geometry (empty polygon by default). "method" is currently not implemented for pandas <= 0.12. """ if value is None: value = BaseGeometry() return super(GeoSeries, self).fillna(value=value, method=method, inplace=inplace, **kwargs)
def __init__(self, coordinates=None): """ Parameters ---------- coordinates : sequence A sequence of (x, y [,z]) numeric coordinate pairs or triples or an object that provides the numpy array interface, including another instance of LineString. Example ------- Create a line with two segments >>> a = LineString([[0, 0], [1, 0], [1, 1]]) >>> a.length 2.0 """ BaseGeometry.__init__(self) if coordinates is not None: self._set_coords(coordinates)
def __init__(self, *args): """ Parameters ---------- There are 2 cases: 1) 1 parameter: this must satisfy the numpy array protocol. 2) 2 or more parameters: x, y, z : float Easting, northing, and elevation. """ BaseGeometry.__init__(self) if len(args) > 0: if len(args) == 1: self._geom, self._ndim = geos_point_from_py(args[0]) elif len(args) > 3: raise TypeError( "Point() takes at most 3 arguments ({} given)".format( len(args))) else: self._geom, self._ndim = geos_point_from_py(tuple(args))
def test_read_carto_basegeometry_as_null_geom_value(mocker): # Given cm_mock = mocker.patch.object(ContextManager, 'copy_to') cm_mock.return_value = GeoDataFrame({ 'cartodb_id': [1], 'the_geom': [None] }) # When gdf = read_carto('__source__', CREDENTIALS, null_geom_value=BaseGeometry()) # Then expected = GeoDataFrame({ 'cartodb_id': [1], 'the_geom': [BaseGeometry()] }, geometry='the_geom') cm_mock.assert_called_once_with('__source__', None, None, 3) assert expected.equals(gdf) assert gdf.crs == 'epsg:4326'
def align(self, other, join='outer', level=None, copy=True, fill_value=None, **kwargs): if fill_value is None: fill_value = BaseGeometry() left, right = super(GeoSeries, self).align(other, join=join, level=level, copy=copy, fill_value=fill_value, **kwargs) if isinstance(other, GeoSeries): return GeoSeries(left), GeoSeries(right) else: # It is probably a Series, let's keep it that way return GeoSeries(left), right
def __init__(self, coordinates=None): """Initialize. Parameters ---------- coordinates : sequence or array This may be an object that satisfies the numpy array protocol, providing an M x 2 or M x 3 (with z) array, or it may be a sequence of x, y (,z) coordinate sequences. Rings are implicitly closed. There is no need to specific a final coordinate pair identical to the first. Example ------- >>> ring = LinearRing( ((0.,0.), (0.,1.), (1.,1.), (1.,0.)) ) Produces a 1x1 square. """ BaseGeometry.__init__(self) self._init_geom(coordinates)
def __init__(self, coordinates=None): """Initialize. Parameters ---------- coordinates : sequence or array This may be an object that satisfies the numpy array protocol, providing an M x 2 or M x 3 (with z) array, or it may be a sequence of x, y (,z) coordinate sequences. Example ------- >>> line = LineString([[0.0, 0.0], [1.0, 2.0]]) >>> line = LineString(array([[0.0, 0.0], [1.0, 2.0]])) Each result in a line string from (0.0, 0.0) to (1.0, 2.0). """ BaseGeometry.__init__(self) self._init_geom(coordinates)
def is_similar(geom1: BaseGeometry, geom2: BaseGeometry, eps: float = 1e-6) -> bool: if type(geom1) is not type(geom2): return False if isinstance(geom1, (LineString, MultiLineString, Point, MultiPoint)): return (geom1.buffer(eps).contains(geom2) and geom2.buffer(eps).contains(geom1)) if isinstance(geom1, (Polygon, MultiPolygon)): return geom1.symmetric_difference(geom2).area < eps if isinstance(geom1, GeometryCollection): polygons1, non_polygons1 = separate(geom1, lambda geom: isinstance(geom, Polygon)) polygons2, non_polygons2 = separate(geom2, lambda geom: isinstance(geom, Polygon)) polygon_union1 = unary_union(polygons1) non_polygon_union1 = unary_union(non_polygons1) polygon_union2 = unary_union(polygons2) non_polygon_union2 = unary_union(non_polygons2) return (polygon_union1.symmetric_difference(polygon_union2).area < eps and non_polygon_union1.buffer(eps).contains(non_polygon_union2) and non_polygon_union2.buffer(eps).contains(non_polygon_union1))
def create_jvm_geometry_from_base_geometry(cls, jvm, geom: BaseGeometry): """ :param jvm: :param geom: :return: """ if isinstance(geom, Envelope): jvm_geom = geom.create_jvm_instance(jvm) else: decoded_geom = GeometryFactory.to_bytes(geom) jvm_geom = jvm.GeometryAdapter.deserializeToGeometry(decoded_geom) return jvm_geom
def create_jvm_geometry_from_base_geometry(cls, jvm, geom: BaseGeometry): """ :param jvm: :param geom: :return: """ if isinstance(geom, Envelope): jvm_geom = geom.create_jvm_instance(jvm) else: decoded_geom = GeometryFactory.to_bytes(geom) jvm_geom = JvmGeometryAdapter(jvm).translate_to_java(decoded_geom) return jvm_geom
def __init__(self, coordinates=None): """ Parameters ---------- coordinates : sequence A sequence of (x, y [,z]) numeric coordinate pairs or triples Rings are implicitly closed. There is no need to specific a final coordinate pair identical to the first. Example ------- Construct a square ring. >>> ring = LinearRing( ((0, 0), (0, 1), (1 ,1 ), (1 , 0)) ) >>> ring.is_closed True >>> ring.length 4.0 """ BaseGeometry.__init__(self) if coordinates is not None: self._set_coords(coordinates)
def __init__(self, shell=None, holes=None): """ Parameters ---------- shell : sequence A sequence of (x, y [,z]) numeric coordinate pairs or triples holes : sequence A sequence of objects which satisfy the same requirements as the shell parameters above Example ------- Create a square polygon with no holes >>> coords = ((0., 0.), (0., 1.), (1., 1.), (1., 0.), (0., 0.)) >>> polygon = Polygon(coords) >>> polygon.area 1.0 """ BaseGeometry.__init__(self) if shell is not None: self._geom, self._ndim = geos_polygon_from_py(shell, holes)
def subtract_turbine_exclusion_zone(min_spacing: float, source_shape: BaseGeometry, turbine_positions: [Point], ) -> BaseGeometry: """ Subtract the min spacing around each turbine from a site polygon :param min_spacing: minimum distance around turbine :param source_shape: site polygon :param turbine_positions: Points of the turbines within the source_shape :return: modified shape with the circles around the turbines removed """ if len(turbine_positions) <= 0: return source_shape return source_shape.difference( unary_union([turbine.buffer(min_spacing) for turbine in turbine_positions]))
def make_geoms(vframe, geo_frame): vframe['geometry'] = None poly = geo_frame.unary_union for index in range(135): try: loop_geom = BaseGeometry.intersection( vframe.loc[index]['points'].buffer(0), poly.buffer(0)) vframe.loc[index, 'geometry'] = loop_geom except: True #set projection as mercator for the new data frame vframe.crs = {'init': 'epsg = 3395'} return vframe
def interpolate(geometry: BaseGeometry, gap: float, simplify_distance: float = 1e-6) -> BaseGeometry: def interpolate_coords(coords): new_coords: List[Tuple[float, float]] = [] for i in range(len(coords) - 2): new_coords.extend( interpolate_coords_by_len(coords[i], coords[i + 1], gap, result_include_coord2=False)) new_coords.extend( interpolate_coords_by_len(coords[-2], coords[-1], gap, result_include_coord2=True)) return new_coords if isinstance(geometry, (Point, MultiPoint)): return geometry elif isinstance(geometry, (Polygon, LineString, LinearRing)): geometry_simplified = geometry.simplify(simplify_distance) if isinstance(geometry, Polygon): exterior_coords = list(geometry_simplified.exterior.coords) interior_coords_list = [ list(interior.coords) for interior in geometry_simplified.interiors ] interpolated_exterior = interpolate_coords(exterior_coords) interpolated_interiors = [ interpolate_coords(interior_coords) for interior_coords in interior_coords_list ] return Polygon(shell=interpolated_exterior, holes=interpolated_interiors) else: # LineString or LinearRing coords = list(geometry_simplified.coords) return type(geometry)(interpolate_coords(coords)) elif isinstance(geometry, (MultiPolygon, MultiLineString, GeometryCollection)): geoms = list(geometry) interpolated_geoms = [interpolate(geom, gap) for geom in geoms] return type(geometry)(interpolated_geoms) return geometry # return origin geometry if not match any type
def test_none_geom(self): p = BaseGeometry() p._geom = None self.assertTrue(p.is_empty)
def test_none_geom(self): p = BaseGeometry() p._geom = None self.failUnless(p.is_empty, True)