def vector_clean(data, tolerance=0): """Cleans the vector data of unnecessary clutter such as repeat points or closely related points within the distance specified in the 'tolerance' parameter. Also tries to fix any broken geometries, dropping any unfixable ones. Adds the resulting cleaned data to the layers list. """ # create new file outfile = GeoTable() outfile.fields = list(data.fields) # clean for feat in data: shapelyobj = geoj2shapely(feat.geometry) # try fixing invalid geoms if not shapelyobj.is_valid: if "Polygon" in shapelyobj.type: # fix bowtie polygons shapelyobj = shapelyobj.buffer(0.0) # remove repeat points (tolerance=0) # (and optionally smooth out complex shapes, tolerance >= 1) shapelyobj = shapelyobj.simplify(tolerance) # if still invalid, do not add to output if not shapelyobj.is_valid: continue # write to file geoj = shapely2geoj(shapelyobj) outfile.add_feature(feat.row, geoj) return outfile
def _to_centroids(data): """create one centroid point for each multi geometry part""" # create new file outfile = GeoTable() outfile.fields = list(data.fields) # loop features for feat in data: if feat.geometry["type"] != "Point": shapelypoint = geoj2shapely(feat.geometry).centroid geoj = shapely2geoj(shapelypoint) outfile.add_feature(feat.row, geoj) return outfile
def vector_buffer(data, dist_expression): # buffer and change each geojson dict in-place new = GeoTable() new.fields = list(data.fields) for feat in data: geom = geoj2shapely(feat.geometry) dist = eval(dist_expression) buffered = geom.buffer(dist) if not buffered.is_empty: geoj = shapely2geoj(buffered) geoj["type"] = buffered.type new.add_feature(feat.row, geoj) # change data type to polygon new.type = "Polygon" return new
def _to_multicentroids(data): """create multiple centroid points for each multi geometry part""" # create new file outfile = GeoTable() outfile.fields = list(data.fields) # loop features if "LineString" in data.type or "Polygon" in data.type: for feat in data: if "Multi" in feat.geometry["type"]: multishape = geoj2shapely(feat.geometry) for geom in multishape.geoms: shapelypoint = geom.centroid geoj = shapely2geoj(shapelypoint) outfile.add_feature(feat.row, geoj) else: shapelypoint = geoj2shapely(feat.geometry).centroid geoj = shapely2geoj(shapelypoint) outfile.add_feature(feat.row, geoj) return outfile else: return data.copy()
def vector_to_polygons(data, polytype="convex hull"): # create new file outfile = GeoTable() outfile.fields = list(data.fields) if polytype == "convex hull": for feat in data: shapelygeom = geoj2shapely(feat.geometry) convex = shapelygeom.convex_hull geoj = shapely2geoj(convex) # sometimes the convex hull is only a line or point # but we cannot mix shapetypes, so exclude those if geoj["type"] == "Polygon": outfile.add_feature(feat.row, geoj) return outfile elif polytype == "delauney triangles": if "Point" in data.type: def get_flattened_points(): for feat in data: if "Multi" in feat.geometry["type"]: for point in feat.geometry["coordinates"]: yield point else: yield feat.geometry["coordinates"] triangles = pytess.triangulate(get_flattened_points()) # triangle polygons are between multiple existing points, # so do not inherit any attributes for tri in triangles: geoj = {"type": "Polygon", "coordinates": [tri] } row = ["" for field in outfile.fields] outfile.add_feature(row, geoj) return outfile else: raise Exception("Delauney triangles can only be made from point data") elif polytype == "voronoi polygons": if "Point" in data.type: def get_flattened_points(): for feat in data: if "Multi" in feat.geometry["type"]: for point in feat.geometry["coordinates"]: yield point else: yield feat.geometry["coordinates"] results = pytess.voronoi(get_flattened_points()) # return new file with polygon geometries for midpoint,polygon in results: geoj = {"type": "Polygon", "coordinates": [polygon] } row = ["" for field in outfile.fields] outfile.add_feature(row, geoj) return outfile else: raise Exception("Voronoi polygons can only be made from point data") elif polytype == "enclose lines": if "LineString" in data.type: shapelylines = (geoj2shapely(feat.geometry) for feat in data) for polygon in shapely.ops.polygonize(shapelylines): geoj = shapely2geoj(polygon) row = ["" for field in outfile.fields] outfile.add_feature(row, geoj) return outfile else: raise Exception("Enclose lines can only be done on line data")