Skip to content

Commit

Permalink
Merge pull request #137 from benchmark-urbanism/dev
Browse files Browse the repository at this point in the history
deduplicates non motorised edges
songololo authored Nov 30, 2024
2 parents c429f15 + 787600a commit 74677e3
Showing 21 changed files with 306 additions and 67 deletions.
Binary file modified docs/public/images/assignment.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/assignment_decomposed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/assignment_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/betas.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/graph_clean.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/graph_colour.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/graph_decomposed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/graph_dual.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/graph_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/graph_raw.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/graph_simple.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/intro_mixed_uses.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/intro_segment_harmonic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/src/pages/rustalgos/rustalgos.md
Original file line number Diff line number Diff line change
@@ -2807,12 +2807,12 @@ datapoints are not located with high spatial precision.



<span class="name">node_xys</span><span class="annotation">: list[tuple[float, float]]</span>
<span class="name">node_lives</span><span class="annotation">: list[bool]</span>




<span class="name">node_lives</span><span class="annotation">: list[bool]</span>
<span class="name">node_xys</span><span class="annotation">: list[tuple[float, float]]</span>



90 changes: 81 additions & 9 deletions docs/src/pages/tools/graphs.md
Original file line number Diff line number Diff line change
@@ -337,9 +337,9 @@ side-effects as a function of varied node intensities when computing network cen
<span class="pn">nx_multigraph</span>
</div>
<div class="param">
<span class="pn">simplify_by_angle</span>
<span class="pn">simplify_by_max_angle</span>
<span class="pc">:</span>
<span class="pa"> int = 100</span>
<span class="pa"> int = 120</span>
</div>
<div class="param">
<span class="pn">min_self_loop_length</span>
@@ -370,7 +370,7 @@ side-effects as a function of varied node intensities when computing network cen

<div class="param-set">
<div class="def">
<div class="name">simplify_by_angle</div>
<div class="name">simplify_by_max_angle</div>
<div class="type">int</div>
</div>
<div class="desc">
@@ -415,22 +415,74 @@ side-effects as a function of varied node intensities when computing network cen

<div class="function">

## simplify_line_by_angle
## nx_deduplicate_edges


<div class="content">
<span class="name">simplify_line_by_angle</span><div class="signature multiline">
<span class="name">nx_deduplicate_edges</span><div class="signature multiline">
<span class="pt">(</span>
<div class="param">
<span class="pn">coords</span>
<span class="pn">nx_multigraph</span>
</div>
<div class="param">
<span class="pn">simplify_line_angles</span>
<span class="pn">dissolve_distance</span>
<span class="pc">:</span>
<span class="pa"> int = 12</span>
</div>
<div class="param">
<span class="pn">max_ang_diff</span>
<span class="pc">:</span>
<span class="pa"> int = 20</span>
</div>
<span class="pt">)</span>
</div>
</div>


Deduplicates non-motorised edges where parallel to nearby motorised edges.
### Parameters
<div class="param-set">
<div class="def">
<div class="name">nx_multigraph</div>
<div class="type">MultiGraph</div>
</div>
<div class="desc">

A `networkX` `MultiGraph` in a projected coordinate system, containing `x` and `y` node attributes, and `geom` edge attributes containing `LineString` geoms.</div>
</div>

<div class="param-set">
<div class="def">
<div class="name">dissolve_distance</div>
<div class="type">int</div>
</div>
<div class="desc">

A distance to use when searching for adjacent edges. 12m by default.</div>
</div>

<div class="param-set">
<div class="def">
<div class="name">max_ang_diff</div>
<div class="type">int</div>
</div>
<div class="desc">

Only count a nearby adjacent edge as duplicitous if the angular difference between edges is less than `max_ang_diff`. 20 degrees by default.</div>
</div>

### Returns
<div class="param-set">
<div class="def">
<div class="name"></div>
<div class="type">MultiGraph</div>
</div>
<div class="desc">

A `networkX` graph. The nodes will have a new `weight` parameter indicating the node's contribution given the locally 'dissolved' context.</div>
</div>


</div>


