Skip to content

Commit

Permalink
dials back iron_edges; reintroduces auto clean options
Browse files Browse the repository at this point in the history
  • Loading branch information
songololo committed Nov 17, 2023
1 parent 7851522 commit ce3fe72
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 38 deletions.
6 changes: 3 additions & 3 deletions docs/src/pages/rustalgos/rustalgos.md
Original file line number Diff line number Diff line change
Expand Up @@ -2726,17 +2726,17 @@ 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_xs</span><span class="annotation">: list[float]</span>




<span class="name">node_xs</span><span class="annotation">: list[float]</span>
<span class="name">node_ys</span><span class="annotation">: list[float]</span>




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



Expand Down
4 changes: 2 additions & 2 deletions docs/src/pages/tools/graphs.md
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ side-effects as a function of varied node intensities when computing network cen
<div class="param">
<span class="pn">contains_buffer_dist</span>
<span class="pc">:</span>
<span class="pa"> int = 40</span>
<span class="pa"> int = 25</span>
</div>
<span class="pt">)</span>
</div>
Expand Down Expand Up @@ -541,7 +541,7 @@ side-effects as a function of varied node intensities when computing network cen
<div class="param">
<span class="pn">contains_buffer_dist</span>
<span class="pc">:</span>
<span class="pa"> float = 40</span>
<span class="pa"> float = 25</span>
</div>
<span class="pt">)</span>
</div>
Expand Down
45 changes: 45 additions & 0 deletions docs/src/pages/tools/io.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,21 @@ builds a graph automatically.
<span class="pc">:</span>
<span class="pa"> bool = True</span>
</div>
<div class="param">
<span class="pn">crawl_consolidate_dist</span>
<span class="pc">:</span>
<span class="pa"> int = 12</span>
</div>
<div class="param">
<span class="pn">parallel_consolidate_dist</span>
<span class="pc">:</span>
<span class="pa"> int = 15</span>
</div>
<div class="param">
<span class="pn">iron_edges</span>
<span class="pc">:</span>
<span class="pa"> bool = True</span>
</div>
<div class="param">
<span class="pn">timeout</span>
<span class="pc">:</span>
Expand Down Expand Up @@ -452,6 +467,36 @@ builds a graph automatically.
Whether to automatically simplify the OSM graph. Set to False for manual cleaning.</div>
</div>

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

The buffer distance to use when doing the initial round of node consolidation. This consolidation step crawls neighbouring nodes to find groups of adjacent nodes within the buffer distance of each other.</div>
</div>

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

The buffer distance to use when looking for adjacent parallel roadways.</div>
</div>

<div class="param-set">
<div class="def">
<div class="name">iron_edges</div>
<div class="type">bool</div>
</div>
<div class="desc">

Whether to iron the edges.</div>
</div>

<div class="param-set">
<div class="def">
<div class="name">timeout</div>
Expand Down
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.3.4'
version = '4.4.0'
description = "Computational tools for network-based pedestrian-scale urban analysis"
readme = "README.md"
requires-python = ">=3.10, <3.12"
Expand Down
49 changes: 20 additions & 29 deletions pysrc/cityseer/tools/graphs.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
logger = logging.getLogger(__name__)


