You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用edge_attrs_differ参数时OSMnx simplify_graph函数导致双向边几何方向不一致问题

Answers to Your OSMnx Simplification Questions

1. Is the mixed geometry direction behavior expected or a bug?

This is expected behavior of the simplify_graph function when using edge_attrs_differ. Here's the breakdown based on the OSMnx source code you examined:

The simplification workflow relies on the _get_paths_to_simplify() function to identify edge sequences that can be merged—these are paths with intermediate nodes that meet the simplification criteria. Edges that directly connect two endpoints with no intermediate nodes never get included in these simplification paths, since there’s nothing to merge for them.

Since these edges aren’t part of a simplification path, the code that rebuilds geometry to align with edge direction never runs for them. They retain their original geometry from the input graph, even if that geometry’s orientation doesn’t match the edge’s u→v direction.

2. How to enforce consistent geometry direction for all edges?

There’s no official built-in flag for this, but you can add a straightforward post-processing step to normalize geometry direction for every edge in your simplified graph. The goal is to ensure every u→v edge has a LineString where the first coordinate matches node u’s location and the last matches node v’s location.

Here’s a reusable function you can integrate into your code:

import numpy as np
from shapely.geometry import LineString

def normalize_edge_geometries(graph):
    """Ensure every u→v edge's geometry starts at u and ends at v."""
    # Pre-fetch node coordinates for quick lookup
    node_coords = {n: (data['x'], data['y']) for n, data in graph.nodes(data=True)}
    
    for u, v, key, data in graph.edges(keys=True, data=True):
        geom = data.get('geometry')
        if not isinstance(geom, LineString):
            continue
            
        # Get start/end points of the current geometry
        geom_start = (geom.coords[0][0], geom.coords[0][1])
        geom_end = (geom.coords[-1][0], geom.coords[-1][1])
        # Get expected start/end points from node coordinates
        expected_start = node_coords[u]
        expected_end = node_coords[v]
        
        # Use tolerance to handle floating-point precision issues
        if not np.allclose(geom_start, expected_start, atol=1e-8) or not np.allclose(geom_end, expected_end, atol=1e-8):
            # Reverse geometry to match edge direction
            reversed_coords = list(reversed(geom.coords))
            data['geometry'] = LineString(reversed_coords)
    return graph

Apply this function right after your custom simplification step:

# Run custom simplification
graph_custom_simplification = ox.simplification.simplify_graph(graph, edge_attrs_differ=["tags"])
# Normalize all edge geometries to align with direction
graph_custom_simplification = normalize_edge_geometries(graph_custom_simplification)
# Save the corrected graph
save_geoparquets(graph_custom_simplification, "custom_simplification_normalized")

Key Notes:

  • The np.allclose check accounts for floating-point precision errors common in geospatial data—adjust the atol (absolute tolerance) if needed for your coordinate system.
  • This function only modifies edges where geometry direction doesn’t match the edge’s u→v orientation, so it won’t alter edges that already have correct geometry.
  • It works for both simplified and unsimplified graphs, making it a reliable final cleanup step regardless of your simplification parameters.

内容的提问来源于stack exchange,提问作者chrisail

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 09:13:11