def one_linestring_per_intersection(lines, crs): """ Move line endpoints to intersections of line segments. Given a list of touching or possibly intersecting LineStrings, return a list LineStrings that have their endpoints at all crossings and intersecting points and ONLY there. Args: a list of LineStrings or a MultiLineString Returns: a list of LineStrings """ lines_merged = linemerge(lines) # intersecting multiline with its bounding box somehow triggers a first intersection try: bounding_box = box(*lines_merged.bounds) lines_merged = lines_merged.intersection(bounding_box) except: #if the bounding_box fails, then revert to lines merge. print('bounding box method did not work, falling to a more simple method, no need to worry') # merge the result lines_merged = linemerge(lines_merged) lines = [line for line in lines_merged] df = gdf(geometry=lines, crs=crs) return df
def vectorize_skeleton(img, stride, tolerance, preserve_topology=True, remove_hair=0): # Extract the image's graph. i, j = np.nonzero(img) unscaled_xy = np.c_[j, i] xy = unscaled_xy * stride * ( len(img) / (len(img) - 1)) # minor expansion to ensure exact fit to borders xy = xy.round(2) try: u, v = np.array(list(cKDTree(xy).query_pairs(1.5 * stride))).T except ValueError: return linemerge([]) # Make sure that no triangles will form at T junctions. unscaled_xy_set = set(map(tuple, unscaled_xy)) unscaled_xy_u = unscaled_xy[u] unscaled_xy_v = unscaled_xy[v] is_diagonal = np.sum((unscaled_xy_v - unscaled_xy_u)**2, axis=-1) == 2 keep_mask = ~is_diagonal.copy() for k in np.flatnonzero(is_diagonal): a = unscaled_xy_u[k] b = unscaled_xy_v[k] c = (a[0], b[1]) d = (b[0], a[1]) if c in unscaled_xy_set or d in unscaled_xy_set: keep_mask[k] = False else: keep_mask[k] = True u = u[keep_mask] v = v[keep_mask] # Convert to Shapely shape. lines = np.array([xy[u], xy[v]]).swapaxes(0, 1) shape = linemerge(lines).simplify(tolerance, preserve_topology=preserve_topology) # Remove any short deadends created by skeletonization. if remove_hair: strings = list(as_MultiLineString(shape)) arity = {} for strn in strings: for point in strn.coords: arity.setdefault(point, 0) arity[point] += 1 good_strings = [] for strn in strings: if (arity[strn.coords[0]] != 1 and arity[strn.coords[-1]] != 1) \ or strn.length >= remove_hair: good_strings.append(strn) shape = MultiLineString(good_strings) # Make sure the submission is valid. shape = ensure_no_duplicates(shape) return shape
def _create_offset_box(line, thickness, side, bevel=0.0, symmetric=False): offsetline = line.parallel_offset(thickness, side=side) if symmetric: offsetline2 = line.parallel_offset(thickness, side=_oderside(side)) line = offsetline2 if bevel > 0.0: raise Exception('Beveling not yet implemented') if side == 'left': connect1 = shpl_geom.LineString( (line.coords[-1], offsetline.coords[-1])) connect2 = shpl_geom.LineString((line.coords[0], offsetline.coords[0])) return shpl_geom.Polygon( ops.linemerge((line, connect1, offsetline, connect2))) else: connect1 = shpl_geom.LineString( (line.coords[-1], offsetline.coords[0])) connect2 = shpl_geom.LineString( (line.coords[0], offsetline.coords[-1])) return shpl_geom.Polygon( ops.linemerge((offsetline, connect1, line, connect2)))
def difference(line1, line2, close_ends=False): """ Create polygons from two LineString objects. Parameters: line1 (LineString) : a line representing the initial condition. line2 (LineString) : a line representing the final condition. close_ends (bool) : option to close open line ends with vertical line segments. Returns: intersections (Point array) : the intersections between the LineString objects. polygons (Polygon array) : the polygons between the lines. signs (int array) : contains values of +1 or -1 to identify polygons as cut or fill. """ if close_ends==True: line1, line2 = close(line1, line2) intersections = line1.intersection(line2) segs1 = cut_by_points([line1], intersections) segs2 = cut_by_points([line2], intersections) polygons = polygonize([segs1, segs2]) signs = sign(linemerge(segs1), linemerge(segs2)) # can't pass the polygonize generator to my class so convert the polygons into an array polygontxt = [] areas = [] for i, poly in enumerate(polygons): polygontxt.append(poly) areas.append(poly.area*signs[i]) cutfill = pnd.Series(asarray(areas), name='area') return intersections, polygontxt, cutfill
def _linemerge(self, lines_to_merge): """Performs a linemerge operation on a list of lines. """ try: for line in linemerge(lines_to_merge).geoms: yield line except AttributeError as ae: yield linemerge(lines_to_merge)
def _calculate_route(self, start, end): """ This function is called within join_event_routes calculates shortest route from two specific locations start: OSM way ID end: OSM WAY ID Returns Linestring object of route """ # make sure all osm ways ids are int values start = int(start) end = int(end) # Using OSM ids as source and target values calculate shortest route and convert to shapely geometric object # query = f"SELECT seq, edge, b.the_geom AS \"the_geom (truncated)\" FROM pgr_dijkstra('select gid as id, source_osm as source, target_osm as target, length as cost FROM ways as ways_outer, (select ST_Expand(ST_Extent(the_geom),0.1) as box from ways as box_table where box_table.source_osm = {start} OR box_table.target_osm = {end}) as box_final where ways_outer.the_geom && box_final.box', {start}, {end}, false) as a INNER JOIN ways as b ON a.edge = b.gid ORDER BY seq;" # query = f"SELECT UNNEST(pgr_flipedges(ARRAY(SELECT st_astext(b.the_geom) AS \"the_geom (truncated)\" FROM pgr_dijkstra('select gid as id, source_osm as source, target_osm as target, length as cost FROM ways as ways_outer, (select ST_Expand(ST_Extent(the_geom),0.1) as box from ways as box_table where box_table.source_osm = {start} OR box_table.target_osm = {end}) as box_final where ways_outer.the_geom && box_final.box', {start}, {end}, false) as a INNER JOIN ways as b ON a.edge = b.gid ORDER BY seq)));" ###### DELETE # query = f"SELECT ST_SetSRID(UNNEST(pgr_flipedges(ARRAY(SELECT st_astext(b.the_geom) FROM pgr_dijkstra('select gid as id, source_osm as source, target_osm as target, length as cost FROM ways as ways_outer, (select ST_Expand(ST_Extent(the_geom),0.1) as box from ways as box_table where box_table.source_osm = {start} OR box_table.target_osm = {end}) as box_final where ways_outer.the_geom && box_final.box', {start}, {end}, false) as a INNER JOIN ways as b ON a.edge = b.gid ORDER BY seq))),4326);" # Load_populations.database.cursor.execute(query) # route_list = [wkb.loads(row[0], hex=True) for row in Load_populations.database.cursor] # merged_routes = ops.linemerge([*route_list]) # print(merged_routes) ###### DELETE query1 = f"SELECT ST_Transform(ST_SetSRID(UNNEST(pgr_flipedges(ARRAY(SELECT st_astext(b.the_geom) FROM pgr_dijkstra('select gid as id, source_osm as source, target_osm as target, length as cost FROM ways as ways_outer, (select ST_Expand(ST_Extent(the_geom),0.1) as box from ways as box_table where box_table.source_osm = {start} OR box_table.target_osm = {end}) as box_final where ways_outer.the_geom && box_final.box', {start}, {end}, false) as a INNER JOIN ways as b ON a.edge = b.gid ORDER BY seq))),4326), 32630);" query2 = f"SELECT ST_Transform(ST_SetSRID(UNNEST(pgr_flipedges(ARRAY(SELECT st_astext(b.the_geom) FROM pgr_dijkstra('select gid as id, source_osm as source, target_osm as target, length as cost FROM ways as ways_outer, (select ST_Expand(ST_Extent(the_geom),0.1) as box from ways as box_table where box_table.source_osm = {end} OR box_table.target_osm = {start}) as box_final where ways_outer.the_geom && box_final.box', {end}, {start}, false) as a INNER JOIN ways as b ON a.edge = b.gid ORDER BY seq))),4326), 32630);" print("query1", query1) print("query2", query2) # This try exept block ensures that database query does not respond an error code try: Load_populations.database.cursor.execute(query1) route_list = [ wkb.loads(row[0], hex=True) for row in Load_populations.database.cursor ] # merge linestrings into one large shapely linestring object merged_routes = ops.linemerge([*route_list]) return merged_routes except: try: # rollback database before executing alternative query Load_populations.database.connection.rollback() # sometimes the route is only available in one direction Load_populations.database.cursor.execute(query2) route_list = [ wkb.loads(row[0], hex=True) for row in Load_populations.database.cursor ] # reverse list order route_list.reverse() # merge linestrings into one large shapely linestring object merged_routes = ops.linemerge([*route_list]) return merged_routes except: # rollback database before executing alternative query Load_populations.database.connection.rollback() return None
def place(self, dc): ls = defaultdict(list) for c in self.pa: attr = c.attrib if c.tag == "wire" and attr["layer"] in ("20", "21"): (x1, y1, x2, y2) = [float(attr[t]) for t in "x1 y1 x2 y2".split()] p0 = dc.copy().goxy(x1, y1) p1 = dc.copy().goxy(x2, y2) ls[attr["layer"]].append(sg.LineString([p0.xy, p1.xy])) elif c.tag == "hole": (x, y, drill) = [float(attr[t]) for t in "x y drill".split()] p = dc.copy().goxy(x, y) dc.board.hole(p.xy, drill) elif c.tag == "circle" and attr["layer"] == "51": (x, y, radius) = [float(attr[t]) for t in "x y radius".split()] p = dc.copy().goxy(x, y) dc.board.hole(p.xy, 2 * radius) elif c.tag == "smd": (x, y, dx, dy) = [float(attr[t]) for t in "x y dx dy".split()] p = dc.copy().goxy(x, y) p.rect(dx, dy) p.setname(attr["name"]) self.pad(p) elif c.tag == "pad": (x, y, diameter, drill) = [ float(attr[t]) for t in "x y diameter drill".split() ] nm = attr["name"] dc.push() dc.goxy(x, y) dc.board.hole(dc.xy, drill) n = { "circle": 60, "octagon": 8, "square": 4 }[attr.get("shape", "circle")] p = dc.copy() p.n_agon(diameter / 2, n) p.setname(nm) p.part = self.id self.pads.append(p) p.contact() if self.use_pad_text and nm not in ("RESERVED", ): self.board.annotate(dc.xy[0], dc.xy[1], nm) dc.pop() if ls["20"]: g = so.linemerge(ls["20"]) brd.layers['GML'].add(g) if self.use_silk and ls["21"]: g = so.linemerge(ls["21"]).buffer(self.board.silk / 2) self.board.layers['GTO'].add(g)
def vectorize_skeleton(img, stride, tolerance, preserve_topology=True, remove_hair=0): # Extract the image's graph. i,j = np.nonzero(img) unscaled_xy = np.c_[j,i] xy = unscaled_xy * stride * (len(img) / (len(img) - 1)) # minor expansion to ensure exact fit to borders xy = xy.round(2) try: u,v = np.array(list(cKDTree(xy).query_pairs(1.5*stride))).T except ValueError: return linemerge([]) # Make sure that no triangles will form at T junctions. unscaled_xy_set = set(map(tuple, unscaled_xy)) unscaled_xy_u = unscaled_xy[u] unscaled_xy_v = unscaled_xy[v] is_diagonal = np.sum((unscaled_xy_v - unscaled_xy_u)**2, axis=-1) == 2 keep_mask = ~is_diagonal.copy() for k in np.flatnonzero(is_diagonal): a = unscaled_xy_u[k] b = unscaled_xy_v[k] c = (a[0], b[1]) d = (b[0], a[1]) if c in unscaled_xy_set or d in unscaled_xy_set: keep_mask[k] = False else: keep_mask[k] = True u = u[keep_mask] v = v[keep_mask] # Convert to Shapely shape. lines = np.array([xy[u], xy[v]]).swapaxes(0,1) shape = linemerge(lines).simplify(tolerance, preserve_topology=preserve_topology) # Remove any short deadends created by skeletonization. if remove_hair: strings = list(as_MultiLineString(shape)) arity = {} for strn in strings: for point in strn.coords: arity.setdefault(point, 0) arity[point] += 1 good_strings = [] for strn in strings: if (arity[strn.coords[0]] != 1 and arity[strn.coords[-1]] != 1) \ or strn.length >= remove_hair: good_strings.append(strn) shape = MultiLineString(good_strings) # Make sure the submission is valid. shape = ensure_no_duplicates(shape) return shape
def shared_segs(self, g1, g2): """ This function returns the segments that are shared with two input geometries. The shapely function `shapely.ops.shared_paths()` is adopted and can catch both the shared paths with the same direction for both inputs as well as the shared paths with the opposite direction for one the two inputs. The returned object extents the `segments` property with detected segments. Where each seperate segment is a linestring between two points. Parameters ---------- g1 : shapely.geometry.LineString first geometry g2 : shapely.geometry.LineString second geometry """ # detect potential shared paths between two linestrings try: fw_bw = shared_paths(g1, g2) except ValueError: self.valerr = True fw_bw = False # fw_bw = shared_paths(snap(g1, g2, tolerance=6), g2) # continue if any shared path was detected if fw_bw and not fw_bw.is_empty: forward = fw_bw[0] backward = fw_bw[1] if backward.is_empty: # only contains forward objects shared_segments = forward elif forward.is_empty: # only contains backward objects shared_segments = backward else: # both backward and forward contains objects, so combine forward = self.validate_linemerge(linemerge(forward)) backward = self.validate_linemerge(linemerge(backward)) shared_segments = geometry.MultiLineString(forward + backward) # add shared paths to segments self.segments.extend([list(shared_segments)]) # also add the first coordinates of both geoms as a vertice to segments p1_g1 = geometry.Point([g1.xy[0][0], g1.xy[1][0]]) p1_g2 = geometry.Point([g2.xy[0][0], g2.xy[1][0]]) ls_p1_g1g2 = geometry.LineString([p1_g1, p1_g2]) self.segments.extend([[ls_p1_g1g2]])
def get_defined_route(data): route_segments = [] for i in range(len(data)): if (data[i]['geometry'].geom_type == 'LineString' and data[i]['attributes']['isRoute'] == 'Yes'): route_segments.append(data[i]['geometry']) # combine them into a multi-linestring multi_line = geometry.MultiLineString(route_segments) route = ops.unary_union(ops.linemerge(multi_line)) if route.geom_type =="MultiString": multi_line = geometry.MultiLineString(route) route1 = ops.unary_union(ops.linemerge(multi_line)) return route1 else: return route
def generate() -> MultiLineString: """ A python module called by the `script` command must implement this function, which takes no arguments and return a MultiLineString object. :return: resulting MultiLineString """ segs = [] # horizontal segments for i in range(math.floor(N / 2)): for j in range(M): append_maybe([(i, j), (i + 1, j)], segs) # add half horizontal segments if N % 2 == 0: for j in range(M): append_maybe([((N / 2) - 1, j), (N / 2, j)], segs) # add vertical segments for i in range(math.ceil(N / 2)): for j in range(M - 1): append_maybe([(i, j), (i, j + 1)], segs) half_mls = MultiLineString(segs) other_mls = affinity.translate( affinity.scale(half_mls, -1, 1, origin=(0, 0)), N - 1, 0) return ops.linemerge(ops.unary_union([half_mls, other_mls]))
def get_talus_inside_face(f, ttree, merge=True, displace=True): face = shape(f['geometry']) tals_candidates = tals_candidates = ttree.query(face) tals = [ line for line in tals_candidates if line.intersects(face) and not line.intersection(face).geom_type.endswith('Point') ] tals = [ line if face.contains(line) else line.intersection(face) for line in tals ] no_multipart = [] for t in tals: if t.geom_type == 'MultiLineString' or t.geom_type == "GeometryCollection": for tt in t: if tt.geom_type == 'LineString': # and not face.exterior.contains(tt): no_multipart.append(tt) else: no_multipart.append(t) if merge: tals_merged = linemerge(no_multipart) if tals_merged.geom_type == 'LineString': no_multipart = [tals_merged] else: no_multipart = [t for t in tals_merged] if displace: no_multipart = [ displace_line_from_centroid_when_snapped_to_road(face, t) for t in no_multipart ] return no_multipart
def create_skeleton_line(self, simplify = True, simplify_tolerance = ''): u""" Create a skeleton line of the polygon by using the circumcenters of the triangles created by the Conforming Delaunay Triangulation applied by Triangle Optionally simplify (by default) the skeleton by using an algorithm provided by Shapely. """ self.circumcenters = list() for t in self.tw.triangles: self.circumcenters.append(self.calculate_circumcenter(t)) # list of skeleton segments skel_segments = list() for key in sorted(self.tw.shared_edges.iterkeys()): if self.tw.shared_edges[key] != 2: continue # retrieve endpoints of the skeleton segment from_pt = self.circumcenters[key[0] - 1] to_pt = self.circumcenters[key[1] - 1] # creating skeleton segment skel_segment = LineString([(cc.x, cc.y) for cc in (from_pt, to_pt)]) skel_segments.append(skel_segment) else: # merging all skeleton segments to a single (possibly multiline) # object skel_line = linemerge(skel_segments) # simplifying skeleton line if simplify: if not simplify_tolerance: simplify_tolerance = self.SIMPLIFY_TOLERANCE skel_line = skel_line.simplify(simplify_tolerance, False) return skel_line
def MedialAxis(axis): """ Calculate corridor medial axis using boundary points from first iteration swath units """ output = config.filename('ax_medialaxis', axis=axis) coordinates, groups = BoundaryPoints(axis) voronoi = Voronoi(coordinates, qhull_options='Qbb Qc') lines = list(medial_segments(voronoi, groups)) medialaxis = linemerge(lines) crs = fiona.crs.from_epsg(2154) driver = 'ESRI Shapefile' schema = {'geometry': 'LineString', 'properties': [('AXIS', 'int')]} options = dict(driver=driver, crs=crs, schema=schema) with fiona.open(output, 'w', **options) as fst: # test only one geometry fst.write({ 'geometry': medialaxis.__geo_interface__, 'properties': { 'AXIS': axis } })
def multiline_realation_to_shape(rel, refs_index): lines = [] if 'members' in rel: members = rel['members'] else: members = refs_index[rel['ref']]['members'] for member in members: if member['type'] == 'way': way_shape = way_to_shape(member, refs_index) elif member['type'] == 'relation': if member['ref'] in refs_index: refs_index[member['ref']]['used'] = rel['id'] way_shape = element_to_shape(member, refs_index) else: warning('multiline member not handled', pformat(member)) continue if way_shape is None: # throw exception warning('Failed to make way in relation', pformat(rel)) continue if isinstance(way_shape['shape'], Polygon): # this should not happen on real data way_shape['shape'] = LineString(way_shape['shape'].exterior.coords) lines.append(way_shape['shape']) if len(lines) < 1: return None multiline = MultiLineString(lines) multiline = linemerge(multiline) return {'shape': multiline, 'properties': get_element_props(rel)}
def __unionIntersecting(self, features, idx, disjointFeatures): if not features: return disjointFeatures else: index = features.iterkeys().next() f = features[index][0] f_prop = features[index][1] if self.__ifDisjoint(f, [features[i][0] for i in features.keys()]): idx.delete(index, features[index][0].bounds) disjointFeatures.append(features[index]) del features[index] return self.__unionIntersecting(features, idx, disjointFeatures) else: intersecting_bounds = list(idx.intersection(f.bounds, objects=True)) for n in intersecting_bounds: if index != n.id and (f.disjoint(n.object[0]) is False): idx.delete(index, f.bounds) if f.geom_type[0:4] == 'Mult' or n.object[0].geom_type[0:4] == 'Mult': f = f.union(n.object[0]) else: f = linemerge([f, n.object[0]]) del features[index] del features[n.id] idx.delete(n.id, n.object[0].bounds) idx.insert(index, f.bounds, f) features[index] = [f, f_prop] return self.__unionIntersecting(features, idx, disjointFeatures)
def _merge_polygons(self): merge = [] lines_only = True for fig in self.figs: if fig.geom_type != 'LineString' and \ fig.geom_type != 'MultiLineString': lines_only = False merge.append(fig) for fig in merge: self.figs.remove(fig) if lines_only and self.ignore_width: result = linemerge(merge) else: try: result = cascaded_union(merge) except Exception as e: print "ERROR:", e if result.geom_type == 'Polygon' or result.geom_type == 'LineString': self.figs.append( result ) elif result.geom_type == 'MultiPolygon' or result.geom_type == 'MultiLineString': for f in result: self.figs.append(f)
def _extract_collection(self, result): """ Extracts all geometries with the same topological dimension as the input geometry from a collection. Args: result (shapely.geometry.base.BaseGeometry): The intersection result. Returns: shapely.geometry.base.BaseGeometry: The extracted geometries with matching topological dimension. """ if isinstance(result, GeometryCollection): matching_geometries = list() for part in result: if self.geom_dim(part) == self.dim: matching_geometries.append(part) if self.dim == 0: points = list() for geom in matching_geometries: if isinstance(geom, Point): points.append(geom) elif isinstance(geom, MultiPoint): points.extend(geom.geoms) return MultiPoint(points) elif self.dim == 1: return linemerge(matching_geometries) elif self.dim == 2: return cascaded_union(matching_geometries) else: return result
def _construct_row(self, obj, conn): tags = TagStore(obj['tags']) outtags, difficulty = basic_tag_transform(obj['id'], tags, self.config) # we don't support hierarchy at the moment outtags['top'] = True # geometry geom = build_route_geometry(conn, obj['members'], self.ways, self.data) if geom is None: return None if geom.geom_type not in ('MultiLineString', 'LineString'): raise RuntimeError("Bad geometry %s for %d" % (geom.geom_type, obj['id'])) # if the route is unsorted but linear, sort it if geom.geom_type == 'MultiLineString': fixed_geom = linemerge(geom) if fixed_geom.geom_type == 'LineString': geom = fixed_geom outtags['geom'] = from_shape(geom, srid=self.c.geom.type.srid) outtags['symbol'] = write_symbol(self.shield_fab, tags, difficulty, self.config.symbol_datadir) outtags['id'] = obj['id'] return outtags
def dissolve_ways(self, src_path, dst_path, fields=None, exclude=False): self.ways = fiona.open(**zip_path(src_path)) self.fields = self._define_filter_fields(fields, exclude) self.src_path = src_path way_groups = self._determine_way_groups() metadata = self.ways.meta.copy() meta_fields = metadata['schema']['properties'] self._filter_tags(meta_fields) logger.info('combining dissolve group geometries...') with fiona.open(dst_path, 'w', **metadata) as dissolve_shp: for group in way_groups: geom_list = list() for way_id in group: feat = self.ways[way_id] geom = shape(feat['geometry']) geom_list.append(geom) group_tags = self.ways[group[0]]['properties'] dissolve_geom = linemerge(geom_list) dissolve_tags = self._filter_tags(group_tags) dissolve_shp.write(dict( geometry=mapping(dissolve_geom), properties=dissolve_tags )) self.ways.close() return dst_path
def clip_transit_routes(self): """Clips transportation routes, converts them to single parts,explodes the results to account for routes with the same name. Contains logic to ensure only records with geospatial data are return. """ clp_routes = self._intxn_polys.intersection(self._routes) single_lines = {} for i, transit in enumerate(clp_routes): if 'GeometryCollection' not in type(transit).__name__: if type( transit ) is shapely.geometry.multilinestring.MultiLineString: single_lines[clp_routes.index[i]] = ops.linemerge( transit) else: single_lines[clp_routes.index[i]] = transit columns = ['transit', 'geometry'] explode_lines = gpd.GeoDataFrame(single_lines.items(), columns=columns) try: return explode_lines.explode().droplevel(0).reset_index( 0, drop=True) except: return explode_lines
def test_merge_loops(self): """ It seems that loops won't merge, we should avoid these where possible """ line1 = LineString([(1, 1), (2, 1), (2, 2), (1, 2), (1, 1)]) line2 = LineString([(1, 1), (1, 0), (0, 0), (0, 1), (1, 1)]) result = linemerge([line1, line2]) expected = LineString([ (1, 1), (2, 1), (2, 2), (1, 2), (1, 1), (1, 0), (0, 0), (0, 1), (1, 1), ]) shapelyReality = MultiLineString([ LineString([(1, 1), (2, 1), (2, 2), (1, 2), (1, 1)]), LineString([(1, 1), (1, 0), (0, 0), (0, 1), (1, 1)]) ]) #self.assertEqual(result.geom_type, 'LineString') self.assertEqual(result.geom_type, 'MultiLineString') self.LinesEquivalent(result, shapelyReality)
def from_osm(osm, relation, *args, **kwargs): """ A way to build a route from OpenStreetMaps data Args: osm (dpd.OSM.osm): the osm that contains the route as a relation relation (int): the relation to build a route for Returns: dpd.driving.Route: a route table """ ways = [ osm.ways[member["ref"]].geo for member in osm.relations[relation]["members"] if member["type"] == "way" and member["role"] == "" ] way = linemerge(ways) stops = [] for member in osm.relations[relation]["members"]: if member["type"] == "node": stops.append({ "geo": str(( osm.nodes[member["ref"]].geo.xy[0][0], osm.nodes[member["ref"]].geo.xy[1][0], )), "name": osm.nodes[member["ref"]].osm["tags"]["name"], }) return Route(way, stops, *args, **kwargs)
def _create_gdf_strokes(self): # create empty list to fill my_list = [] # loop through merged geometry for a in self.merged: # get all segment points and make line strings linelist = _tuple_to_list(list(self.merged[a])) list_lines_segments = [] for b in linelist: list_lines_segments.append(LineString(b)) # merge seperate segments geom_multi_line = ops.linemerge( MultiLineString(list_lines_segments)) # get other values for gdf id_value = a n_segments = len(self.merged[a]) # append list my_list.append([id_value, n_segments, geom_multi_line]) edge_gdf = gpd.GeoDataFrame( my_list, columns=["stroke_group", "n_segments", "geometry"], crs=self.gdf_projection, ) edge_gdf.set_index("stroke_group", inplace=True) return edge_gdf
def reindex_trimmed(trimmed=trimmedlarge, other=smallermerged): targetpoint = Point(list(trimmed.coords)[0]) finallist = list(other) distlist = [] indexlist = [] index = 0 check_for_intersects(trimmed, smallermerged) for linestring in finallist: endpoints = [ list(linestring.coords)[0], list(linestring.coords)[-1] ] for point in endpoints: indexlist.append(index) dist = targetpoint.distance(Point(point)) distlist.append(dist) index += 1 targetindex = np.where(distlist == np.min(distlist))[0][0] if targetindex % 2 == 0: modifier = 0 else: modifier = 1 lineindex = indexlist[targetindex] targetlinecoords = finallist[lineindex].coords[:] targetlinecoords[(modifier * -1)] = targetpoint.coords[0] finallist[lineindex] = LineString(targetlinecoords) combinedlist = MultiLineString([trimmed, finallist[lineindex]]) combined = ops.linemerge(combinedlist) del finallist[lineindex] finallist.insert(lineindex - 1, combined) final = MultiLineString(finallist) return (final)
def side_based_procedure(terrain, image): line = terrain.center_line.coords con = terrain.poly.boundary.coords mer = linemerge([con, line]) uni = unary_union(mer) left_side, right_side = polygonize(uni) draw = ImageDraw.Draw(image) # draw.polygon(convert_to_map(v[0].boundary.coords), fill="#ff0000") # draw.polygon(convert_to_map(v[1].boundary.coords), fill="#00ff00") center_l = helpers.points_located_on_center_line( terrain.center_line, max(1, 1 / TIME_CONSUMPTION)) left_points = helpers.uniformly_distribute_points(8 / TIME_CONSUMPTION, terrain.poly) left_points += random_points_in_polygon(int(3 * TIME_CONSUMPTION), left_side) right_points = helpers.uniformly_distribute_points(8 / TIME_CONSUMPTION, terrain.poly) right_points += random_points_in_polygon(int(3 * TIME_CONSUMPTION), right_side) image = put_rotated_sprites_onto_image(image, False, left_points, "mountains_side", left_side, center_l) image = put_rotated_sprites_onto_image(image, True, right_points, "mountains_side", right_side, center_l) if center_l: image = put_rotated_sprites_onto_image(image, False, center_l, "mountains", terrain.poly, center_l) return image
def extract_contour(topdown_seg_mask, canvas_size, thickness=5): topdown_seg_mask[topdown_seg_mask != 0] = 255 ret, thresh = cv2.threshold(topdown_seg_mask, 127, 255, 0) contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) mask = np.zeros_like(topdown_seg_mask) patch = box(1, 1, canvas_size[1] - 2, canvas_size[0] - 2) idx = 0 for cnt in contours: cnt = cnt.reshape((-1, 2)) cnt = np.append(cnt, cnt[0].reshape(-1, 2), axis=0) line = LineString(cnt) line = line.intersection(patch) if isinstance(line, MultiLineString): line = ops.linemerge(line) if isinstance(line, MultiLineString): for l in line: idx += 1 cv2.polylines(mask, [np.asarray(list(l.coords), np.int32).reshape((-1, 2))], False, color=idx, thickness=thickness) elif isinstance(line, LineString): idx += 1 cv2.polylines(mask, [np.asarray(list(line.coords), np.int32).reshape((-1, 2))], False, color=idx, thickness=thickness) return mask, idx
def merge_linestrings(first, second): new_coordinates = [] first_geometry = first['geometry'] second_geometry = second['geometry'] f_lines = [] if first_geometry['type'] == 'MultiLineString': first = geometry.MultiLineString(first_geometry['coordinates']) for f in first: f_lines.append(f) else: f_lines.append(geometry.LineString(first_geometry['coordinates'])) if second_geometry['type'] == 'MultiLineString': second = geometry.MultiLineString(second_geometry['coordinates']) for s in second: f_lines.append(s) else: f_lines.append(geometry.LineString(second_geometry['coordinates'])) merged_multiline = geometry.MultiLineString(f_lines) linestring = ops.linemerge(merged_multiline) return linestring
def __plot_edges(self, to_plot: List, edges: List, vertices: List, label: str): lines = [] for edge_idx in to_plot: edge = edges[edge_idx] start_vertex = vertices[edge.start] end_vertex = vertices[edge.end] # Note it could be that the edge is supposed to be parabola (edge.is_linear # will be false), but in our case we always have boxes with 90 degree # corners. If it's a parabola then the focus is one of these corners, and by # drawing a line instead of a parabola we at worse cut through this point, # which is fine. lines.append( geometry.LineString([[start_vertex.X, start_vertex.Y], [end_vertex.X, end_vertex.Y]])) merged_line = ops.linemerge(geometry.MultiLineString(lines)) kwargs = { "label": label, "alpha": 0.5, "color": self.__colour_mapping[label] } # Merged line is either a MultiLineString which means we need to draw multiple # lines, or it is a LineString which means we only need to draw one. if isinstance(merged_line, geometry.MultiLineString): for line in merged_line: xs, ys = self.__simplify_outlines(line) self.__ax.plot(xs, ys, **kwargs) kwargs.pop( "label", None) # Only pass label once for single legend entry else: xs, ys = self.__simplify_outlines(merged_line) self.__ax.plot(xs, ys, **kwargs)
def build_lines(links, line_columns='all', group_id='trip_id', sum_columns=[], mean_columns=[], force_linestring=True): if line_columns is 'all': # all the columns that are shared by all the links of the group are listed variability = links.groupby(group_id).agg(lambda s: s.nunique()).max() line_columns = list(variability.loc[variability == 1].index) lines = links.groupby(group_id)[line_columns].first() if len(sum_columns): lines[sum_columns] = links.groupby(group_id)[sum_columns].sum() if len(mean_columns): lines[mean_columns] = links.groupby(group_id)[mean_columns].mean() links = links.loc[~links['geometry'].apply(lambda g: g.is_empty)] lines['geometry'] = links.groupby(group_id)['geometry'].agg( lambda s: ops.linemerge(list(s))) # force the series to a list lines = lines.dropna(subset =['geometry']) if force_linestring: lines['geometry'] = links.groupby(group_id)['geometry'].agg( lambda s: line_list_to_polyline(list(s))) # force the series to a list lines = lines.dropna(subset =['geometry']) lines = lines.loc[~lines['geometry'].apply(lambda g: g.is_empty)] return lines.reset_index()
def merge_layers(geom1, geom2): """Find the overlapping portions of two transit trips.""" g2l = geom2['line'].buffer(bTol) # snap(geom2['line'], geom1['line'], TOL) intersect_geom = geom1['line'].intersection(g2l) if intersect_geom.type == 'LineString': if intersect_geom.length > TOL: intersect = [intersect_geom] else: intersect = [] elif intersect_geom.type == 'Point': intersect = [] else: intersect = [g for g in intersect_geom if g.type != 'Point' and g.length > TOL] if intersect: intersect = linemerge(intersect) if intersect.type == 'LineString': intersect = [intersect] else: intersect = list(intersect) intersect = [g for g in intersect if g.length > TOL] if not intersect: return [], [geom1, geom2] else: count = geom1['count'] + geom2['count'] intersect = [dict(line=g, count=count) for g in intersect] sg1 = {'count': geom2['count'], 'line': geom1['line'].buffer(bTol)} sg2 = {'count': geom2['count'], 'line': g2l} g1 = diff_layers(geom1, sg2) g2 = diff_layers(geom2, sg1) return [intersect, g1 + g2]
def polygon_intersections(gdf): """Computes the intersections between all polygons in a GeoDataFrame. Parameters ---------- gdf : Geopandas.GeoDataFrame Returns ------- a Geodataframe containing the intersections """ out_cols = ['id_1', 'id_2', 'geometry'] out = gpd.GeoDataFrame(columns=out_cols) for i, major in gdf.iterrows(): # Exterior only major_poly = major.geometry.exterior # Remove the major from the list gdf = gdf.loc[gdf.index != i] # Keep catchments which intersect gdfs = gdf.loc[gdf.intersects(major_poly)] for j, neighbor in gdfs.iterrows(): # No need to check if we already found the intersect if j in out.id_1 or j in out.id_2: continue # Exterior only neighbor_poly = neighbor.geometry.exterior # Ok, the actual intersection mult_intersect = major_poly.intersection(neighbor_poly) # All what follows is to catch all possibilities # Should no happen in our simple geometries but ya never know if isinstance(mult_intersect, shpg.Point): continue if isinstance(mult_intersect, shpg.linestring.LineString): mult_intersect = [mult_intersect] if len(mult_intersect) == 0: continue mult_intersect = [m for m in mult_intersect if not isinstance(m, shpg.Point)] if len(mult_intersect) == 0: continue mult_intersect = linemerge(mult_intersect) if isinstance(mult_intersect, shpg.linestring.LineString): mult_intersect = [mult_intersect] for line in mult_intersect: assert isinstance(line, shpg.linestring.LineString) line = gpd.GeoDataFrame([[i, j, line]], columns=out_cols) out = out.append(line) return out
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 pfr_lines(self, inp, core): c = QuadContourGenerator.from_rectilinear(core.psi_data.R[0], core.psi_data.Z[:, 0], core.psi_data.psi_norm) contours = c.contour(0.999) if len(contours) == 1: # then we're definitely dealing with a surface inside the seperatrix raise ValueError("Did not find PFR flux surface. Stopping.") else: # we need to find the surface that is contained within the private flux region for j, contour in enumerate(contours): # if the contour is entirely below the x-point and contour extends to both the left and the # right of the x-point horizontally, then the contour is almost certainly the desired PFR contour if np.amax(contour[:, 1]) < core.pts.xpt[1] and \ np.amin(contour[:, 0]) < core.pts.xpt[0] < np.amax(contour[:, 0]): # then it's a probably a pfr flux surface, might need to add additional checks later # make sure the line goes from inboard to outboard if contour[-1, 0] < contour[0, 0]: contour = np.flipud(contour) # find cut points cut_pt_ib = LineString(contour).intersection(inp.wall_line)[0] cut_pt_ob = LineString(contour).intersection(inp.wall_line)[1] dist1 = LineString(contour).project(cut_pt_ib, normalized=True) cutline_temp = cut(LineString(contour), dist1)[1] # reverse line point order so we can reliably find the second intersection point cutline_temp_rev = LineString(np.flipud(np.asarray(cutline_temp.coords))) dist2 = cutline_temp_rev.project(cut_pt_ob, normalized=True) cutline_final_rev = cut(cutline_temp_rev, dist2)[1] # reverse again for final pfr flux line pfr_flux_line = LineString(np.flipud(np.asarray(cutline_final_rev.coords))) # add pfr_line intersection points on inboard side # for some reason, union freaks out when I try to do inboard and outboard # at the same time. union = inp.wall_line.union(cut(LineString(contour), 0.5)[0]) result = [geom for geom in polygonize(union)][0] inp.wall_line = LineString(result.exterior.coords) # add pfr line intersection points on outboard side union = inp.wall_line.union(cut(LineString(contour), 0.5)[1]) result = [geom for geom in polygonize(union)][0] inp.wall_line = LineString(result.exterior.coords) # cut out pfr section of wall line wall_pts = np.asarray(inp.wall_line.xy).T wall_start_pos = np.where((wall_pts == cut_pt_ob).all(axis=1))[0][0] wall_line_rolled = LineString(np.roll(wall_pts, -wall_start_pos, axis=0)) wall_line_cut_pfr = cut(wall_line_rolled, wall_line_rolled.project(cut_pt_ib, normalized=True))[0] # create LineString with pfr line and section of wall line self.pfr_line = linemerge((pfr_flux_line, wall_line_cut_pfr)) break
def isNonAeroDynamic(index, cordpt, globaldata, wallpoints): main_pointx,main_pointy = getPoint(index, globaldata) cordptx = float(cordpt.split(",")[0]) cordpty = float(cordpt.split(",")[1]) line = shapely.geometry.LineString([[main_pointx, main_pointy], [cordptx, cordpty]]) responselist = [] for item in wallpoints: polygonpts = [] for item2 in item: polygonpts.append([float(item2.split(",")[0]), float(item2.split(",")[1])]) polygontocheck = shapely.geometry.Polygon(polygonpts) merged = linemerge([polygontocheck.boundary, line]) borders = unary_union(merged) polygons = polygonize(borders) i = 0 for p in polygons: i = i + 1 if i == 1: responselist.append(False) else: responselist.append(True) if True in responselist: return True else: return False
def multiline_realation_to_shape(rel, refs_index): lines = [] for member in rel['members']: if member['type'] != 'way': print('multiline member not handled', member) continue way_shape = way_to_shape(member, refs_index) if way_shape is None: # throw exception print('Failed to make way in relation', rel) continue if isinstance(way_shape['shape'], Polygon): # this should not happen on real data way_shape['shape'] = LineString(way.exterior.coords) lines.append(way_shape['shape']) if len(lines) < 1: return None multiline = MultiLineString(lines) multiline = linemerge(multiline) return { 'shape': multiline, 'properties': get_element_props(rel) }
def transform_tags(self, osmid, tags): outtags = { 'intnames' : {}, 'top' : None} for k in conf.TAGS_DIFFICULTY_MAP.keys(): outtags[k] = None for k in conf.TAGS_PISTETYPE_MAP.keys(): outtags[k] = None difficulty = 0 if tags.has_key('piste:name'): outtags['name'] = tags['piste:name'] elif tags.has_key('name'): outtags['name'] = tags['name'] elif tags.has_key('piste:ref'): outtags['name'] = '[%s]' % tags['piste:ref'] elif tags.has_key('ref'): outtags['name'] = '[%s]' % tags['ref'] else: outtags['name'] = '(%s)' % osmid # default treatment of tags for (k,v) in tags.iteritems(): if k == 'piste:difficulty': if v in conf.TAGS_DIFFICULTY_MAP.keys(): outtags[v] = True difficulty = conf.TAGS_DIFFICULTY_MAP[v] if k == 'piste:type': if v in conf.TAGS_PISTETYPE_MAP.keys(): outtags[v] = True if k.startswith('name:'): outtags['intnames'][k[5:]] = v outtags['symbol'] = symbols.get_symbol(difficulty, None, tags, symboltypes) cur = self.thread.cursor if 'name' not in outtags: outtags['name'] = '(%s)' % osmid if outtags['top'] is None: if 'network' in tags: top = self.db.select_one("EXECUTE get_route_top(%s, %s)", (osmid, tags['network']), cur=cur) outtags['top'] = True if (top == 0) else False else: outtags['top'] = True # finally: compute the geometry routelines = self.db.select_column("EXECUTE get_route_geometry(%s)", (osmid,), cur=cur) if routelines: outtags['geom'] = sops.linemerge(routelines) outtags['geom']._crs = int(conf.DB_SRID) # Clear elevation profile cache clearcache.clearElevationProfileCache(osmid) return outtags
def load_lines_relevant(self, major_tile): print('Setting up %s...' % major_tile) relevant_pd = self.tl_relationshps[self.tl_relationshps['name'] == major_tile] relevant_list = [] try: relevant_list = relevant_pd['Relevant'].to_list()[0] except IndexError: print('No tiles for %s...' % major_tile) exit() if 'list' not in str(type(relevant_list)) or len(relevant_list) == 0: print('No tiles for %s...' % major_tile) else: line_list = [] for i, item in enumerate(relevant_list): path_to_minor = os.path.join(self.ctr_folder, "%s.shp" % item) linestring_list, test_dic = self.load_tile(path_to_minor) for elev in test_dic.keys(): new_linestring_list = self.examine_head_tail( elev, test_dic) line_list = line_list + new_linestring_list merge_lines = linemerge(line_list) self.write_output_file(merge_lines, major_tile)
def publish(self, file_name): self.region.UUID = str(CimWriter.uuid()) self.cimobject_by_uuid_dict[self.region.UUID] = self.region self.add_location(self.centroid.x, self.centroid.y, is_center=True) total_line_length = 0 for circuit in self.circuits: station1 = circuit.members[0] station2 = circuit.members[-1] if 'station' in station1.type: connectivity_node1 = self.substation_to_cim(station1, circuit.voltage) elif 'plant' in station1.type or 'generator' in station1.type: connectivity_node1 = self.generator_to_cim(station1, circuit.voltage) else: self.root.error('Invalid circuit! - Skip circuit') circuit.print_circuit() continue if 'station' in station2.type: connectivity_node2 = self.substation_to_cim(station2, circuit.voltage) elif 'plant' in station2.type or 'generator' in station2.type: connectivity_node2 = self.generator_to_cim(station2, circuit.voltage) else: self.root.error('Invalid circuit! - Skip circuit') circuit.print_circuit() continue lines_wsg84 = [] line_length = 0 for line_wsg84 in circuit.members[1:-1]: lines_wsg84.append(line_wsg84.geom) line_length += line_wsg84.length line_wsg84 = linemerge(lines_wsg84) total_line_length += line_length self.root.debug('Map line from (%lf,%lf) to (%lf,%lf) with length %s meters', station1.geom.centroid.y, station1.geom.centroid.x, station2.geom.centroid.y, station2.geom.centroid.x, str(line_length)) self.line_to_cim(connectivity_node1, connectivity_node2, line_length, circuit.name, circuit.voltage, line_wsg84.centroid.y, line_wsg84.centroid.x) # self.root.info('The inferred net\'s length is %s meters', str(total_line_length)) self.attach_loads() cimwrite(self.cimobject_by_uuid_dict, file_name + '.xml', encoding='utf-8') cimwrite(self.cimobject_by_uuid_dict, file_name + '.rdf', encoding='utf-8') # pretty print cim file xml = parse(file_name + '.xml') pretty_xml_as_string = xml.toprettyxml(encoding='utf-8') matches = re.findall('#x[0-9a-f]{4}', pretty_xml_as_string) for match in matches: pretty_xml_as_string = pretty_xml_as_string.replace(match, unichr(int(match[2:len(match)], 16))) pretty_file = io.open(file_name + '_pretty.xml', 'w', encoding='utf8') pretty_file.write(unicode(pretty_xml_as_string)) pretty_file.close()
def build_geometries(diff, srid): srid_txt = "EPSG:{}".format(srid) geom = {'line': [], 'point': [], 'polygon': []} for osm_id, node in diff['add']['node'].iteritems(): x, y = projections.from4326(node["geom"], srid_txt) geom["point"].append({"geom": "SRID={};POINT({} {})".format(srid, x, y), "osm_id": osm_id, "tags": node["tags"]}) for osm_id, way in diff['add']['way'].iteritems(): line = projections.from4326(way["geom"], srid_txt) polygonize = check_tags_if_polygon(way["tags"]) if polygonize: result, dangles, cuts, invalids = polygonize_full([line]) #print result, dangles, cuts, invalids for poly in result: geom["polygon"].append({"geom": "SRID={};{}".format(srid, poly.wkt), "osm_id": osm_id, "way_area":poly.area, "tags": way["tags"]}) for line in dangles: geom["line"].append({"geom": "SRID={};{}".format(srid, line.wkt), "osm_id": osm_id, "tags": way["tags"]}) for line in cuts: geom["line"].append({"geom": "SRID={};{}".format(srid, line.wkt), "osm_id": osm_id, "tags": way["tags"]}) for line in invalids: geom["line"].append({"geom": "SRID={};{}".format(srid, line.wkt), "osm_id": osm_id, "tags": way["tags"]}) else: ll = ",".join([a[0] + a[1] for a in line]) geom["line"].append({"geom": "SRID={};LINESTRING({})".format(srid, ll), "osm_id": osm_id, "tags": way["tags"]}) for osm_id, relation in diff['add']['relation'].iteritems(): lines = [projections.from4326(way, srid_txt) for way in relation["geom"]] polygonize = check_tags_if_polygon(relation["tags"]) if polygonize: merged = linemerge(lines) polys = [] lines = [] for line in merged: if line.is_ring: polys.append(line) else: lines.append(line) if polys: # TODO: repair geometry poly = Polygon(polys[0], polys[1:]) geom["polygon"].append({"geom": "SRID={};{}".format(srid, poly.wkt), "osm_id": -osm_id, "way_area":0, "tags": relation["tags"]}) for line in lines: geom["line"].append({"geom": "SRID={};{}".format(srid, line.wkt), "osm_id": -osm_id, "tags": relation["tags"]}) #result, dangles, cuts, invalids = polygonize_full(lines) ##print result, dangles, cuts, invalids #result = list(result) #sd = result[0] #for poly in result[1:]: #sd = sd.symmetric_difference(poly) #geom["polygon"].append({"geom": "SRID={};{}".format(srid, sd.wkt), "osm_id": -osm_id, "way_area":sd.area, "tags": relation["tags"]}) #for line in dangles: #geom["line"].append({"geom": "SRID={};{}".format(srid, line.wkt), "osm_id": -osm_id, "tags": relation["tags"]}) #for line in cuts: #geom["line"].append({"geom": "SRID={};{}".format(srid, line.wkt), "osm_id": -osm_id, "tags": relation["tags"]}) else: ll = ",".join([a[0] + a[1] for a in line]) geom["line"].append({"geom": "SRID={};LINESTRING({})".format(srid, ll), "osm_id": osm_id, "tags": relation["tags"]}) return geom
def get_shapes_from_osm(relation_id): overpass = '******'+relation_id+');out body;>;out skel qt;>;out skel qt;' resp_overpass = requests.get(overpass) resutl = resp_overpass.json()['elements'] relations = [] ways = [] nodes = [] #stocker tous les nodes/ways dans une structure pour pouvoir les utiliser plus facilement plus tard for elem in resutl: if elem['type']=="relation" : relations.append(elem) if elem['type']=="way" : ways.append(elem) if elem['type']=="node" : nodes.append(elem) relation = relations[0] print ("traitement de la relation {}".format(relation['id'])) ways_linestrings = [] for member in relation['members']: if member['type'] == "way": current_way_details = [way for way in ways if way['id']==member['ref']] if len(current_way_details) != 1 : print ('>> KO (en cherchant le chemin {})'.format(member['ref'])) continue nodes_in_current_way = [] for current_node in current_way_details[0]['nodes'] : current_node_details = [node for node in nodes if node['id'] == current_node] if len(current_node_details) < 1 : print ('>> KO (en cherchant les noeuds {})'.format(current_node)) continue nodes_in_current_way.append(current_node_details[0]) #on construit une ligne avec les noeuds points_nodes = [(node['lon'], node['lat']) for node in nodes_in_current_way] way_linestring = LineString(points_nodes) ways_linestrings.append(way_linestring) #on fusionne tous les chemins en un final_linestring = linemerge(ways_linestrings) print(final_linestring) if final_linestring.geom_type == "LineString": print(list(final_linestring.coords)) else : for a_line in final_linestring.geoms : print(list(a_line.coords)) return "OK"
def test_linemerge(self): lines = MultiLineString( [((0, 0), (1, 1)), ((2, 0), (2, 1), (1, 1))]) result = linemerge(lines) self.assertIsInstance(result, LineString) self.assertFalse(result.is_ring) self.assertEqual(len(result.coords), 4) self.assertEqual(result.coords[0], (0.0, 0.0)) self.assertEqual(result.coords[3], (2.0, 0.0)) lines2 = MultiLineString( [((0, 0), (1, 1)), ((0, 0), (2, 0), (2, 1), (1, 1))]) result = linemerge(lines2) self.assertTrue(result.is_ring) self.assertEqual(len(result.coords), 5) lines3 = [ LineString(((0, 0), (1, 1))), LineString(((0, 0), (0, 1))), ] result = linemerge(lines3) self.assertFalse(result.is_ring) self.assertEqual(len(result.coords), 3) self.assertEqual(result.coords[0], (0.0, 1.0)) self.assertEqual(result.coords[2], (1.0, 1.0)) lines4 = [ ((0, 0), (1, 1)), ((0, 0), (0, 1)), ] self.assertTrue(result.equals(linemerge(lines4))) lines5 = [ ((0, 0), (1, 1)), ((1, 0), (0, 1)), ] result = linemerge(lines5) self.assertEqual(result.type, 'MultiLineString')
def clipped_polygon(azimuth,polygon,line1,line2): merged_line = linemerge([line1, line2]) merged = linemerge([polygon.boundary, merged_line]) borders = unary_union(merged) polygons = polygonize(borders) polygon_list = list(polygons) if len(polygon_list)>1: polygon1 = polygon_list[0] polygon2 = polygon_list[1] polygon1_area = polygon_area_calculator(polygon=polygon1) polygon2_area=polygon_area_calculator(polygon=polygon2) polygon_areas = (polygon1_area, polygon2_area) polygon_dict = {polygon1_area:polygon1, polygon2_area:polygon2} if azimuth >= 180: result = polygon_dict[max(polygon_areas)] elif azimuth == 0 or azimuth == 360: result = polygon_dict[max(polygon_areas)] else: result = polygon_dict[min(polygon_areas)] return result else: return polygon
def diff_layers(geom1, geom2): """Find the difference between two transit trips.""" g1diff = geom1['line'].difference(geom2['line']) if g1diff.type == 'LineString' and g1diff > TOL: return [dict(line=g1diff, count=geom1['count'])] elif g1diff.type == 'MultiLineString': merge = linemerge(g1diff) if merge.type == 'LineString': merge = [merge] return [dict(line=g, count=geom1['count']) for g in merge if g.length > TOL] else: return []
def intersection(self, geom): intersection_ids = list(self.index.intersection(geom.bounds)) if not intersection_ids: raise EmtpyGeometryError('No intersection or empty geometry') intersections = [] for i in intersection_ids: polygon = self.polygons[i] if polygon.contains(geom): return geom if polygon.intersects(geom): try: new_geom_part = polygon.intersection(geom) new_geom_part = filter_geometry_by_type(new_geom_part, geom.type) if new_geom_part: if isinstance(new_geom_part, list): intersections.extend(new_geom_part) else: intersections.append(new_geom_part) except TopologicalError: pass if not intersections: raise EmtpyGeometryError('No intersection or empty geometry') # intersections from multiple sub-polygons # try to merge them back to a single geometry try: if geom.type.endswith('Polygon'): union = cascaded_union(list(flatten_polygons(intersections))) elif geom.type.endswith('LineString'): linestrings = flatten_linestrings(intersections) linestrings = list(filter_invalid_linestrings(linestrings)) if not linestrings: raise EmtpyGeometryError() union = linemerge(linestrings) if union.type == 'MultiLineString': union = list(union.geoms) elif geom.type == 'Point': union = intersections[0] else: log.warn('unexpexted geometry type %s', geom.type) raise EmtpyGeometryError() except ValueError, ex: # likely an 'No Shapely geometry can be created from null value' error log.warn('could not create union: %s', ex) raise EmtpyGeometryError()
def merge_line(self): lines=[] for elmt in self.figs.elements: if elmt.active == 0: continue if elmt.element.geom_type=='LineString': lines.append(elmt.element) elmt.active = 0 elif elmt.element.geom_type=='MultiLineString': lines.extend(elmt.element) elmt.active = 0 if len(lines) > 0: self.figs.add(self.Figs(linemerge(lines))) else: print "no lines merged"
def merge_lines(lines): ''' Returns tuple of merged lines. :param lines: iterable of :class:`shapely.geometry.LineString` :returns: tuple :class:`shapely.geometry.LineString` ''' merged = linemerge(lines) if merged.geom_type == 'LineString': merged = (merged, ) else: # MultiLineString merged = tuple(merged) return merged
def get_slice(self, z_level): """Calculates the polygons in the slice for a plane.""" unsorted_lines = [] for triangle in self.ctriangles: if (triangle[2, 2] < z_level) or (triangle[0, 2] > z_level): pass elif (triangle[0, 2] < z_level) and (triangle[2, 2] > z_level): intersection = self.get_z_intersect(triangle, z_level) unsorted_lines.append(intersection) elif (triangle[0, 2] == z_level) and (triangle[2, 2] == z_level): print "WARNING: Triangle in z_level!" elif (triangle[0, 2] <= z_level) and (triangle[1, 2] > z_level): print 'TRIANGULO CON LADO EN Z' elif (triangle[1, 2] < z_level) and (triangle[2, 2] >= z_level): print 'TRIANGULO CON LADO EN Z' doubles = 0 for n_line in range(len(unsorted_lines)): unsorted_lines[n_line] = np.round(unsorted_lines[n_line],5) if np.array_equal(unsorted_lines[n_line][0], unsorted_lines[n_line][1]): doubles = doubles +1 if doubles > 0: print 'WARNING: Puntos dobles detectados' if not unsorted_lines == []: # Arrange the line segments so that each segment leads to the # nearest available segment. This is accomplished by using two # list of lines, and at each step moving the nearest available # line segment from the unsorted pile to the next slot in the # sorted pile. lines = [] for line in unsorted_lines: lines.append(geometry.LineString(line)) multiline = geometry.MultiLineString(lines) merged_line = ops.linemerge(multiline) polygons = [] try: for merged in merged_line: polygons.append(np.array(merged)) except TypeError: # If there is only one contour polygons.append(np.array(merged_line)) # for i, polygon in enumerate(polygons): # roll_point = self.get_roll_point(polygon) # if roll_point != 0: # polygons[i] = polygon[roll_point:] + polygon[:roll_point] # print 'Roll point: ' + str(roll_point) return [poly.filter_polyline(polygon, dist=0.05) for polygon in polygons] # Polygons filter else: return None
def isovalues(self, values): """return a list of multilinestring, one for each value in values""" idx = self.__meshDataProvider.triangles() vtx = self.__meshDataProvider.nodeCoord() lines = [] for value in values: lines.append([]) if self.__meshDataProvider.valueAtElement(): val = self.__meshDataProvider.elementValues() - float(value) else: val = self.__meshDataProvider.nodeValues() - float(value) # we filter triangles in which the value is negative on at least # one node and positive on at leat one node filtered = idx[numpy.logical_or( val[idx[:, 0]]*val[idx[:, 1]] <= 0, val[idx[:, 0]]*val[idx[:, 2]] <= 0 ).reshape((-1,))] # create line segments for tri in filtered: line = [] # the edges are sorted to avoid interpolation error for edge in [sorted([tri[0], tri[1]]), sorted([tri[1], tri[2]]), sorted([tri[2], tri[0]])]: if val[edge[0]]*val[edge[1]] <= 0: if val[edge[1]] != val[edge[0]]: alpha = -val[edge[0]]/(val[edge[1]] - val[edge[0]]) assert alpha >= 0 and alpha <= 1 line.append(tuple((1-alpha)*vtx[edge[0]] + alpha*vtx[edge[1]])) else: # the edge is part of the isoline print "meshlayer:isovalues: ", value, edge[0], edge[1], val[edge[0]], val[edge[1]], vtx[edge[0]], vtx[edge[1]] line.append(tuple(vtx[edge[0]])) line.append(tuple(vtx[edge[1]])) # avoiding loops l = list(set(line)) if len(l) > 1: lines[-1].append(l) if len(lines[-1]): m = linemerge([LineString(l) for l in lines[-1]]) if isinstance(m, LineString): lines[-1] = [list(m.coords)] else: assert(isinstance(m, MultiLineString)) lines[-1] = [list(l.coords) for l in m] return lines
def _geometric_process(self): if len(self._entries) != 1: merged_union = linemerge(unary_union(self._entries)) else: merged_union = MultiLineString(self._entries) self._edges = [ Edge(tuple(g.coords)) for g in merged_union.geoms ] edges = map(lambda e: e._geom, self._edges) if self._bnode: xyset = set([edge.coords[i] for edge in edges for i in (0,-1)]) self._nodes = map(lambda xy: Node(xy),xyset) if self._bface: self._faces = [Face(poly.exterior,poly.interiors) for poly in polygonize(edges)]
def intersection(self, geom): intersection_ids = list(self.index.intersection(geom.bounds)) if not intersection_ids: raise EmtpyGeometryError('No intersection or empty geometry') intersections = [] for i in intersection_ids: polygon = self.polygons[i] if polygon.contains(geom): return geom if polygon.intersects(geom): try: new_geom_part = polygon.intersection(geom) new_geom_part = filter_geometry_by_type(new_geom_part, geom.type) if new_geom_part: if len(intersection_ids) == 1: return new_geom_part if isinstance(new_geom_part, list): intersections.extend(new_geom_part) else: intersections.append(new_geom_part) except TopologicalError: pass if not intersections: raise EmtpyGeometryError('No intersection or empty geometry') # intersections from multiple sub-polygons # try to merge them back to a single geometry if geom.type.endswith('Polygon'): union = cascaded_union(list(flatten_polygons(intersections))) elif geom.type.endswith('LineString'): union = linemerge(list(flatten_linestrings(intersections))) if union.type == 'MultiLineString': union = list(union.geoms) elif geom.type == 'Point': union = intersections[0] else: log.warn('unexpexted geometry type %s', geom.type) raise EmtpyGeometryError() return union
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))
def _topological_process(self): # initialisation des arcs (géométrie calculée, autres attributs à None) init_None = dict.fromkeys(('start_node','end_node','left_face','right_face'),None) if len(self._entries) != 1: merged_union = linemerge(unary_union(self._entries)) else: merged_union = MultiLineString(self._entries) self._edges = [ Edge(tuple(g.coords),**init_None) for g in merged_union.geoms ] del merged_union # liste des géométries Shapely des Edge (arcs du graphe) et index spatial # (facilité d'écriture par la suite + fait une seule fois) edges = map(lambda e: e._geom,self._edges) edge_si = geometry_spatial_index(edges) # construction des noeuds, mise à jour des noeuds départ et fin des arcs self._nodes, already_done = list(), dict() for edge in self._edges: for i,attname in ((0,'_start_node'),(-1,'_end_node')): xy = edge._geom.coords[i] inode = already_done.get(xy,None) if inode is None: already_done[xy] = inode = len(self._nodes) self._nodes.append(Node(xy)) setattr(edge,attname,inode) del already_done # création des faces du graphe planaire self._faces = list() for polygon in polygonize(edges): new_face = Face(polygon.exterior,polygon.interiors,extring=None,intrings=list()) self._faces.append(new_face) # liste des géométries Shapely des Face (faces du graphe et index spatial) # (facilité d'écriture par la suite + fait une seule fois) faces = map(lambda pgf: pgf._geom,self._faces) face_si = geometry_spatial_index(faces) self._process_rings(edges,faces,edge_si,face_si)
def add_holders(self, ring, holder_size, min_len): x = ring.xy[0] y = ring.xy[1] X1 = x[0] Y1 = y[0] lines = [] for i in range(1,len(x)): X2 = x[i] Y2 = y[i] l = LineString( [(X1,Y1),(X2,Y2)] ) if l.length >= min_len: lp1 = (l.length/2.0) - (holder_size/2.0) lp2 = (l.length/2.0) + (holder_size/2.0) hp1 = l.interpolate(lp1) hp2 = l.interpolate(lp2) l1 = cut_line(l, lp1) l2 = cut_line(l, lp2) lines.append(l1[0]) lines.append(l2[1]) else: lines.append(l) X1=X2 Y1=Y2 ml = linemerge(lines) lines = [] if ml.geom_type == 'MultiLineString': for ls in ml: lines.append(ls) else: lines.append(ml) return lines
def transform_tags(self, osmid, tags): outtags = { 'intnames' : {}, 'level' : 35, 'top' : None} # default treatment of tags for (k,v) in tags.iteritems(): if k == 'name': outtags[k] = v elif k.startswith('name:'): outtags['intnames'][k[5:]] = v elif k == 'ref': if 'name' not in outtags: outtags['name'] = '[%s]' % v elif k == 'network': outtags['level'] = conf.TAGS_NETWORK_MAP.get(v, 35) outtags['symbol'] = symbols.get_symbol(outtags['level'], None, tags, symboltypes) cur = self.thread.cursor if 'name' not in outtags: outtags['name'] = '(%s)' % osmid if outtags['top'] is None: if 'network' in tags: top = self.db.select_one("EXECUTE get_route_top(%s, %s)", (osmid, tags['network']), cur=cur) outtags['top'] = True if (top == 0) else False else: outtags['top'] = True # finally: compute the geometry routelines = self.db.select_column("EXECUTE get_route_geometry(%s)", (osmid,), cur=cur) if routelines: outtags['geom'] = sops.linemerge(routelines) outtags['geom']._crs = int(conf.DB_SRID) # Clear elevation profile cache clearcache.clearElevationProfileCache(osmid) return outtags
def ensure_no_duplicates(shape): """ This guarantees that the submission is valid even in the hypothetical scenario where line simplification might create quasi-duplicate edges. Otherwise, this function is a no-op. """ strings = list(as_MultiLineString(shape)) edges = [] for strn in strings: for u,v in zip(strn.coords, strn.coords[1:]): edges.append((u,v)) edges = np.array(edges) edges = edges.round(1) num_edges = len(edges) edges = { tuple(sorted(map(tuple, edge))) for edge in edges } if len(edges) < num_edges: print("INFORMATION: a duplicate edge had to be removed") edges = np.array(list(edges)) return linemerge(edges) else: return shape
def join_features(features, props, buf=False): """ joins polygonal features """ from feature import MultiPolygonFeature, MultiLineFeature from shapely.ops import linemerge if len(features) == 0: return features joined = [] polygons = [] lines = [] for feat in features: if isinstance(feat, MultiPolygonFeature): polygons.append(feat.geom) elif isinstance(feat, MultiLineFeature): lines.append(feat.geom) else: joined.append(feat) # cannot join this polygons = filter(lambda x: x is not None, polygons) if len(polygons) > 0: poly = polygons[0] if buf is not False: poly = poly.buffer(buf, 4) for poly2 in polygons[1:]: if buf is not False: poly2 = poly2.buffer(buf, 4) poly = poly.union(poly2) joined.append(MultiPolygonFeature(poly, props)) if len(lines) > 0: rings = [] for line in lines: geoms = hasattr(line, 'geoms') and line.geoms or [line] rings += geoms joined.append(MultiLineFeature(linemerge(rings), props)) return joined
def get_scene_geometry(name): if not ':' in name: # Not a scene description return None geoms = [] for obj in name.split('+'): oname = obj.strip() if oname.startswith(':'): geoms.append(world.current_scene[oname[1:]]) else: scene, obj = oname.split(':', 2) oldscene = world.current_scene world.load_scene(scene) wkt = world.current_scene[obj] world.current_scene = oldscene geoms.append(wkt) if len(geoms) == 1: return geoms[0] else: return linemerge(geoms)
def transform_tags(self, osmid, tags): outtags = {"intnames": {}, "level": 25, "top": None} # default treatment of tags for (k, v) in tags.iteritems(): if k == "name": outtags[k] = v elif k.startswith("name:"): outtags["intnames"][k[5:]] = v elif k == "ref": if "name" not in outtags: outtags["name"] = "[%s]" % v elif k == "network": outtags["level"] = conf.TAGS_NETWORK_MAP.get(v, 25) outtags["symbol"] = symbols.get_symbol(outtags["level"], None, tags, symboltypes) cur = self.thread.cursor if "name" not in outtags: outtags["name"] = "(%s)" % osmid if outtags["top"] is None: if "network" in tags: top = self.db.select_one("EXECUTE get_route_top(%s, %s)", (osmid, tags["network"]), cur=cur) outtags["top"] = True if (top == 0) else False else: outtags["top"] = True # finally: compute the geometry routelines = self.db.select_column("EXECUTE get_route_geometry(%s)", (osmid,), cur=cur) if routelines: outtags["geom"] = sops.linemerge(routelines) outtags["geom"]._crs = 900913 return outtags
def dissolve_lines(self, toDissolve, outFile, attributes, multiPart): with fiona.open(toDissolve, 'r') as input: schema = input.schema crs = input.crs features = {} for i, f in enumerate(input): features[i] = [shape(f['geometry']), f['properties']] if attributes: #TODO test this if block to make it dissolves features properly by attributes param for attr in schema['properties'].keys(): if attr not in attributes: del schema['properties'][attr] attr_sets = {} for i in features.keys(): prop_list = [] for key in features[i][1].keys(): if key in attributes: prop_list.append(features[i][1][key]) attr_sets[tuple(prop_list)] = [] features[i].append(tuple(prop_list)) for i in features.keys(): attr_sets[features[i][2]].append(features[i]) del features[i][2] disjointFeatures = [] for key in attr_sets.keys(): for item in attr_sets[key]: idx = index.Index() for i in features.keys(): idx.insert(i, features[i][0].bounds, features[i]) disjointFeatures_partial = [] disjointFeatures = disjointFeatures + self.__unionIntersecting(features, idx, disjointFeatures_partial) for feature in disjointFeatures: for attr in feature[1].keys(): if attr not in attributes: del feature[1][attr] dissolveFeatures = disjointFeatures #no attributes specified, dissolve all features else: #if multiPart is True all features will be dissolve if multiPart is True: features = linemerge([geom for geom, prop in features.values()]) schema = {'geometry':features.geom_type, 'properties':{'fid':'int'}} dissolveFeatures = [(features, {'fid':1})] #if multiPart is False dissolve all features that are not disjoint elif multiPart is False: schema = {'geometry':'MultiLineString', 'properties':{'fid':'int'}} idx = index.Index() for i in features.keys(): idx.insert(i, features[i][0].bounds, features[i]) disjointFeatures = [] self.__unionIntersecting(features, idx, disjointFeatures) dissolveFeatures = [] count = 0 for geom, prop in disjointFeatures: dissolveFeatures.append((geom, {'fid':count})) count += 1 with fiona.open(outFile, 'w', 'ESRI Shapefile', crs=crs, schema=schema) as output: for geom, prop in dissolveFeatures: output.write({'geometry': mapping(geom), 'properties':prop})