def split_geom(row): # Get related line rel_line = lines[row[lineIdInPntShp]] if type(rel_line["GEOM"]) != list: line_geom = fix_line(rel_line["GEOM"], row.geometry) split_lines = split(line_geom, row.geometry) lines[row[lineIdInPntShp]]["GEOM"] = [l for l in split_lines] else: for i in range(len(rel_line["GEOM"])): if rel_line["GEOM"][i].distance(row.geometry) < 1e-8: line_geom = fix_line(rel_line["GEOM"][i], row.geometry) split_lines = split(line_geom, row.geometry) split_lines = [l for l in split_lines] lines[row[lineIdInPntShp]]["GEOM"][i] = split_lines[0] lines[row[lineIdInPntShp]]["GEOM"] += split_lines[1:] break else: continue return row
def transform(self, image, target): orig_size = image.size image = self.head_transforms(image) if not is_bitonal(image): self.im_mode = image.mode image = self.tail_transforms(image) scale = image.shape[2] / orig_size[0] t = torch.zeros((self.num_classes, ) + image.shape[1:]) start_sep_cls = self.class_mapping['aux']['_start_separator'] end_sep_cls = self.class_mapping['aux']['_end_separator'] for key, lines in target['baselines'].items(): cls_idx = self.class_mapping['baselines'][key] for line in lines: # buffer out line to desired width line = [k for k, g in groupby(line)] line = np.array(line) * scale shp_line = geom.LineString(line) split_offset = min(5, shp_line.length / 2) line_pol = np.array(shp_line.buffer(self.line_width / 2, cap_style=2).boundary, dtype=np.int) rr, cc = polygon(line_pol[:, 1], line_pol[:, 0], shape=image.shape[1:]) t[cls_idx, rr, cc] = 1 split_pt = shp_line.interpolate(split_offset).buffer(0.001) start_sep = np.array((split(shp_line, split_pt)[0].buffer( self.line_width, cap_style=3).boundary), dtype=np.int) rr_s, cc_s = polygon(start_sep[:, 1], start_sep[:, 0], shape=image.shape[1:]) t[start_sep_cls, rr_s, cc_s] = 1 t[start_sep_cls, rr, cc] = 0 split_pt = shp_line.interpolate(-split_offset).buffer(0.001) end_sep = np.array((split(shp_line, split_pt)[-1].buffer( self.line_width, cap_style=3).boundary), dtype=np.int) rr_s, cc_s = polygon(end_sep[:, 1], end_sep[:, 0], shape=image.shape[1:]) t[end_sep_cls, rr_s, cc_s] = 1 t[end_sep_cls, rr, cc] = 0 for key, regions in target['regions'].items(): cls_idx = self.class_mapping['regions'][key] for region in regions: region = np.array(region) * scale rr, cc = polygon(region[:, 1], region[:, 0], shape=image.shape[1:]) t[cls_idx, rr, cc] = 1 target = t if self.aug: image = image.permute(1, 2, 0).numpy() target = target.permute(1, 2, 0).numpy() o = self.aug(image=image, mask=target) image = torch.tensor(o['image']).permute(2, 0, 1) target = torch.tensor(o['mask']).permute(2, 0, 1) return image, target
def split_intersection(a, b): """Return geometry collections of line a split by line b and line b split by line a. :param a: :type a: shapely.geometry.linestring.LineString :param b: :type b: shapely.geometry.linestring.LineString :return: :rtype: tuple """ split_a = split(a, b) split_b = split(b, a) return split_a, split_b
def split_flowline(intersectionPoint, flowlines): # Convert the flowline to a geometry colelction to be exported nhdGeom = flowlines['features'][0]['geometry'] nhdFlowline = GeometryCollection([shape(nhdGeom)])[0] nhdFlowline = LineString([xy[0:2] for xy in list(nhdFlowline[0].coords) ]) # Convert xyz to xy # If the intersectionPoint is on the NHD Flowline, split the flowline at the point if nhdFlowline.intersects(intersectionPoint) is True: NHDFlowlinesCut = split(nhdFlowline, intersectionPoint) # If they don't intersect (weird right?), buffer the intersectionPoint and then split the flowline if nhdFlowline.intersects(intersectionPoint) is False: buffDist = intersectionPoint.distance(nhdFlowline) * 1.01 buffIntersectionPoint = intersectionPoint.buffer(buffDist) NHDFlowlinesCut = split(nhdFlowline, buffIntersectionPoint) # print('NHDFlowlinesCut: ', len(NHDFlowlinesCut), NHDFlowlinesCut) # If the NHD Flowline was split, then calculate measure try: NHDFlowlinesCut[1] except AssertionError as error: # If NHDFlowline was not split, then the intersectionPoint is either the first or last point on the NHDFlowline startPoint = Point(nhdFlowline[0].coords[0][0], nhdFlowline[0].coords[0][1]) lastPointID = len(nhdFlowline[0].coords) - 1 lastPoint = Point(nhdFlowline[0].coords[lastPointID][0], nhdFlowline[0].coords[lastPointID][1]) if (intersectionPoint == startPoint): upstreamFlowline = GeometryCollection() downstreamFlowline = NHDFlowlinesCut error = 'The point of intersection is the first point on the NHD Flowline.' if (intersectionPoint == lastPoint): downstreamFlowline = GeometryCollection() upstreamFlowline = NHDFlowlinesCut error = 'The point of intersection is the last point on the NHD Flowline.' if (intersectionPoint != startPoint and intersectionPoint != lastPoint): error = 'Error: NHD Flowline measure not calculated' downstreamFlowline = GeometryCollection() upstreamFlowline = GeometryCollection() print(error) else: lastLineID = len(NHDFlowlinesCut) - 1 upstreamFlowline = NHDFlowlinesCut[0] downstreamFlowline = NHDFlowlinesCut[lastLineID] print('split NHD Flowline') return upstreamFlowline, downstreamFlowline
def run_part2(self): g1 = self.make_geom(self.w1) g2 = self.make_geom(self.w2) intshape = g1.intersection(g2) min_steps = 1000000000 for point in intshape: if point.x == 0 and point.y == 0: continue # split the lines at the intersection and take the lengths s1 = split(g1, point) s2 = split(g2, point) steps = s1[0].length + s2[0].length if steps < min_steps: min_steps = steps return min_steps
def is_underlapping( geom: LineString, trace: LineString, endpoint: Point, snap_threshold: float, snap_threshold_error_multiplier: float, ) -> Optional[bool]: """ Determine if a geom is underlapping. """ split_results = list(split(geom, trace).geoms) if len(split_results) == 1: # Do not intersect return True if len(split_results) > 1: for segment in split_results: if ( segment.distance(endpoint) < snap_threshold * snap_threshold_error_multiplier ): # Dangling end, overlapping return False logging_prints = { "geom": geom, "trace": trace, "endpoint": endpoint, "snap_threshold": snap_threshold, "snap_threshold_error_multiplier": snap_threshold_error_multiplier, } logging.error( f"Expected is_underlapping to be resolvable.\nvalues:{logging_prints}" ) return None
def polygon_vertical_split(p, cut_x): assert p.type == 'Polygon' min_x, min_y, max_x, max_y = p.bounds assert min_x < cut_x < max_x return ops.split(p, LineString([(cut_x, min_y), (cut_x, max_y)]))
def _split_linestring_by_point(linestring, points): """ Function to split a linestring geometry by multiple inner points Parameters ---------- lstring : LineString Linestring of the line to be splitted points : list List of points to split the linestring Return ------ list_lines : list List of linestring to split the line """ list_linestrings = [linestring] for p in points: # execute split to all lines and store results temp_list = [split(l, p) for l in list_linestrings] # nest all geometries list_linestrings = [ lstring for tval in temp_list for lstring in tval.geoms ] return list_linestrings
def connect_nodes_to_closest_edges(edges_df, nodes_df, edges_geom='individual_linestring', nodes_geom='point_geometry'): """fdas """ for i in range(len(prag_points)): point = prag_points.loc[i,nodes_geom] shortest_distance = 100000 closest_street_index = None original_street_id = None for j in range(len(edges_df)): line = edges_df.loc[j,edges_geom] if line.distance(point) < shortest_distance: shortest_distance = line.distance(point) print(shortest_distance) closest_street_index = j original_street_id = edges_df.loc[j,'kod'] intersect_point = line.interpolate(line.project(point)) closest_line = line # write results - both to points and to streets # new street split at the closest point new_line = add_point_to_linestring(closest_line, intersect_point) print(new_line, '\n', closest_line, '\n', LineString([point, intersect_point]), '\n', original_street_id, '\n', shortest_distance, '\n', line == split(line, intersect_point)) edges_df.loc[closest_street_index, edges_geom] = new_line nodes_df.loc[i,'shortest_path'] = LineString([point, intersect_point]) nodes_df.loc[i,'closest_street_id'] = original_street_id nodes_df.loc[i,'street_distance'] = point.distance(intersect_point) nodes_df.loc[i,'intersect_point'] = intersect_point return(edges_df, nodes_df)
def getShapelySectors(v_type, trajectory, shapely_dist, shapely_ang): sectors = [] if v_type == "person": for i in range(1, len(trajectory.coords)): p1 = Point(trajectory.coords[0]) p1b = Point(trajectory.coords[i - 1]) p2 = Point(trajectory.coords[i]) dist = p1.distance(p2) circle = p1.buffer(dist) line = LineString([trajectory.coords[0], trajectory.coords[i]]) left_border = rotate(line, -shapely_ang, origin=p1b) right_border = rotate(line, shapely_ang, origin=p1b) splitter = LineString([ *left_border.coords, line.coords[-1], *right_border.coords[::-1] ]) polygon = split(circle, splitter) if len(polygon) > 1: sectors.append(polygon[1]) else: for i in range(1, len(trajectory.coords)): line = LineString([trajectory.coords[i - 1], trajectory.coords[i]]) lineB = line.buffer(shapely_dist, cap_style=1) sectors.append(lineB) return sectors
def refinedConvexHull(shapesInRegion, borderGeoms): """ tries to cut the convex hull based on the borders """ regionShape = shapesInRegion.convex_hull # TODO: this does not work yet as linesegments are not complete (maybe need to union street segments into one) shapesForRefinement = unary_union(borderGeoms) if isinstance(shapesForRefinement, LineString): shapesForRefinement = [shapesForRefinement] elif not isinstance(shapesForRefinement, BaseMultipartGeometry): raise ValueError(type(shapesForRefinement)) for singleLine in shapesForRefinement: polygonSplits = split(regionShape, singleLine) # as the region contains every buildingGroup regionPolygons = [ s for s in polygonSplits if s.contains(shapesInRegion[0]) ] if len(regionPolygons) == 1: regionShape = regionPolygons[0] else: raise ValueError( "Borders should not split a region into more than one valid region" ) return regionShape
def _remove_halfplane(polygon, origin, normal): """ :param polygon: Polygon to cut :param origin: Point that defines the half-plane with `normal` :param normal: Vector that defines the half-plane with `origin` """ unit_normal = _normalize(normal) cut_direction = _rotate_2d(unit_normal, pi / 2) # Assuming that `origin` is inside the polygon, we can use this length # (*2 even) and stretch the line from there to construct a line that cuts # the entire polygon. safe_length = 3 * _diagonal_length(polygon.bounds) cut_line = LineString([ origin - safe_length * cut_direction, origin + safe_length * cut_direction ]) parts = split(polygon, cut_line) # Assumes `split` returns a collection of two geometries (I think it does): # one on the one side of the line, and one on the other side. for part in parts: if not _in_halfplane(part.representative_point().coords[0], origin, unit_normal): return part return Point() # The empty feature (nothing is left!)
def findBoundaryLines(self): #Find the bounary line which will cut by faults lines #ACTNUM is not considered here NX, NY = self.GRDECL_Data.NX, self.GRDECL_Data.NY if (self.NumFaultLines == 0): print( "Please find the Fault lines first! Boundary Lines cutted by it" ) return #Raw boundary lines (currently only support straight boundary) Edge1 = ((0, 0), (NX, 0)) Edge2 = ((NX, 0), (NX, NY)) Edge3 = ((NX, NY), (0, NY)) Edge4 = ((0, NY), (0, 0)) RawBoundaryLines = MultiLineString([Edge1, Edge2, Edge3, Edge4]) #Shapely object #Split boundary lines unique_intersectPts = list(set(self.IntersectPts)) #print(unique_intersectPts) pts = MultiPoint(unique_intersectPts) #Shapely object result = split(RawBoundaryLines, pts) #Shapely function #Convert shapely object to list of tuple self.BoundaryLines = Shapely2List_MultiLineString(result)
def Taxi(centroids, minMaxXY): vertRegions = dict() polies = list() for c in centroids: mesh = sg.box(*minMaxXY) others = list(set(centroids) - {c}) for other in NearestFirst(c, others): pp = sg.LineString(TaxiPP(c, other, minMaxXY)) r = rSide(c, other, ops.split(mesh, pp)) if r: mesh = r finished = True for p in mesh.exterior.coords: if not p in vertRegions: vertRegions[p] = RegionsAt(p, centroids) if len(vertRegions[p]) == 1: finished = False if finished: break # region mesh verts are all bordering 2 or 3 regions if mesh.is_empty: oopes() polies.append(mesh) # remove invalid verts #vertRegions = {v:vertRegions[v] for v in vertRegions if len(vertRegions[v])>1} return polies
def scale(self, xfact=1, yfact=1, origin='center', inplace=True): if type(origin) is int: sides = split(self.polygon.boundary, MultiPoint(self.polygon.exterior.coords)) origin = sides[origin].centroid return self.affine_transform('scaling', inplace, (xfact, yfact, origin))
def split_to_lines(polygon): """Split a square-ish polygon into 4 lines. :param polygon: :type polygon: shapely.geometry.polygon.Polygon :return: """ breakpoints = [] vertices = polygon.exterior.coords for i in range(1, len(vertices) + 1): a = vertices[i - 1] try: b = vertices[i] except IndexError: break try: c = vertices[i + 1] except IndexError: c = vertices[1] angle = calculate_angle(a, b, c) if MIN_ANGLE < angle < MAX_ANGLE: logging.debug("Adding breakpoint: {}".format(angle)) breakpoints.append(b) if len(breakpoints) != 4: raise Exception( "Expecting 4 breakpoints for polygon, found {}!".format( len(breakpoints))) logging.debug(breakpoints) lines = split(asLineString(polygon.exterior.coords), MultiPoint(breakpoints)) return lines
def cut_line_between_fractions( line: shp.linestring, start_fraction: float, end_fraction: float) -> shp.LineString: # todo refactor """Cut a line at 2 fractions and return the region between them. :param line: Linestring to cut :param start_fraction: Fraction 1 (0 < f1 < f2) :param end_fraction: Fraction 2 (f1 < f2 < 1) :return: Linestring that was cut out """ assert 0 <= start_fraction <= end_fraction assert start_fraction <= end_fraction <= 1 # point a fraction on the line p1 = line.interpolate(start_fraction, normalized=True) p2 = line.interpolate(end_fraction, normalized=True) # Cut the line: this returns the target cut but also returns several little chunks (<< 1e-6 in length) # small buffer includes rounding errors cut_lines = ops.split(line, shp.MultiPoint([p1, p2]).buffer(1e-12)) # Filter out the tiny pieces filter_function = partial(filter_line_length, line, start_fraction, end_fraction) valid_line = filter(filter_function, cut_lines) # There should be a single item in this list return list(valid_line)[0]
def shift_geom(shift, gdataframe, plotQ=False): # this code is adapted from answer found in SO # will be credited here: ??? shift -= 180 moved_geom = [] splitted_geom = [] border = LineString([(shift, 90), (shift, -90)]) for row in gdataframe["geometry"]: splitted_geom.append(split(row, border)) for element in splitted_geom: items = list(element) for item in items: minx, miny, maxx, maxy = item.bounds if minx >= shift: moved_geom.append(translate(item, xoff=-180 - shift)) else: moved_geom.append(translate(item, xoff=180 - shift)) # got `moved_geom` as the moved geometry moved_geom_gdf = gpd.GeoDataFrame({"geometry": moved_geom}) # can change crs here if plotQ: fig1, ax1 = plt.subplots(figsize=[8, 6]) moved_geom_gdf.plot(ax=ax1) plt.show() return moved_geom_gdf
def clip_geometry_to_tile(geometry, tile): tile_geom = box(*mercantile.bounds(tile)) # Geometry collection of split objects split_gc = split(geometry, tile_geom) return [g for g in split_gc if tile_geom.contains(g)]
def divide_bbox(rectangle, nrows, ncols): ''' Divides a rectangular bounding box in rows and columns Reference: https://stackoverflow.com/questions/58283684/how-to-divide-a-rectangle-in-specific-number-of-rows-and-columns ''' minx, miny, maxx, maxy = rectangle.bounds dx = (maxx - minx) / nrows # width of a small part dy = (maxy - miny) / ncols # height of a small part horizontal_splitters = [ LineString([(minx, miny + i * dy), (maxx, miny + i * dy)]) for i in range(ncols) ] vertical_splitters = [ LineString([(minx + i * dx, miny), (minx + i * dx, maxy)]) for i in range(nrows) ] splitters = horizontal_splitters + vertical_splitters for splitter in splitters: rectangle = MultiPolygon(split(rectangle, splitter)) return [split_rectangle for split_rectangle in rectangle]
def get_exterior_lines(self,as_the_line=True,show=0): lines=list() if as_the_line: line_getter=lambda _line:TheLine(_line) else: line_getter=lambda _line:_line if self.is_multilinestring: is_ok=False for _ in self.polygon.boundary: is_ok=True break if not is_ok: simple_logger.critical('self.geometry:\n%s',self.geometry) for p in self.points: p.plot() simple_logger.critical('len(self.points): %s',len(self.points)) plt.show() current_chunk=self.polygon.boundary[0] if self.is_multilinestring else self.polygon.boundary for xy in self.xy[1:-1]: # ThePoint(xy).plot() line,current_chunk=shops.split(current_chunk,shg.Point(xy)) lines.append(line_getter(line)) lines.append(line_getter(current_chunk)) if show: for i,line in enumerate(lines): if as_the_line: line.plot() else: TheLine(line).plot() # TheLine(line=line).plot(**plot_kwargs) # simple_logger.debug('line.xy: %s',line.xy) # plt.plot(*line.xy,**plot_kwargs) # plt.plot(*line.parallel_offset(5).xy) return lines
def cutOutline(point, linestring): """ Given a point finds an entity in (multi)linestring which goes through the point. Then returns the string starting and ending in that point """ LEN_LIMIT = 40 # Should be roughly equal to half the circular segments, # may prevent from finding a solution if isinstance(linestring, LineString): geom = [linestring] elif isinstance(linestring, MultiLineString): geom = linestring.geoms else: raise RuntimeError("Unknown geometry '{}' passed".format(type(linestring))) for string in geom: if not string.intersects(point): continue splitted = split(string, point) if len(splitted) > 1: string = LineString(list(splitted[1].coords) + splitted[0].coords[1:]) else: string = splitted[0] limit1 = max(1, len(string.coords) - LEN_LIMIT) limit2 = min(LEN_LIMIT, len(string.coords) - 1) return LineString(string.coords[limit1:]), LineString(string.coords[:limit2]) return None, None
def snap_points(points, lines, crs): tolerance = 0.5 length = lines.shape[0] for i in range(length): for point in points.geometry: line = lines.loc[i, "geometry"] line._crs = crs point._crs = crs point_inline_projection = line.interpolate(line.project(point)) point_inline_projection._crs = crs distance_to_line = point.distance(point_inline_projection) if (point.x, point.y) in line.coords: x = "nothing" else: if distance_to_line < tolerance: buff = point.buffer(0.1) ### Split the line on the buffer geometry = split(line, buff) geometry._crs = crs line_1_points = [tuple(xy) for xy in geometry[0].coords[:-1]] line_1_points.append((point.x, point.y)) line_2_points = [] line_2_points.append((point.x, point.y)) line_2_points.extend([x for x in geometry[-1].coords[1:]]) ### Stitch together the first segment, the interpolated point, and the last segment new_line = linemerge((LineString(line_1_points), LineString(line_2_points))) lines.loc[i, "geometry"] = new_line G = points["geometry"].apply(lambda geom: geom.wkb) points = points.loc[G.drop_duplicates().index] G = lines["geometry"].apply(lambda geom: geom.wkb) lines = lines.loc[G.drop_duplicates().index] return points, lines
def test1(): polygon = [[40, 20], [150, 50], [240, 130], [80, 120]] shapely_poly = Polygon(polygon) line = [(10, 20), (220, 180)] shapely_line = LineString(line) # intersection_line = list(shapely_poly.intersection(shapely_line).coords) # print(intersection_line.area) splited1, splited2 = split(shapely_poly, shapely_line) area1 = splited1.area area2 = splited2.area if area1 > area2: big_split_polygon = splited1.exterior.coords else: big_split_polygon = splited2.exterior.coords # print(list(big_split_polygon)) big_split_polygon = np.array(list(big_split_polygon), np.int32) image = np.full((400, 400, 3), 255) image = cv2.polylines(image, [np.array(polygon)], True, (0, 0, 255), 2) image = cv2.fillPoly(image, [big_split_polygon], (0, 0, 255)) image = cv2.line(image, line[0], line[1], (255, 0, 0), 2) return image
def split_line_at_point(line, point): """Splits the `line` at the `point` on the line and returns it's two parts. Parameters ---------- line : shapely.geometry.LineString point : shapely.geometry.Point Returns ------- line_before: shapely.geometry.LineString Part of `line` before `point` line_after: shapely.geometry.LineString Part of `line` after `point` """ if line.distance(point) > 1e-8: raise ValueError('Point not on line') # Use small buffer polygon instead of point to deal with floating point precision circle = point.buffer(1e-8) line_split = ops.split(line, circle) line_before = line_split[0] line_after = line_split[-1] return line_before, line_after
def split_line_by_nearest_points(gdf_line, gdf_points, tolerance, crs): """ Split the union of lines with the union of points resulting :param GeoDataFrame gdf_line: GeoDataFrame with multiple rows of connecting line segments :param GeoDataFrame gdf_points: geodataframe with multiple rows of single points :returns: ``gdf_segments`` (GeoDataFrame of segments) :rtype: GeoDataFrame https://github.com/ojdo/python-tools/blob/master/shapelytools.py#L144 """ # union all geometries line = gdf_line.geometry.unary_union line._crs = crs snap_points = gdf_points.geometry.unary_union snap_points._crs = crs # snap and split coords on line # returns GeometryCollection # snap_points = snap(coords, line, tolerance) # snap_points._crs = crs split_line = split(line, snap(snap_points, line, tolerance)) split_line._crs = crs segments = [feature for feature in split_line if feature.length > 0.01] gdf_segments = gdf(geometry=segments, crs=crs) # gdf_segments.columns = ['index', 'geometry'] return gdf_segments
def simple_line_cut(linestring, point1, dist_thres, tol, trace=True): from shapely.ops import nearest_points from shapely.ops import split from shapely.geometry import MultiPoint, LineString #Find nearest points on line: np1 = nearest_points(linestring, point1) # Return error message if points are too far away from line: dist1 = np1[0].distance(np1[1]) if dist1 > dist_thres: if trace: print( 'Point1 is', dist1, 'units apart from line which is more than the specified distance threshold of', dist_thres) return None #Do split: split_1 = split(linestring, np1[0].buffer(tol)) if len(list(split_1)) == 1: if trace: print('Splitting at mapped point 1 did not work') return None return list(split_1)
def split_country_superseded(country_polygon): '''This works for countries when a single split results in only two areas (not more than two areas)''' # Split the country if its area is greater than 250 degree square max_area = 250 n_splits = math.ceil(country_polygon.area / max_area) if n_splits == 1: return country_polygon else: centroid = country_polygon.centroid.coords[0] boundary_points = [ pt for i, pt in enumerate(country_polygon.exterior.coords) if i % math.ceil(len(country_polygon.exterior.coords) / n_splits) == 0 ] # original selected boundary points boundary_points_org = boundary_points.copy() # Roll the list to the left boundary_points.append(boundary_points.pop(0)) line_dict = dict() for i, (a, b) in enumerate(zip(boundary_points_org, boundary_points)): line_dict[i] = LineString([a, centroid, b]) # Create a dictionary where each value is a segment of the country country_segment_dict = dict() remaining = country_polygon for s in range(n_splits - 1): area_area = split(remaining, line_dict[s]) country_segment_dict[s] = area_area[0] remaining_iter = iter(area_area) next(remaining_iter) remaining = next(remaining_iter) country_segment_dict[n_splits - 1] = remaining return list(country_segment_dict.values())
def split_precise(linestring, splitter): """ Shapely's split() function will only split LineStrings at vertices. This returns the split LineStrings exactly at the point of intersection. Assumes a single intersection. """ # If there is no intersection, return the linestring if linestring.intersects(splitter) is False: return linestring ssplit = split(linestring, splitter) split_pt = linestring.intersection(splitter) splits = [] for s in ssplit: if Point(s.coords[0]).distance(split_pt) < Point( s.coords[-1]).distance(split_pt): splits.append( LineString(list(split_pt.coords) + list(s.coords))) else: splits.append( LineString(list(s.coords) + list(split_pt.coords))) return splits
def split_line_at_MultiPoint(line_geometry, intersection): """ The function checks whether the coordinates of Point(s) in a Point Collections coordinate are part of the sequence of coordinates of a LineString. When this has been ascerted or fixed, the LineString line_geometry is split at each of the intersecting points in the collection. The input intersection, must be an actual intersection. Parameters ---------- line_geometry: LineString the LineString which has to be split intersection: MultiPoint the intersecting points Returns ------- MultiLineString """ for point in intersection: new_line_coords = list(line_geometry.coords) for n, v in enumerate(new_line_coords): if n == 0: continue line = LineString([Point(new_line_coords[n-1]), Point(v)]) if ((point.intersects(line)) | (line.distance(point) < 1e-8)): new_line_coords.insert(n, point.coords[0]) break line_geometry = LineString([coor for coor in new_line_coords]) lines = split(line_geometry, intersection) return lines
def test_split_closed_ring_with_point(self): splitter = Point([0.0, 0.0]) self.helper(self.ls, splitter, 1) splitter = Point([0.0, 0.5]) self.helper(self.ls, splitter, 2) result = split(self.ls, splitter) assert result[0].coords[:] == [(0, 0), (0.0, 0.5)] assert result[1].coords[:] == [(0.0, 0.5), (0, 1), (1, 1), (1, 0), (0, 0)] # previously failed, see GH#585 splitter = Point([0.5, 0.0]) self.helper(self.ls, splitter, 2) result = split(self.ls, splitter) assert result[0].coords[:] == [(0, 0), (0, 1), (1, 1), (1, 0), (0.5, 0)] assert result[1].coords[:] == [(0.5, 0), (0, 0)] splitter = Point([2.0, 2.0]) self.helper(self.ls, splitter, 1)
def test_split_poly_with_other(self): with self.assertRaises(ValueError): split(self.poly_simple, Point(1, 1)) with self.assertRaises(ValueError): split(self.poly_simple, MultiPoint([(1, 1), (3, 4)])) with self.assertRaises(ValueError): split(self.poly_simple, self.poly_hole)
def helper(self, geom, splitter, expected_chunks): s = split(geom, splitter) self.assertEqual(s.type, "GeometryCollection") self.assertEqual(len(s), expected_chunks) if expected_chunks > 1: # split --> expected collection that when merged is again equal to original geometry if s.geoms[0].type == 'LineString': self.assertTrue(linemerge(s).simplify(0.000001).equals(geom)) elif s.geoms[0].type == 'Polygon': union = cascaded_union(s).simplify(0.000001) self.assertTrue(union.equals(geom)) self.assertEqual(union.area, geom.area) else: raise ValueError elif expected_chunks == 1: # not split --> expected equal to line self.assertTrue(s[0].equals(geom))