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

如何在OSMnx中移除萨尔瓦多市边界的人工海洋三角区域?

如何在OSMnx中移除萨尔瓦多市边界的人工海洋三角区域?

我完全理解你遇到的困扰——OSM的行政边界偶尔会和海域边界出现奇怪的重叠,导致减去水体后留下这种突兀的三角区域。与其用手动缓冲这种治标不治本的方法,咱们可以从优化标签覆盖、完善裁剪逻辑这两个方向入手,找到更通用的解决方案:

一、优化水体标签,覆盖更多海洋区域

你当前的水体标签只包含了bay和maritime=yes,这大概率是漏减了部分海域的原因。OSM里标记海洋/海域的标签不止这些,咱们可以扩展标签集合,确保所有相关的海洋区域都被纳入裁剪范围:

修改你的water_tags为:

water_tags = {
    "natural": ["bay", "sea", "ocean"],
    "maritime": "yes",
    "water": ["sea", "ocean"],
    "place": ["sea"]
}

这样能覆盖OSM中绝大多数海洋相关的地理特征,减少漏减的概率。

二、结合海岸线进行二次裁剪

如果单纯优化水体标签还解决不了问题,咱们可以引入海岸线来进一步修正边界。你之前尝试过海岸线但效果不好,可能是没有用对方法——咱们可以先获取海岸线,再用海岸线围成的陆地范围和城市边界做交集,确保最终的边界只保留陆地区域:

在你的函数中添加海岸线处理的逻辑:

# 新增:获取海岸线并构建陆地裁剪范围
try:
    coastline_tags = {"natural": "coastline"}
    coastline_gdf = ox.features_from_polygon(bounding_box, tags=coastline_tags)
    if not coastline_gdf.empty:
        # 将海岸线转为线集合,然后生成陆地多边形
        coastline_lines = coastline_gdf.geometry.union_all()
        # 用shapely的polygonize生成由海岸线围成的多边形
        land_polygons = list(shapely.ops.polygonize(coastline_lines))
        # 找到和城市边界重叠的陆地多边形并合并
        land_union = shapely.ops.unary_union([poly for poly in land_polygons if poly.intersects(city_polygon)])
        city_polygon = city_polygon.intersection(land_union)
except Exception as e:
    print(f"Error processing coastline: {e}")

这个逻辑的核心是:用海岸线把陆地范围圈出来,再让城市边界只保留和陆地重叠的部分,从根源上排除海洋区域。

三、修正边界的拓扑问题

有时候这种三角区域的出现,也可能是因为原始行政边界存在拓扑错误(比如自相交)。你已经用了buffer(0)来修正,这很好,还可以加上shapely.make_valid()来进一步确保几何图形的有效性:

city_polygon = shapely.make_valid(city_polygon)
city_polygon = city_polygon.buffer(0)

整合后的完整代码

把这些优化点整合到你的函数中,修改后的代码如下:

import osmnx as ox
import shapely

def get_city_boundary(place_name):
    city_gdf = ox.geocode_to_gdf(place_name)
    city_polygon = city_gdf.loc[0, "geometry"]

    expand = 0
    minx, miny, maxx, maxy = city_polygon.bounds
    bounding_box = shapely.geometry.box(minx - expand, miny - expand, maxx + expand, maxy + expand)

    # 第一步:优化水体裁剪
    try:
        water_tags = {
            "natural": ["bay", "sea", "ocean"],
            "maritime": "yes",
            "water": ["sea", "ocean"],
            "place": ["sea"]
        }
        water_gdf = ox.features_from_polygon(bounding_box, tags=water_tags)
        if not water_gdf.empty:
            water_union = water_gdf.geometry.union_all()
            city_polygon = city_polygon.difference(water_union)
    except Exception as e:
        print(f"Error processing water areas: {e}")

    # 第二步:用海岸线二次裁剪
    try:
        coastline_tags = {"natural": "coastline"}
        coastline_gdf = ox.features_from_polygon(bounding_box, tags=coastline_tags)
        if not coastline_gdf.empty:
            coastline_lines = coastline_gdf.geometry.union_all()
            land_polygons = list(shapely.ops.polygonize(coastline_lines))
            land_union = shapely.ops.unary_union([poly for poly in land_polygons if poly.intersects(city_polygon)])
            city_polygon = city_polygon.intersection(land_union)
    except Exception as e:
        print(f"Error processing coastline: {e}")

    # 修正拓扑错误
    city_polygon = shapely.make_valid(city_polygon)
    city_polygon = city_polygon.buffer(0)

    # 保留最大的多边形(去掉岛屿)
    if isinstance(city_polygon, shapely.geometry.MultiPolygon):
        polygons = list(city_polygon.geoms)
        city_polygon = max(polygons, key=lambda p: p.area)

    return city_polygon

# 调用测试
place_name = "Salvador, Bahia, Brazil"
processed_polygon = get_city_boundary(place_name)

processed_gdf = ox.geocode_to_gdf(place_name).copy()
processed_gdf.loc[0, "geometry"] = processed_polygon

if processed_gdf.crs is None:
    processed_gdf.set_crs(epsg=4326, inplace=True)

output_file = "salvador_processed_boundary.shp"
processed_gdf.to_file(output_file)

额外提示

如果以上方法还是解决不了,可能是OSM中萨尔瓦多的行政边界本身存在数据问题。这时候你可以去OpenStreetMap官网手动查看该区域的边界数据,确认是否有错误的节点/线段,必要时可以提交修正(当然这是更进阶的操作了)。

备注:内容来源于stack exchange,提问作者enriicoo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 11:58:00