def nx_simple_geoms(nx_multigraph: MultiGraph, simplify_dist: int = 5) -> MultiGraph:
def nx_simple_geoms(nx_multigraph: MultiGraph) -> MultiGraph:
"""
Inferring geometries from node to node.
Expand All @@ -38,8 +38,6 @@ def nx_simple_geoms(nx_multigraph: MultiGraph, simplify_dist: int = 5) -> MultiG
----------
nx_multigraph: MultiGraph
A `networkX` `MultiGraph` with `x` and `y` node attributes.
simplify_dist: int
Simplification distance to use for simplifying the linestring geometries.
Returns
-------
Expand Down Expand Up @@ -75,7 +73,6 @@ def _process_node(nd_key: NodeKey):
s_x, s_y = _process_node(start_nd_key)
e_x, e_y = _process_node(end_nd_key)
seg = geometry.LineString([[s_x, s_y], [e_x, e_y]])
seg: geometry.LineString = seg.simplify(simplify_dist)
if start_nd_key == end_nd_key and seg.length == 0:
remove_edges.append((start_nd_key, end_nd_key, edge_idx))
else:
Expand Down Expand Up @@ -468,31 +465,25 @@ def nx_iron_edges(
if start_nd_key == end_nd_key:
continue
edge_geom: geometry.LineString = edge_data["geom"]
start_point = edge_geom.coords[0]
end_point = edge_geom.coords[-1]
simpl_edge_geom = geometry.LineString([start_point, end_point])
max_angle = util.measure_max_angle(edge_geom.coords)
total_angle = util.measure_cumulative_angle(edge_geom.coords)
# for all changes - write over edge_geom and also update in place
# remove erroneous switchbacks
if max_angle > 100:
edge_geom = simpl_edge_geom
# remove line geoms where cumulative length is greater than around 1.5 * shortest route (hypotenuse)
elif edge_geom.length > simpl_edge_geom.length * 1.8:
edge_geom = simpl_edge_geom
elif simpl_edge_geom.buffer(15).contains(edge_geom):
edge_geom = simpl_edge_geom
elif edge_geom.length < 50:
edge_geom = simpl_edge_geom
# subtle simplication
if total_angle < 5:
edge_geom = edge_geom.simplify(20, preserve_topology=False)
elif total_angle < 10:
edge_geom = edge_geom.simplify(10, preserve_topology=False)
elif total_angle < 20:
edge_geom = edge_geom.simplify(5, preserve_topology=False)
max_angle = util.measure_max_angle(edge_geom.coords)
# don't apply to longer geoms, e.g. rural roads
if edge_geom.length > 100:
edge_geom = edge_geom.simplify(4)
# if there is an angle greater than 95 then it is likely spurious
elif max_angle > 100:
edge_geom = edge_geom.simplify(16)
# preserve resolution for twisty roads
elif total_angle > 170:
edge_geom = edge_geom.simplify(4)
# look for spurious kinks
elif edge_geom.simplify(16).buffer(16).contains(edge_geom) and max_angle > 35:
edge_geom = edge_geom.simplify(16)
elif edge_geom.simplify(8).buffer(8).contains(edge_geom) and max_angle > 35:
edge_geom = edge_geom.simplify(8)
else:
edge_geom = edge_geom.simplify(2, preserve_topology=True)
edge_geom = edge_geom.simplify(4)

g_multi_copy[start_nd_key][end_nd_key][edge_idx]["geom"] = edge_geom
# straightening parallel edges can create duplicates
g_multi_copy = nx_merge_parallel_edges(g_multi_copy, False, 1)
Expand Down Expand Up @@ -652,7 +643,7 @@ def nx_consolidate_nodes(
crawl: bool = False,
centroid_by_itx: bool = True,
merge_edges_by_midline: bool = True,
contains_buffer_dist: int = 40,
contains_buffer_dist: int = 25,
) -> MultiGraph:
"""
Consolidates nodes if they are within a buffer distance of each other.
Expand Down Expand Up @@ -805,7 +796,7 @@ def nx_split_opposing_geoms(
nx_multigraph: MultiGraph,
buffer_dist: float = 12,
merge_edges_by_midline: bool = True,
contains_buffer_dist: float = 40,
contains_buffer_dist: float = 25,
) -> MultiGraph:
"""
Split edges opposite nodes on parallel edge segments if within a buffer distance.
Expand Down
17 changes: 14 additions & 3 deletions pysrc/cityseer/tools/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ def osm_graph_from_poly(
to_epsg_code: int | None = None,
custom_request: str | None = None,
simplify: bool = True,
crawl_consolidate_dist: int = 12,
parallel_consolidate_dist: int = 15,
iron_edges: bool = True,
timeout: int = 300,
max_tries: int = 3,
) -> nx.MultiGraph: # noqa
Expand Down Expand Up @@ -274,6 +277,13 @@ def osm_graph_from_poly(
the geometry passed to the OSM API query. See the discussion below.
simplify: bool
Whether to automatically simplify the OSM graph. Set to False for manual cleaning.
crawl_consolidate_dist: int
The buffer distance to use when doing the initial round of node consolidation. This consolidation step crawls
neighbouring nodes to find groups of adjacent nodes within the buffer distance of each other.
parallel_consolidate_dist: int
The buffer distance to use when looking for adjacent parallel roadways.
iron_edges: bool
Whether to iron the edges.
timeout: int
Timeout duration for API call in seconds.
max_tries: int
Expand Down Expand Up @@ -365,10 +375,11 @@ def osm_graph_from_poly(
graph_crs = graphs.nx_remove_filler_nodes(graph_crs)
if simplify:
graph_crs = graphs.nx_remove_dangling_nodes(graph_crs)
graph_crs = graphs.nx_consolidate_nodes(graph_crs, buffer_dist=12, crawl=True)
graph_crs = graphs.nx_split_opposing_geoms(graph_crs, buffer_dist=15)
graph_crs = graphs.nx_consolidate_nodes(graph_crs, buffer_dist=15, neighbour_policy="indirect")
graph_crs = graphs.nx_consolidate_nodes(graph_crs, buffer_dist=crawl_consolidate_dist, crawl=True)
graph_crs = graphs.nx_split_opposing_geoms(graph_crs, buffer_dist=parallel_consolidate_dist)
graph_crs = graphs.nx_consolidate_nodes(graph_crs, buffer_dist=parallel_consolidate_dist)
graph_crs = graphs.nx_remove_filler_nodes(graph_crs)
if iron_edges:
graph_crs = graphs.nx_iron_edges(graph_crs)

return graph_crs
Expand Down

0 comments on commit ce3fe72

Please sign in to comment.