@@ -491,7 +543,7 @@ side-effects as a function of varied node intensities when computing network cen
<span class="pa"> bool = False</span>
</div>
<div class="param">
<span class="pn">simplify_line_angles</span>
<span class="pn">simplify_by_max_angle</span>
<span class="pc">:</span>
<span class="pa"> int | None = None</span>
</div>
@@ -608,6 +660,16 @@ side-effects as a function of varied node intensities when computing network cen
Whether to only merge edges with shared OSM `name` or `ref` tags. False by default. Requires graph prepared with via [`io.osm_graph_from_poly`](/io#osm-graph-from-poly).</div>
</div>

<div class="param-set">
<div class="def">
<div class="name">simplify_by_max_angle</div>
<div class="type">int</div>
</div>
<div class="desc">

The optional maximum angle to permit for a given edge. Angles greater than this will be reduced.</div>
</div>

### Returns
<div class="param-set">
<div class="def">
@@ -731,7 +793,7 @@ side-effects as a function of varied node intensities when computing network cen
<span class="pa"> bool = False</span>
</div>
<div class="param">
<span class="pn">simplify_line_angles</span>
<span class="pn">simplify_by_max_angle</span>
<span class="pc">:</span>
<span class="pa"> int | None = None</span>
</div>
@@ -850,6 +912,16 @@ side-effects as a function of varied node intensities when computing network cen
Whether to automatically squash new node pairings resulting from splitting a nearby edge. If set to `False` then a line will be added instead. Defaults to `True`.</div>
</div>

<div class="param-set">
<div class="def">
<div class="name">simplify_by_max_angle</div>
<div class="type">int</div>
</div>
<div class="desc">

The optional maximum angle to permit for a given edge. Angles greater than this will be reduced.</div>
</div>

### Returns
<div class="param-set">
<div class="def">
2 changes: 1 addition & 1 deletion docs/src/pages/tools/io.md
Original file line number Diff line number Diff line change
@@ -354,7 +354,7 @@ builds a graph automatically.
<div class="param">
<span class="pn">final_clean_distances</span>
<span class="pc">:</span>
<span class="pa"> tuple[int, ...] = (6, 12)</span>
<span class="pa"> tuple[int, ...] = (5, 10)</span>
</div>
<div class="param">
<span class="pn">remove_disconnected</span>
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "cityseer"
version = '4.16.27'
version = '4.17.0'
description = "Computational tools for network-based pedestrian-scale urban analysis"
readme = "README.md"
requires-python = ">=3.10, <3.14"
193 changes: 157 additions & 36 deletions pysrc/cityseer/tools/graphs.py
Original file line number Diff line number Diff line change
@@ -529,9 +529,38 @@ def nx_snap_endpoints(nx_multigraph: MultiGraph) -> MultiGraph:
return g_multi_copy


def _simplify_line_by_max_angle(coords, max_angle):
# continue simplifying until no angles exceed the threshold
while True:
angles_exceeding_threshold = False
# start with the first point
new_coords = [coords[0]]
# iterate through the points
for i in range(1, len(coords) - 1):
p1, p2, p3 = coords[i - 1], coords[i], coords[i + 1]
angle = util.measure_coords_angle(p1, p2, p3)
# if angle exceeds the threshold
if angle > max_angle:
angles_exceeding_threshold = True
# skip adding this point
continue
# otherwise, keep the point
new_coords.append(p2)
# always keep the last point
new_coords.append(coords[-1])
# exit loop if no angles exceeded the threshold
if not angles_exceeding_threshold:
break
# update coords with modified list
coords = new_coords

# Return a new LineString with simplified coordinates
return new_coords


def nx_iron_edges(
nx_multigraph: MultiGraph,
simplify_by_angle: int = 100,
simplify_by_max_angle: int = 120,
min_self_loop_length: int = 100,
max_foot_tunnel_length: int = 50,
) -> MultiGraph:
@@ -543,7 +572,7 @@ def nx_iron_edges(
nx_multigraph: MultiGraph
A `networkX` `MultiGraph` in a projected coordinate system, containing `x` and `y` node attributes, and `geom`
edge attributes containing `LineString` geoms.
simplify_by_angle: int
simplify_by_max_angle: int
The maximum angle to permit for a given edge. Angles greater than this will be reduced.
min_self_loop_length: int
Maximum self loop length to permit for a given edge.
@@ -595,7 +624,7 @@ def nx_iron_edges(
remove_edges.append((start_nd_key, end_nd_key, edge_idx))
continue
# simplify
line_coords = simplify_line_by_angle(edge_geom.coords, simplify_by_angle)
line_coords = _simplify_line_by_max_angle(edge_geom.coords, simplify_by_max_angle)
g_multi_copy[start_nd_key][end_nd_key][edge_idx]["geom"] = geometry.LineString(line_coords)
g_multi_copy.remove_edges_from(remove_edges)
# straightening parallel edges can create duplicates
@@ -604,40 +633,131 @@ def nx_iron_edges(
return g_multi_copy


def simplify_line_by_angle(coords, simplify_line_angles):
# Continue simplifying until no angles exceed the threshold
while True:
angles_exceeding_threshold = False
new_coords = [coords[0]] # Start with the first point
_MOTORISED_HWYS = set(
[
"motorway",
"motorway_link",
"trunk",
"trunk_link",
"primary",
"primary_link",
"secondary",
"secondary_link",
"tertiary",
"tertiary_link",
"residential",
"living_street",
# "service", # intentional
]
)


def nx_deduplicate_edges(
nx_multigraph: MultiGraph,
dissolve_distance: int = 12,
max_ang_diff: int = 20,
) -> MultiGraph:
"""
Deduplicates non-motorised edges where parallel to nearby motorised edges.
# Iterate through the points to calculate angles
for i in range(1, len(coords) - 1):
p1, p2, p3 = coords[i - 1], coords[i], coords[i + 1]
angle = util.measure_coords_angle(p1, p2, p3)
Remove non-motorised edges where adjacent to motorised edges. This helps to simplify complex network representations
for the purpose of network centralities or visualisation. Short dead-end non-motorised edges falling within the
specified dissolve distance will also be removed.
# If angle exceeds the threshold, mark the middle point for deletion
if angle > simplify_line_angles:
angles_exceeding_threshold = True
continue # Skip adding this point
new_coords.append(p2) # Otherwise, keep the point
Parameters
----------
nx_multigraph: MultiGraph
A `networkX` `MultiGraph` in a projected coordinate system, containing `x` and `y` node attributes, and `geom`
edge attributes containing `LineString` geoms.
dissolve_distance: int
A distance to use when searching for adjacent edges. 12m by default.
max_ang_diff: int
Only count a nearby adjacent edge as duplicitous if the angular difference between edges is less than
`max_ang_diff`. 20 degrees by default.
new_coords.append(coords[-1]) # Always keep the last point
Returns
-------
MultiGraph
A `networkX` graph with non-motorised edges removed if parallel to motorised edges.
# Check if we made any modifications
if not angles_exceeding_threshold:
break # Exit loop if no angles exceeded the threshold
coords = new_coords # Update coords with modified list
"""
g_multi_copy: MultiGraph = nx_multigraph.copy()
# generate STR tree
edges_tree, edge_lookups = util.create_edges_strtree(g_multi_copy)
# edges to remove
edges_to_remove = set()
# first iterate edges to save number of iters
for start_nd_key, end_nd_key, edge_idx, edge_data in tqdm(
g_multi_copy.edges(data=True, keys=True), disable=config.QUIET_MODE
):
# find nearby edges
edge_geom = edge_data["geom"]
# edge_hierarchy = len(_ROAD_HIERARCHY)
candidate = False
for hwy_key in edge_data["highways"]:
if hwy_key in _MOTORISED_HWYS:
candidate = True
break
if candidate is False:
continue
edges_hits: list[int] = edges_tree.query(
edge_geom,
predicate="dwithin",
distance=dissolve_distance,
) # type: ignore
# buffer once outside of loop
edge_geom_buff = edge_geom.buffer(dissolve_distance, cap_style=geometry.CAP_STYLE.flat)
# review hits
for edge_hit_idx in edges_hits:
edge_lookup = edge_lookups[edge_hit_idx]
nearby_start_nd_key = edge_lookup["start_nd_key"]
nearby_end_nd_key = edge_lookup["end_nd_key"]
nearby_edge_idx = edge_lookup["edge_idx"]
# continue if already removed
if (nearby_start_nd_key, nearby_end_nd_key, nearby_edge_idx) in edges_to_remove:
continue
# or current edge
if nearby_start_nd_key == start_nd_key and nearby_end_nd_key == end_nd_key and edge_idx == nearby_edge_idx:
continue
# get edge data
nearby_edge_data = g_multi_copy[nearby_start_nd_key][nearby_end_nd_key][nearby_edge_idx]
# only remove if non motorised
bail = False
for nearby_hwy_key in nearby_edge_data["highways"]:
if nearby_hwy_key in _MOTORISED_HWYS:
bail = True
break
if bail is True:
continue
# fetch geom and check for intersection
nearby_edge_geom: geometry.LineString = nearby_edge_data["geom"]
# remove contained geoms but only if dead-ends
if edge_geom_buff.contains(nearby_edge_geom) and (
nx.degree(nx_multigraph, nearby_start_nd_key) == 1 or nx.degree(nx_multigraph, nearby_end_nd_key) == 1
):
edges_to_remove.add((nearby_start_nd_key, nearby_end_nd_key, nearby_edge_idx))
else:
edge_itx = nearby_edge_geom.intersection(edge_geom_buff)
if edge_itx and edge_itx.geom_type == "LineString" and edge_itx.length > 5:
# check for angle
ang_diff = util.measure_angle_diff_betw_linestrings(edge_geom.coords, edge_itx.coords)
if ang_diff < max_ang_diff:
# remove if duplicitous
edges_to_remove.add((nearby_start_nd_key, nearby_end_nd_key, nearby_edge_idx))
# remove edges from graph
g_multi_copy.remove_edges_from(edges_to_remove)
# remove orphaned nodes
g_multi_copy = nx_remove_filler_nodes(g_multi_copy)

# Return a new LineString with simplified coordinates
return new_coords
return g_multi_copy


def _squash_adjacent(
nx_multigraph: MultiGraph,
node_group: set[NodeKey],
centroid_by_itx: bool,
prioritise_by_hwy_tag: bool,
simplify_line_angles: int | None = None,
simplify_by_max_angle: int | None = None,
) -> MultiGraph:
"""
Squash nodes from a specified node group down to a new node.
@@ -797,8 +917,8 @@ def _squash_adjacent(
else:
target_nd_key = nb_nd_key
# simplify to handle new kinks
if simplify_line_angles is not None:
line_coords = simplify_line_by_angle(line_coords, simplify_line_angles)
if simplify_by_max_angle is not None:
line_coords = _simplify_line_by_max_angle(line_coords, simplify_by_max_angle)
# build the new geom
new_edge_geom = geometry.LineString(line_coords)
if new_edge_geom.length == 0:
@@ -854,7 +974,7 @@ def nx_consolidate_nodes(
contains_buffer_dist: int = 25,
osm_hwy_target_tags: list[str] | None = None,
osm_matched_tags_only: bool = False,
simplify_line_angles: int | None = None,
simplify_by_max_angle: int | None = None,
) -> MultiGraph:
"""
Consolidates nodes if they are within a buffer distance of each other.
@@ -906,6 +1026,8 @@ def nx_consolidate_nodes(
osm_matched_tags_only: bool
Whether to only merge edges with shared OSM `name` or `ref` tags. False by default. Requires graph prepared with
via [`io.osm_graph_from_poly`](/io#osm-graph-from-poly).
simplify_by_max_angle: int
The optional maximum angle to permit for a given edge. Angles greater than this will be reduced.
Returns
-------
@@ -1038,7 +1160,7 @@ def recursive_squash(
node_group,
centroid_by_itx=centroid_by_itx,
prioritise_by_hwy_tag=prioritise_by_hwy_tag,
simplify_line_angles=simplify_line_angles,
simplify_by_max_angle=simplify_by_max_angle,
)
# remove parallel edges resulting from squashing nodes
_multi_graph = nx_merge_parallel_edges(
@@ -1171,7 +1293,7 @@ def nx_split_opposing_geoms(
max_node_degree: int | None = None,
squash_nodes: bool = True,
centroid_by_itx: bool = False,
simplify_line_angles: int | None = None,
simplify_by_max_angle: int | None = None,
) -> nx.MultiGraph:
"""
Split edges in near proximity to nodes, then weld the resultant node group together, updating edges in the process.
@@ -1223,6 +1345,8 @@ def nx_split_opposing_geoms(
squash_nodes: bool
Whether to automatically squash new node pairings resulting from splitting a nearby edge. If set to `False` then
a line will be added instead. Defaults to `True`.
simplify_by_max_angle: int
The optional maximum angle to permit for a given edge. Angles greater than this will be reduced.
Returns
-------
@@ -1349,9 +1473,6 @@ def recurse_child_keys(
# don't split on tunnels
if "is_tunnel" in edge_data and edge_data["is_tunnel"] is True:
continue
# don't split on bridges
if "is_bridge" in edge_data and edge_data["is_bridge"] is True:
continue
# level tags
if nb_levels_tags:
# only split on ground levels
@@ -1477,7 +1598,7 @@ def recurse_child_keys(
node_group,
centroid_by_itx=centroid_by_itx,
prioritise_by_hwy_tag=prioritise_by_hwy_tag,
simplify_line_angles=simplify_line_angles,
simplify_by_max_angle=simplify_by_max_angle,
)
else:
for node_group in node_groups:
@@ -1944,8 +2065,8 @@ def nx_weight_by_dissolved_edges(
]:
continue
# get linestring
edge_data = g_multi_copy[nearby_start_nd_key][nearby_end_nd_key][nearby_edge_idx]
nearby_edge_geom: geometry.LineString = edge_data["geom"]
nearby_edge_data = g_multi_copy[nearby_start_nd_key][nearby_end_nd_key][nearby_edge_idx]
nearby_edge_geom: geometry.LineString = nearby_edge_data["geom"]
# get angular difference
ang_diff = util.measure_angle_diff_betw_linestrings(edge_geom.coords, nearby_edge_geom.coords)
if ang_diff > max_ang_diff:
80 changes: 63 additions & 17 deletions pysrc/cityseer/tools/io.py
Original file line number Diff line number Diff line change
@@ -256,6 +256,8 @@ def _auto_clean_network(
green_footways: bool = False,
green_service_roads: bool = False,
) -> nx.MultiGraph:
# deduplicate by hierarchy
G = graphs.nx_deduplicate_edges(G)
# parks
parks_gdf = ox.features_from_polygon(
geom_wgs,
@@ -326,9 +328,9 @@ def _auto_clean_network(
G.remove_edges_from(remove_edges)
# remove disconnected components
G = graphs.nx_remove_dangling_nodes(G, despine=0, remove_disconnected=remove_disconnected)
# clean by highway types - leave motorway as is
# clean by highway types - leave motorways alone
# split only for a given type at a time
for dist, tags, simplify_line_angles in (
for dist, tags, max_angle in (
(28, ["trunk"], 45),
(24, ["primary"], 45),
(20, ["secondary"], 45),
@@ -342,9 +344,10 @@ def _auto_clean_network(
osm_hwy_target_tags=tags,
osm_matched_tags_only=True,
prioritise_by_hwy_tag=True,
simplify_line_angles=simplify_line_angles,
simplify_by_max_angle=max_angle,
)
for dist, tags, simplify_line_angles in (
# consolidate
for dist, tags, max_angle in (
(28, ["trunk"], 95),
(24, ["trunk", "primary"], 95),
(20, ["trunk", "primary", "secondary"], 95),
@@ -358,36 +361,76 @@ def _auto_clean_network(
osm_hwy_target_tags=tags,
osm_matched_tags_only=True,
prioritise_by_hwy_tag=True,
simplify_line_angles=simplify_line_angles,
simplify_by_max_angle=max_angle,
)
G = graphs.nx_remove_filler_nodes(G)
# snap gapped endings - don't clean danglers before this
G = graphs.nx_snap_gapped_endings(G, buffer_dist=20)
G = graphs.nx_snap_gapped_endings(
G,
osm_hwy_target_tags=[
"residential",
"living_street",
# "service", # intentionally omitted - e.g. parking lots
"cycleway",
"bridleway",
"pedestrian",
"steps",
"footway",
"footway_green",
"footway_pedestrian", # plazas
"path",
],
buffer_dist=20,
)
# snap gapped endings to roads - don't clean danglers before this
# look for degree 1 dead-ends and link to nearby edges
G = graphs.nx_split_opposing_geoms(
G,
buffer_dist=25,
buffer_dist=20,
osm_hwy_target_tags=[
# "trunk", # intentionally omitted
"primary",
"primary_link",
"secondary",
"secondary_link",
"tertiary",
"tertiary_link",
"residential",
"living_street",
# "service", # intentionally omitted - e.g. parking lots
"cycleway",
"bridleway",
"pedestrian",
"steps",
"footway",
"footway_green",
"footway_pedestrian", # plazas
"path",
],
min_node_degree=1,
max_node_degree=1,
squash_nodes=False,
)
# remove danglers
G = graphs.nx_remove_dangling_nodes(G, despine=40)
# do smaller scale cleaning
simplify_angles = 95
max_angle = 120 # rue de nevers in Paris
for dist in final_clean_distances:
G = graphs.nx_split_opposing_geoms(
G,
buffer_dist=dist,
squash_nodes=True,
centroid_by_itx=True,
osm_hwy_target_tags=[
# "trunk",
# "primary",
# "secondary",
# "tertiary",
# "trunk", # intentionally omitted
"primary",
"primary_link",
"secondary",
"secondary_link",
"tertiary",
"tertiary_link",
"residential",
"living_street",
"service",
"cycleway",
"bridleway",
@@ -396,11 +439,10 @@ def _auto_clean_network(
"footway",
"footway_pedestrian", # plazas
"path",
"living_street",
"unclassified",
],
prioritise_by_hwy_tag=True,
simplify_line_angles=simplify_angles,
simplify_by_max_angle=max_angle,
)
G = graphs.nx_consolidate_nodes(
G,
@@ -409,10 +451,15 @@ def _auto_clean_network(
centroid_by_itx=True,
osm_hwy_target_tags=[
"trunk",
"trunk_link",
"primary",
"primary_link",
"secondary",
"secondary_link",
"tertiary",
"tertiary_link",
"residential",
"living_street",
"service",
"cycleway",
"bridleway",
@@ -421,11 +468,10 @@ def _auto_clean_network(
"footway",
"footway_pedestrian", # plazas
"path",
"living_street",
"unclassified",
],
prioritise_by_hwy_tag=True,
simplify_line_angles=simplify_angles,
simplify_by_max_angle=max_angle,
)
G = graphs.nx_remove_filler_nodes(G)
G = graphs.nx_merge_parallel_edges(G, merge_edges_by_midline=True, contains_buffer_dist=50)
@@ -442,7 +488,7 @@ def osm_graph_from_poly(
to_crs_code: int | str | None = None,
custom_request: str | None = None,
simplify: bool = True,
final_clean_distances: tuple[int, ...] = (6, 12),
final_clean_distances: tuple[int, ...] = (5, 10),
remove_disconnected: int = 100,
cycleways: bool = True,
busways: bool = False,
2 changes: 1 addition & 1 deletion tests/tools/test_graphs.py
Original file line number Diff line number Diff line change
@@ -462,7 +462,7 @@ def test_nx_iron_edges():
out_geom = nx_out[0][1][0]["geom"]
assert list(out_geom.coords) == [(0.0, 0.0), (0.0, 50.0), (50.0, 50.0), (50.0, 100.0)]
# 2 sharply jogged line should be simplified
line_geom = geometry.LineString([[0, 0], [50, 0], [75, 5], [75, 0]])
line_geom = geometry.LineString([[0, 0], [50, 0], [75, 20], [75, 0]])
nx_multi[0][1][0]["geom"] = line_geom
nx_out = graphs.nx_iron_edges(nx_multi)
out_geom = nx_out[0][1][0]["geom"]

0 comments on commit 74677e3

Please sign in to comment.