def _interp_polygon(polygon, dx): """Interpolates an irregular polygon to a regular step dx. Interior geometries are also interpolated if they are longer then 3*dx, otherwise they are ignored. Parameters ---------- polygon: The shapely.geometry.Polygon instance to interpolate dx : the step (float) Returns ------- an interpolated shapely.geometry.Polygon class instance. """ # remove last (duplex) point to build a LineString from the LinearRing line = shpg.LineString(np.asarray(polygon.exterior.xy).T) e_line = [] for distance in np.arange(0.0, line.length, dx): e_line.append(*line.interpolate(distance).coords) e_line = shpg.LinearRing(e_line) i_lines = [] for ipoly in polygon.interiors: line = shpg.LineString(np.asarray(ipoly.xy).T) if line.length < 3 * dx: continue i_points = [] for distance in np.arange(0.0, line.length, dx): i_points.append(*line.interpolate(distance).coords) i_lines.append(shpg.LinearRing(i_points)) return shpg.Polygon(e_line, i_lines)
def test_stitch(self): # The following LinearRing wanders in/out of the map domain # but importantly the "vertical" lines at 0'E and 360'E are both # chopped by the map boundary. This results in their ends being # *very* close to each other and confusion over which occurs # first when navigating around the boundary. # Check that these ends are stitched together to avoid the # boundary ordering ambiguity. # NB. This kind of polygon often occurs with MPL's contouring. coords = [(0.0, -70.70499926182919), (0.0, -71.25), (0.0, -72.5), (0.0, -73.49076371657017), (360.0, -73.49076371657017), (360.0, -72.5), (360.0, -71.25), (360.0, -70.70499926182919), (350, -73), (10, -73)] src_proj = ccrs.PlateCarree() target_proj = ccrs.Stereographic(80) linear_ring = sgeom.LinearRing(coords) rings, mlinestr = target_proj.project_geometry(linear_ring, src_proj) assert len(mlinestr) == 1 assert len(rings) == 0 # Check the stitch works in either direction. linear_ring = sgeom.LinearRing(coords[::-1]) rings, mlinestr = target_proj.project_geometry(linear_ring, src_proj) assert len(mlinestr) == 1 assert len(rings) == 0
def _InsureSinglePolygonCorrectWinding(coords): """Modifies in place the coords for correct windings.""" exterior = coords[0] if not sgeo.LinearRing(exterior).is_ccw: exterior.reverse() for hole in coords[1:]: if sgeo.LinearRing(hole).is_ccw: hole.reverse()
def _HasSinglePolygonCorrectWinding(coords): exterior = coords[0] if not sgeo.LinearRing(exterior).is_ccw: return False for hole in coords[1:]: if sgeo.LinearRing(hole).is_ccw: return False return True
def setUp(self): self.tslr1 = mg.TS_LinearRing( sg.LinearRing([(1, 1), (2, 1), (2, 2), (1, 2), (1, 1)]), dt.datetime(2017, 07, 25, 20, 0, 0)) self.tslr2 = mg.TS_LinearRing( sg.LinearRing([(3, 1), (4, 1), (4, 2), (3, 2), (3, 1)]), dt.datetime(2017, 07, 25, 20, 0, 10)) self.t1 = dt.datetime(2017, 07, 25, 20, 0, 5)
def test_create_diff_dict(self): lr = sg.LinearRing([(1.5, 1.5), (2, 1), (2, 2), (1, 2), (1, 1), (1.5, 1.5)]) lr_convex = sg.LinearRing(lr.convex_hull.exterior.coords[::-1]) lr_seg = I_Helper.curve_segments(lr) lr_convex_seg = I_Helper.curve_segments(lr_convex) d_dict = I_Helper.create_diff_dict(lr_convex_seg, lr_seg) self.assertEqual(d_dict, {0: [(1.0, 1.0), (1.5, 1.5), (2.0, 1.0)]})
def _calculate_geometry(self, exterior): inside_direction = _get_inside_direction(exterior) interior = exterior.parallel_offset(self.thickness, side=inside_direction) if interior.type == 'MultiLineString': interior = shpl_geom.LinearRing(interior.geoms[0]) else: interior = shpl_geom.LinearRing(interior) geometry = shpl_geom.Polygon(exterior) - shpl_geom.Polygon(interior) return interior, geometry
def _calculate_geometry(self, exterior): limited_box = shpl_geom.box(self._limits[0], exterior.bounds[1] * 1.1, self._limits[1], exterior.bounds[3] * 1.1) intersection = limited_box.intersection(exterior) side = _get_inside_direction(exterior) tmp_geometries = [] tmp_interior = shpl_geom.Polygon(exterior) for ageo in intersection.geoms: tmp_geometry = _create_offset_box(ageo, self.thickness, side, symmetric=False) tmp_interior -= tmp_geometry tmp_geometries.append(tmp_geometry) geometry = shpl_geom.GeometryCollection(tmp_geometries) interior = shpl_geom.LinearRing(tmp_interior.exterior) return _refine_interior(interior), geometry
def snap_geom(self, gdf, geom1, geom2, index1, index2, tolerance): if isinstance(geom1, geom.Polygon) and isinstance(geom2, geom.Polygon): vertices1 = geom1.exterior.coords[:] vertices2 = geom2.exterior.coords[:] for i in range(0, len(vertices1)): vertex1 = vertices1[i] closest_vertex, vertex_index = self.get_closest_vertex(vertex1, vertices2, tolerance) if i not in self.snapped_vertices[str(index1)] and closest_vertex != None: self.snapped_vertices[str(index1)].append(i) # if code_entite in ['NRO_08_003_044', 'NRO_08_003_157']: # print "vertex ", vertex1, " at index ", i, " with closest vertex ", closest_vertex vertices1[i] = closest_vertex elif geom.Point(vertex1).distance(geom2) <= tolerance: self.snapped_vertices[str(index1)].append(i) linear_ring = geom.LinearRing(geom2.exterior.coords) geom2, vertex_added_at = self.insert_vertex_at(geom2, vertex1, nearest_points(geom.Point(vertex1), linear_ring)[1].coords[0]) # if vertex_added_at > vertex_index +1: # print "different indices : get_closest_vertex index = ", vertex_index, " / insert_at index = ", vertex_added_at # elif vertex_added_at == vertex_index + 1: # print "same indices = ", vertex_added_at # else: # print "WTF case !" gdf.loc[index2, 'geometry'] = geom2 self.snapped_vertices[str(index1)].append(vertex_added_at) return geom.Polygon(vertices1)
def _get_patterns(node): from .elements import EmbroideryElement from .elements.stroke import Stroke fills = [] strokes = [] xpath = "./parent::svg:g/*[contains(@style, 'marker-start:url(#inkstitch-pattern-marker)')]" patterns = node.xpath(xpath, namespaces=inkex.NSS) for pattern in patterns: if pattern.tag not in EMBROIDERABLE_TAGS: continue element = EmbroideryElement(pattern) fill = element.get_style('fill') stroke = element.get_style('stroke') if fill is not None: fill_pattern = Stroke(pattern).paths linear_rings = [shgeo.LinearRing(path) for path in fill_pattern] for ring in linear_rings: fills.append(shgeo.Polygon(ring)) if stroke is not None: stroke_pattern = Stroke(pattern).paths line_strings = [shgeo.LineString(path) for path in stroke_pattern] strokes.append(shgeo.MultiLineString(line_strings)) return {'fill_patterns': fills, 'stroke_patterns': strokes}
def joined_outer_ring(self): outer_ring = [] #2d array of geoms # TODO: Prune overlapping points when appending a ring section # or: add shapely for combining geometries for w in self.outer_ways(): inserted = False new_segment = w.way.linestring if len(new_segment) == 0: continue for index in range(len(outer_ring)): linestring = outer_ring[index] if linestring[-1] == new_segment[0]: outer_ring.insert(index + 1, new_segment) inserted = True elif new_segment[-1] == linestring[0]: outer_ring.insert(index, new_segment) inserted = True if not inserted: outer_ring.append(new_segment) merged = linemerge( [shapely.LineString(segment) for segment in outer_ring]) if merged.is_closed and merged.is_valid: return shapely.LinearRing(merged) else: # IPython.embed() # could be multipolygon with 2 non-touching outer rings # TODO: Split those print('found rel with multiple closed outer rings: %d' % self.id) return None
def _create_geometry(default_range, num_points): if random.choice((True, False)): if not explore_queue.empty(): try: return explore_queue.get(block=False) except: pass start_point = geometry.Point(random.uniform(-180, 180), random.uniform(-90, 90)) tries = 1 while geometry_collection.intersects(start_point): tries += 1 start_point = geometry.Point(random.uniform(-180, 180), random.uniform(-90, 90)) logger.debug('took %s tries to generate geo', tries) points = [start_point] for i in range(num_points - 1): new_x = start_point.x + random.uniform(*default_range) if new_x > 180: new_x = new_x % 180 + (-180) new_y = start_point.y + random.uniform(*default_range) if new_y > 90: new_y = new_y % 90 + (-90) points.append(geometry.Point(new_x, new_y)) return geometry.Polygon( geometry.LinearRing( tuple(map(lambda x: (x.x, x.y), (*points, points[0])))))
def get_external_contour(points, resolution=None): """ takes a list of `points` defining a linear ring, which can be self-intersecting, and returns an approximation to the external contour """ if resolution is None: # determine resolution from minimal distance of consecutive points dist_min = np.inf for p1, p2 in itertools.izip(np.roll(points, 1, axis=0), points): dist = curves.point_distance(p1, p2) if dist > 0: dist_min = min(dist_min, dist) resolution = 0.5 * dist_min # limit the resolution such that there are at most 2048 points dim_max = np.max(np.ptp(points, axis=0)) #< longest dimension resolution = max(resolution, dim_max / 2048) # build a linear ring with integer coordinates ps_int = np.array(np.asarray(points) / resolution, np.int) ring = geometry.LinearRing(ps_int) # get the image of the linear ring by plotting it into a mask x_min, y_min, x_max, y_max = ring.bounds shape = ((y_max - y_min) + 3, (x_max - x_min) + 3) x_off, y_off = int(x_min - 1), int(y_min - 1) mask = np.zeros(shape, np.uint8) cv2.fillPoly(mask, [ps_int], 255, offset=(-x_off, -y_off)) # find the contour of this mask to recover the exterior contour contours = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE, offset=(x_off, y_off))[1] return np.array(np.squeeze(contours)) * resolution
def _write_boat_area(pier, stg_manager, coords_transform: co.Transformation): if len(pier.nodes) < 3: return # Guess a possible position for realistic boat placement linear_ring = shg.LinearRing(pier.nodes) centroid = linear_ring.centroid # Simplify ring = linear_ring.convex_hull.buffer( 40, cap_style=CAP_STYLE.square, join_style=JOIN_STYLE.bevel).simplify(20) for p in ring.exterior.coords: line_coords = [[centroid.x, centroid.y], p] target_vector = shg.LineString(line_coords) coords = linear_ring.coords for i in range(len(coords) - 1): segment = LineString(coords[i:i + 2]) if segment.length > 20 and segment.intersects(target_vector): direction = math.degrees( math.atan2(segment.coords[0][0] - segment.coords[1][0], segment.coords[0][1] - segment.coords[1][1])) parallel = segment.parallel_offset(10, 'right') boat_position = parallel.interpolate(segment.length / 2) try: pos_global = coords_transform.to_global( (boat_position.x, boat_position.y)) _write_model(segment.length, stg_manager, pos_global, direction, pier.elevation) except AttributeError as reason: logging.error(reason)
def test_cuts(self): # Check that fragments do not start or end with one of the # original ... ? linear_ring = sgeom.LinearRing([(-10, 30), (10, 60), (10, 50)]) projection = ccrs.Robinson(170.5) rings, multi_line_string = projection.project_geometry(linear_ring) # The original ring should have been split into multiple pieces. assert len(multi_line_string) > 1 assert not rings def assert_intersection_with_boundary(segment_coords): # Double the length of the segment. start = segment_coords[0] end = segment_coords[1] end = [end[i] + 2 * (end[i] - start[i]) for i in (0, 1)] extended_segment = sgeom.LineString([start, end]) # And see if it crosses the boundary. intersection = extended_segment.intersection(projection.boundary) assert not intersection.is_empty, 'Bad topology near boundary' # Each line resulting from the split should start and end with a # segment that crosses the boundary when extended to double length. # (This is important when considering polygon rings which need to be # attached to the boundary.) for line_string in multi_line_string: coords = list(line_string.coords) assert len(coords) >= 2 assert_intersection_with_boundary(coords[1::-1]) assert_intersection_with_boundary(coords[-2:])
def test_at_boundary(self): # Check that a polygon is split and recombined correctly # as a result of being on the boundary, determined by tolerance. exterior = np.array( [[177.5, -79.912], [178.333, -79.946], [181.666, -83.494], [180.833, -83.570], [180., -83.620], [178.438, -83.333], [178.333, -83.312], [177.956, -83.888], [180., -84.086], [180.833, -84.318], [183., -86.], [183., -78.], [177.5, -79.912]]) tring = sgeom.LinearRing(exterior) tcrs = ccrs.PlateCarree() scrs = ccrs.PlateCarree() rings, mlinestr = tcrs._project_linear_ring(tring, scrs) # Number of linearstrings assert len(mlinestr) == 4 assert not rings # Test area of smallest Polygon that contains all the points in the # geometry. assert round(abs(mlinestr.convex_hull.area - 2347.75623076), 7) == 0
def test_out_of_bounds(self): # Check that a ring that is completely out of the map boundary # produces an empty result. # XXX Check efficiency? projection = ccrs.TransverseMercator(central_longitude=0, approx=True) rings = [ # All valid ([(86, 1), (86, -1), (88, -1), (88, 1)], -1), # One NaN ([(86, 1), (86, -1), (130, -1), (88, 1)], 1), # A NaN segment ([(86, 1), (86, -1), (130, -1), (130, 1)], 1), # All NaN ([(120, 1), (120, -1), (130, -1), (130, 1)], 0), ] # Try all four combinations of valid/NaN vs valid/NaN. for coords, expected_n_lines in rings: linear_ring = sgeom.LinearRing(coords) rings, mlinestr = projection.project_geometry(linear_ring) if expected_n_lines == -1: assert rings assert not mlinestr else: assert len(mlinestr) == expected_n_lines if expected_n_lines == 0: assert mlinestr.is_empty
def test_basic_linear(self): ts_lr1 = mg.TS_LinearRing( sg.LinearRing([(1, 0.5), (2.25, 0.75), (1.5, 1.25), (1.75, 1.75), (1.25, 2.25), (0.5, 1.75), (0.5, 1.0), (1, 0.5)]), dt.datetime(2017, 07, 25, 20, 0, 0)) ts_lr2 = mg.TS_LinearRing( sg.LinearRing([(3.0, 0.5), (4.5, 0.5), (3.75, 2.25), (3.0, 0.5)]), dt.datetime(2017, 07, 25, 20, 0, 20)) ts_lr3 = mg.TS_LinearRing( sg.LinearRing([(1, 1), (1.25, 1.75), (1.5, 1.75), (1.5, 1.25), (2, 1), (2, 2), (1.75, 1.75), (1, 2), (1, 1)]), dt.datetime(2017, 07, 25, 20, 0, 0)) ts_lr4 = mg.TS_LinearRing( sg.LinearRing([(4.5, 1.5), (4, 2), (3.5, 1.5), (3.5, 0.5), (3.75, 1.25), (4, 1.25), (4, 1), (4.5, 1), (4.25, 1.25), (4.5, 1.5)]), dt.datetime(2017, 07, 25, 20, 0, 20)) self.assertEqual( IRing.basic_linear(ts_lr1, ts_lr2, dt.datetime(2017, 07, 25, 20, 0, 10)).value.coords[:], [(3.375, 0.625), (2.8440513845721638, 1.2388801026649512), (2.872336158951433, 1.7145489624466568), (2.5, 2.25), (1.9816795819387427, 1.6655856911903992), (1.8624297859062504, 1.0123361671145843), (2.0, 0.5), (3.375, 0.625)]) self.assertEqual( IRing.basic_linear(ts_lr3, ts_lr4, dt.datetime(2017, 07, 25, 20, 0, 10)).value.coords[:], [(3.25, 1.0), (3.125, 1.625), (3.125, 1.625), (2.5, 2.0), (2.25, 1.5428932188134525), (2.25, 0.75), (2.5, 1.5), (2.75, 1.5), (2.75, 1.125), (3.25, 1.0)]) self.assertEqual( IRing.basic_linear(ts_lr1, ts_lr2, dt.datetime(2017, 07, 25, 20, 0, 10), "distance").value.coords[:], [(3.375, 0.625), (2.8440513845721638, 1.2388801026649512), (2.872336158951433, 1.7145489624466568), (2.5, 2.25), (1.9816795819387427, 1.6655856911903992), (1.8624297859062504, 1.0123361671145843), (2.0, 0.5), (3.375, 0.625)])
def build_shapely_geometry(self) -> BaseGeometry: """ Builds the internal shapely representation of the geometry. This is used by other base class methods to build the other output types. :return: A shapely geometry specific to the derived type. :rtype: :py:class:`BaseGeometry` """ # Get the UTMSRID so we can transform the center point to a coordinate system where distance is # measured in meters. utmsrid: int = getutmsrid(self.longitude, self.latitude, self.sr_id) # Create the OGR Point center: ogr.Geometry = ogr.Geometry(ogr.wkbPoint) center.AssignSpatialReference(Geodetic2D.get_ogr_sr(self.sr_id)) center.AddPoint(self.longitude, self.latitude) # Project the point from its native projection to the UTM system. center = reproject_geom(center, self.sr_id, utmsrid) # adjust for the fact that we're not doing standard geometry - back up 90 degress # to start from north. start_angle: float = 90 - self.start_angle # find the end angle, which is the sweep relative to the start angle going clockwise so we subtract. end_angle: float = start_angle - self.opening_angle # plot a line for the outer arc. outer_arc_x, outer_arc_y = \ calculate_arc(center.GetX(), center.GetY(), self.outer_radius, start_angle, end_angle) # plot a line for the inner arc. inner_arc_x, inner_arc_y = \ calculate_arc(center.GetX(), center.GetY(), self.inner_radius, start_angle, end_angle) # reverse the inner arc to set is up to be welded to the outer arc into a polygon. inner_arc_x = np.flip(inner_arc_x, 0) inner_arc_y = np.flip(inner_arc_y, 0) # glue the arcs together band_x = np.append(outer_arc_x, inner_arc_x) band_y = np.append(outer_arc_y, inner_arc_y) # complete the ring by adding taking the first point and adding it again at the end. first_x = band_x[0] first_y = band_y[0] band_x = np.append(band_x, first_x) band_y = np.append(band_y, first_y) # smash the x and y arrays together to get coordinate pairs. ring_coordinates = np.column_stack([band_x, band_y]) # Build the shapely linear ring . . . line_string: shp_geom.LinearRing = shp_geom.LinearRing(ring_coordinates) # so we can build a shapely polygon . . . arc_band_polygon: shp_geom.Polygon = shp_geom.Polygon(line_string) # so we can create the OGR geometry . . . arcband: ogr.Geometry = ogr.CreateGeometryFromWkb(arc_band_polygon.wkb) # so we can reproject back to the original coordinate system arcband = reproject_geom(arcband, utmsrid, self._spatial_ref_id) # so we can build and return a shapely geometry. (Whew!) return loads(arcband.ExportToWkt())
def test_curve_segments(self): lr = sg.LinearRing([(1, 1), (2, 1), (2, 2), (1, 2), (1, 1)]) lr_seg = I_Helper.curve_segments(lr) self.assertEqual(lr_seg, [[(1.0, 1.0), (2.0, 1.0)], [(2.0, 1.0), (2.0, 2.0)], [(2.0, 2.0), (1.0, 2.0)], [(1.0, 2.0), (1.0, 1.0)]])
def test_degenerate_shapes(self): # Test all degenerate shapes (points, lines) have area zero points = sgeo.MultiPoint([(4, 59), (6, 59), (6, 61), (4, 61)]) line = sgeo.LineString([(4, 59), (6, 59), (6, 61), (4, 61)]) ring = sgeo.LinearRing([(4, 59), (6, 59), (6, 61), (4, 61)]) self.assertEqual(utils.GeometryArea(points), 0) self.assertEqual(utils.GeometryArea(line), 0) self.assertEqual(utils.GeometryArea(ring), 0)
def _create_dummy_shp(fname): if not os.path.exists(testdir): os.makedirs(testdir) e_line = shpg.LinearRing([(1.5, 1), (2., 1.5), (1.5, 2.), (1, 1.5)]) i_line = shpg.LinearRing([(1.4, 1.4), (1.6, 1.4), (1.6, 1.6), (1.4, 1.6)]) p1 = shpg.Polygon(e_line, [i_line]) p2 = shpg.Polygon([(2.5, 1.3), (3., 1.8), (2.5, 2.3), (2, 1.8)]) p3 = shpg.Point(0.5, 0.5) p4 = shpg.Point(1, 1) df = gpd.GeoDataFrame() df['name'] = ['Polygon', 'Line'] df['geometry'] = gpd.GeoSeries([p1, p2]) of = os.path.join(testdir, fname) df.crs = 'epsg:4326' df.to_file(of) return of
def shift_polygons(self, shift=(0, 0)): """ Returns the polygons shifted by the given values. Parameters ---------- shift : list or tuple The [X, Y] shift to be added to the coordinates. Returns ------- polygons : List of polygons Polygons shifted by the given values """ polygons = [] if type(self.shape) is geometry.multipolygon.MultiPolygon: for geom in self.shape.geoms: ext_coords = np.array(geom.exterior) ext_coords += shift if len(geom.interiors) > 0: int_rings = [] for i in geom.interiors: int_coords = np.array(i) int_coords += shift int_rings.append(geometry.LinearRing(int_coords)) poly = geometry.Polygon(ext_coords, int_rings) else: poly = geometry.Polygon(ext_coords) polygons.append(poly) elif type(self.shape) is geometry.polygon.Polygon: ext_coords = np.array(self.shape.exterior) ext_coords += shift if len(self.shape.interiors) > 0: int_rings = [] for i in self.shape.interiors: int_coords = np.array(i) int_coords += shift int_rings.append(geometry.LinearRing(int_coords)) poly = geometry.Polygon(ext_coords, int_rings) else: poly = geometry.Polygon(ext_coords) polygons.append(poly) else: raise TypeError('Shape not the correct type.') return polygons
def get_shape(self): ls = geom.LinearRing(( (self.a[0], self.a[1]), (self.a[0], self.b[1]), (self.b[0], self.b[1]), (self.b[0], self.a[1]), )) return ls
def create_dummy_shp(fname): import shapely.geometry as shpg import geopandas as gpd e_line = shpg.LinearRing([(1.5, 1), (2., 1.5), (1.5, 2.), (1, 1.5)]) i_line = shpg.LinearRing([(1.4, 1.4), (1.6, 1.4), (1.6, 1.6), (1.4, 1.6)]) p1 = shpg.Polygon(e_line, [i_line]) p2 = shpg.Polygon([(2.5, 1.3), (3., 1.8), (2.5, 2.3), (2, 1.8)]) p3 = shpg.Point(0.5, 0.5) p4 = shpg.Point(1, 1) df = gpd.GeoDataFrame() df['name'] = ['Polygon', 'Line'] df['geometry'] = gpd.GeoSeries([p1, p2]) of = os.path.join(testdir, fname) df.to_file(of) return of
def regularize_linear_ring(linear_ring): """ regularize a list of points defining a contour """ polygon = geometry.Polygon(linear_ring) regular_polygon = regularize_polygon(polygon) if regular_polygon.is_empty: return geometry.LinearRing() #< empty linear ring else: return regular_polygon.exterior
def generate_target_polygon(min_area=10, max_edge=6, max_size=50): edges = random.randint(3, max_edge) size = max_size # edges = 3 logger.info("Generating polygon with {} edges".format(edges)) while True: tuple_list = array_to_tuples( np.reshape([random.uniform(-size, size) for x in range(6)], (3, 2)).astype(np.float32)) shots = 0 while len(tuple_list) < edges: shots += 1 if shots > 100: tuple_list = array_to_tuples( np.reshape([random.uniform(-size, size) for x in range(6)], (3, 2)).astype(np.float32)) shots = 0 tuple_list_buffer = tuple_list.copy() tuple_list_buffer.insert( random.randint(0, len(tuple_list)), (random.uniform(-size, size), random.uniform(-size, size))) linear_ring = geometry.LinearRing(tuple(tuple_list_buffer)) if linear_ring.is_simple: pointy = 90 for s_ in range(len(tuple_list_buffer)): arr = tuples_to_array(tuple_list_buffer) logger.debug("{}; {}".format(arr[s_] - arr[s_ - 1], arr[s_ - 1] - arr[s_ - 2])) angle_ = np.abs( py_ang(arr[s_] - arr[s_ - 1], arr[s_ - 1] - arr[s_ - 2])) angle_ = 90 - np.abs(angle_ - 90) pointy = min(angle_, pointy) logger.debug(angle_) if pointy > 15.0: logger.debug("not pointy") tuple_list = tuple_list_buffer.copy() logger.debug("simple") else: logger.debug("NOT simple") if get_spin(tuple_list) < 0: logger.info("REVERSE LIST") tuple_list.reverse() polygon_points = tuple_list logger.info("polygon_points: {}".format(polygon_points)) polygon_obj = geometry.Polygon(polygon_points) point_array = np.array( [polygon_obj.exterior.xy[0][:-1], polygon_obj.exterior.xy[1][:-1]]).transpose() if polygon_obj.area >= min_area: logger.debug("area: {}".format(polygon_obj.area)) break return point_array
def from_system(cls, system): """Convert a `System` instance to a `Polygons` instance. Parameters ---------- system : System Returns ------- Polygons """ obj = cls() for e in system: if not hasattr(e, "paths"): continue # assert isinstance(e, PolygonPixelElectrode), (e, e.name) exts, ints = [], [] for pi in e.paths: # shapely ignores f-contiguous arrays so copy # https://github.com/sgillies/shapely/issues/26 ei = area_centroid(pi)[0] pi = geometry.LinearRing(pi.copy("C")) if ei < 0: ints.append((abs(ei), pi)) elif ei > 0: exts.append((abs(ei), pi)) if not exts: continue ints.sort(key=operator.itemgetter(0)) exts.sort(key=operator.itemgetter(0)) # the following needs to be complicated to cover # onion-like "ext in int in ext" cases. groups = [] done = set() for exta, exterior in exts: ep = geometry.Polygon(exterior) gint = [] for i, (inta, interior) in enumerate(ints): if i in done: continue if inta >= exta: break if ep.contains(interior): gint.append(interior) done.add(i) pi = geometry.Polygon(exterior, gint) if pi.is_valid and pi.area > 0: groups.append(pi) else: logger.warn("polygon %s failed %s/%s", e.name, pi.is_valid, pi.area) # remaining interiors must be top level or "free" #assert not ints, ints #mp = geometry.MultiPolygon(groups) #mp = mp.union(geometry.Point()) mp = ops.unary_union(groups) obj.append((e.name, mp)) return obj
def polygon_polygon_touch(poly1, poly2): """ :param poly1: :param poly2: :return: boolean """ p1 = sg.LinearRing(poly1) p2 = sg.LinearRing(poly2) inter = p1.intersection(p2) if inter.type == 'LineString': return np.array(inter) elif inter.type == 'MultiLineString': ar = [] for line in inter: ar += list(zip(line.xy[0], line.xy[1])) return np.array(ar) return np.zeros(0)
def nearest_culture_point(cm): ''' return the coordinates of nearest point in the boundary of the culture ''' cult = sg.LinearRing(sg.Point([0.,0.]).buffer(1000.).exterior.coords) min_d = cult.project(sg.Point(cm)) ret = cult.interpolate(min_d) return list(ret.coords)[0]