Update threaded script, try to reduce multipolygons in geojson
This commit is contained in:
parent
693c40302d
commit
a1521f4a47
95
shp-to-geojson.py
Normal file
95
shp-to-geojson.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import geopandas as gpd
|
||||||
|
from shapely.geometry import LineString, MultiLineString, Polygon, MultiPolygon
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
df = gpd.read_file('original data/Sumter/RoadCenterlines_041125.shp.zip') #, crs=2237 NAD83 / Florida West (ftUS)
|
||||||
|
df = df.to_crs(4326) # Convert to WGS 84
|
||||||
|
|
||||||
|
def convert_to_linestrings(geom):
|
||||||
|
"""Convert any geometry to a list of LineStrings"""
|
||||||
|
linestrings = []
|
||||||
|
|
||||||
|
if geom is None or geom.is_empty:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# If it's already a LineString, just return it
|
||||||
|
if isinstance(geom, LineString):
|
||||||
|
linestrings.append(geom)
|
||||||
|
|
||||||
|
# If it's a MultiLineString, extract all LineStrings
|
||||||
|
elif isinstance(geom, MultiLineString):
|
||||||
|
for line in geom.geoms:
|
||||||
|
linestrings.append(line)
|
||||||
|
|
||||||
|
# If it's a Polygon, convert boundary to LineString(s)
|
||||||
|
elif isinstance(geom, Polygon):
|
||||||
|
# Exterior boundary
|
||||||
|
if not geom.exterior.is_empty:
|
||||||
|
linestrings.append(LineString(geom.exterior.coords))
|
||||||
|
# Interior boundaries (holes)
|
||||||
|
for interior in geom.interiors:
|
||||||
|
if not interior.is_empty:
|
||||||
|
linestrings.append(LineString(interior.coords))
|
||||||
|
|
||||||
|
# If it's a MultiPolygon, process each polygon
|
||||||
|
elif isinstance(geom, MultiPolygon):
|
||||||
|
for poly in geom.geoms:
|
||||||
|
# Exterior boundary
|
||||||
|
if not poly.exterior.is_empty:
|
||||||
|
linestrings.append(LineString(poly.exterior.coords))
|
||||||
|
# Interior boundaries (holes)
|
||||||
|
for interior in poly.interiors:
|
||||||
|
if not interior.is_empty:
|
||||||
|
linestrings.append(LineString(interior.coords))
|
||||||
|
|
||||||
|
return linestrings
|
||||||
|
|
||||||
|
def explode_linestring(linestring):
|
||||||
|
"""Convert a LineString into individual segments"""
|
||||||
|
if linestring is None or linestring.is_empty:
|
||||||
|
return []
|
||||||
|
|
||||||
|
coords = list(linestring.coords)
|
||||||
|
segments = []
|
||||||
|
|
||||||
|
for i in range(len(coords) - 1):
|
||||||
|
segment = LineString([coords[i], coords[i + 1]])
|
||||||
|
segments.append(segment)
|
||||||
|
|
||||||
|
return segments
|
||||||
|
|
||||||
|
# Convert all geometries to LineStrings first
|
||||||
|
df['linestrings'] = df.geometry.apply(convert_to_linestrings)
|
||||||
|
|
||||||
|
# Explode to get one row per LineString
|
||||||
|
df_exploded = df.explode('linestrings')
|
||||||
|
|
||||||
|
# Filter out rows with empty linestrings
|
||||||
|
df_exploded = df_exploded[df_exploded['linestrings'].notna()]
|
||||||
|
df_exploded = df_exploded[~df_exploded['linestrings'].apply(lambda x: x.is_empty if x is not None else True)]
|
||||||
|
|
||||||
|
# Now explode each LineString into segments
|
||||||
|
df_exploded['segments'] = df_exploded['linestrings'].apply(explode_linestring)
|
||||||
|
|
||||||
|
# Explode segments
|
||||||
|
df_final = df_exploded.explode('segments')
|
||||||
|
|
||||||
|
# Filter out empty segments
|
||||||
|
df_final = df_final[df_final['segments'].notna()]
|
||||||
|
df_final = df_final[~df_final['segments'].apply(lambda x: x.is_empty if x is not None else True)]
|
||||||
|
|
||||||
|
# Create final GeoDataFrame with segments as geometry
|
||||||
|
dfline = gpd.GeoDataFrame(
|
||||||
|
data=df_final.drop(['geometry', 'linestrings', 'segments'], axis=1),
|
||||||
|
geometry=df_final['segments'],
|
||||||
|
crs=df.crs
|
||||||
|
)
|
||||||
|
|
||||||
|
# Reset index
|
||||||
|
dfline = dfline.reset_index(drop=True)
|
||||||
|
|
||||||
|
# Save to GeoJSON
|
||||||
|
dfline.to_file('original data/Sumter/RoadCenterlines_041125.geojson', driver='GeoJSON')
|
||||||
|
|
||||||
|
print(f"Converted {len(df)} original features to {len(dfline)} line segments")
|
||||||
|
print(f"Geometry types in output: {dfline.geometry.geom_type.value_counts()}")
|
12
threaded.py
12
threaded.py
@ -32,6 +32,13 @@ qgisfunctions = importlib.import_module("qgis-functions")
|
|||||||
# Suppress warnings for cleaner output
|
# Suppress warnings for cleaner output
|
||||||
warnings.filterwarnings('ignore')
|
warnings.filterwarnings('ignore')
|
||||||
|
|
||||||
|
import re
|
||||||
|
def titlecase(s):
|
||||||
|
return re.sub(
|
||||||
|
r"[A-Za-z]+('[A-Za-z]+)?",
|
||||||
|
lambda word: word.group(0).capitalize(),
|
||||||
|
s)
|
||||||
|
|
||||||
class RoadComparator:
|
class RoadComparator:
|
||||||
def __init__(self, tolerance_feet: float = 50.0, min_gap_length_feet: float = 100.0,
|
def __init__(self, tolerance_feet: float = 50.0, min_gap_length_feet: float = 100.0,
|
||||||
n_jobs: int = None, chunk_size: int = 1000):
|
n_jobs: int = None, chunk_size: int = 1000):
|
||||||
@ -308,11 +315,9 @@ class RoadComparator:
|
|||||||
'surface': 'asphalt'
|
'surface': 'asphalt'
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Added: "+properties['name'])
|
|
||||||
|
|
||||||
for key, value in original_properties.items():
|
for key, value in original_properties.items():
|
||||||
if key == 'NAME':
|
if key == 'NAME':
|
||||||
properties['name'] = qgisfunctions.formatstreet(str(value)).title() if value is not None else None
|
properties['name'] = titlecase(qgisfunctions.formatstreet(value,None,None)) if value is not None else None
|
||||||
elif key == 'SpeedLimit':
|
elif key == 'SpeedLimit':
|
||||||
properties['maxspeed'] = f"{value} mph" if value is not None else None
|
properties['maxspeed'] = f"{value} mph" if value is not None else None
|
||||||
elif key == 'RoadClass':
|
elif key == 'RoadClass':
|
||||||
@ -333,6 +338,7 @@ class RoadComparator:
|
|||||||
})
|
})
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
continue # Skip problematic geometries
|
continue # Skip problematic geometries
|
||||||
|
|
||||||
return added_roads
|
return added_roads
|
||||||
|
Loading…
x
Reference in New Issue
Block a user