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

使用NetTopologySuite偏移C#多边形出现多余线条问题求助

多边形偏移(Buffer)结果异常排查与修复

我正在开发一个基于C#的几何项目,使用NetTopologySuite库。自定义了Z_Point类(构造函数接收X、Y、Z三个double参数)与Z_Polygon类(构造函数接收点列表)。为实现多边形偏移,Z_Polygon的Offset方法实现如下:

public List<Z_Polygon> Offset(double distance)
{
    Coordinate[] coords = new Coordinate[Vertices.Count];
    for (int i = 0; i < this.Vertices.Count; i++)
    {
        coords[i] = new Coordinate(this.Vertices[i].X, this.Vertices[i].Y);
    }

    LinearRing rng1 = new LinearRing(coords);
    Polygon pol1 = new Polygon(rng1);

    var bufParams = new BufferParameters();
    bufParams.MitreLimit = 5;
    bufParams.JoinStyle = JoinStyle.Mitre;
    Geometry b = BufferOp.Buffer(pol1, distance, bufParams);

    List<Z_Polygon> result = new List<Z_Polygon>();
    List<Z_Point> newVertices = new List<Z_Point>();

    if (b is MultiPolygon)
    {
        b = (MultiPolygon)b;
        for (int i = 0; i < b.NumGeometries; i++)
        {
            Polygon pol = (Polygon)b.GetGeometryN(i);
            Geometry g = (Geometry)pol;

            foreach (var item in pol.Coordinates)
            {
                newVertices.Add( new Z_Point(item.X, item.Y));
            }
            result.Add(new Z_Polygon(newVertices));
        }
    }
    else
    {
        Polygon pol = (Polygon)b;
        foreach (var item in pol.Coordinates)
        {
            newVertices.Add(new Z_Point(item.X, item.Y));
        }
        result.Add(new Z_Polygon(newVertices));
    }
    return result;
}

但该方法未返回正确结果,出现了不必要的多余线条。测试用多边形代码如下:

Z_Point p1 = new Z_Point(1300.0, 1200.0);
Z_Point p2 = new Z_Point(1300.0, 9800.0);
Z_Point p3 = new Z_Point(6200.0, 9800.0);
Z_Point p4 = new Z_Point(6200.0, 6500.0);
Z_Point p5 = new Z_Point(2600.0, 6500.0);
Z_Point p6 = new Z_Point(2600.0, 5300.0);
Z_Point p7 = new Z_Point(10700.0, 5300.0);
Z_Point p8 = new Z_Point(10700.0, -2900.0);
Z_Point p9 = new Z_Point(3200.0, -2900.0);
Z_Point p10 = new Z_Point(3200.0, -800.0);
Z_Point p11 = new Z_Point(9700.0, -800.0);
Z_Point p12 = new Z_Point(9700.0, 1200.0);
Z_Polygon polygon1 = new Z_Polygon(new List<Z_Point>() { p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p1 });

List<Z_Polygon> new_polygon = polygon1.Offset(-800);

问题原因分析

  • 顶点列表未重置:处理MultiPolygon时,newVertices列表未在每个子多边形处理前清空,导致后续子多边形顶点追加到前一个列表中,生成错误多边形。
  • 多边形拓扑方向错误:原始多边形顶点顺序可能不符合NetTopologySuite的标准规则(外环逆时针、内环顺时针),负距离偏移时容易出现拓扑异常。
  • Mitre连接风格适配问题:Mitre连接在小角度下会产生过长尖刺,复杂多边形内角处偏移时易引发拓扑错误。

修复方案

1. 重置子多边形顶点列表

每个子多边形单独创建顶点列表,避免顶点累积:

if (b is MultiPolygon multiPolygon)
{
    for (int i = 0; i < multiPolygon.NumGeometries; i++)
    {
        List<Z_Point> newVertices = new List<Z_Point>();
        Polygon pol = (Polygon)multiPolygon.GetGeometryN(i);
        foreach (var item in pol.Coordinates)
        {
            newVertices.Add(new Z_Point(item.X, item.Y));
        }
        result.Add(new Z_Polygon(newVertices));
    }
}
else if (b is Polygon pol)
{
    List<Z_Point> newVertices = new List<Z_Point>();
    foreach (var item in pol.Coordinates)
    {
        newVertices.Add(new Z_Point(item.X, item.Y));
    }
    result.Add(new Z_Polygon(newVertices));
}

2. 修正多边形拓扑方向

使用NetTopologySuite内置方法将多边形调整为标准拓扑结构:

Polygon pol1 = new Polygon(rng1);
pol1 = (Polygon)pol1.Orient(); // 自动修正外环逆时针、内环顺时针

3. 调整Buffer连接风格

改用更稳定的Round连接风格,避免尖刺问题:

var bufParams = new BufferParameters();
bufParams.JoinStyle = JoinStyle.Round;

完整修复后的Offset方法

public List<Z_Polygon> Offset(double distance)
{
    Coordinate[] coords = new Coordinate[Vertices.Count];
    for (int i = 0; i < this.Vertices.Count; i++)
    {
        coords[i] = new Coordinate(this.Vertices[i].X, this.Vertices[i].Y);
    }

    LinearRing rng1 = new LinearRing(coords);
    Polygon pol1 = new Polygon(rng1);
    // 修正多边形拓扑方向
    pol1 = (Polygon)pol1.Orient();

    var bufParams = new BufferParameters();
    bufParams.JoinStyle = JoinStyle.Round;
    Geometry b = BufferOp.Buffer(pol1, distance, bufParams);

    List<Z_Polygon> result = new List<Z_Polygon>();

    if (b is MultiPolygon multiPolygon)
    {
        for (int i = 0; i < multiPolygon.NumGeometries; i++)
        {
            List<Z_Point> newVertices = new List<Z_Point>();
            Polygon pol = (Polygon)multiPolygon.GetGeometryN(i);
            foreach (var item in pol.Coordinates)
            {
                newVertices.Add(new Z_Point(item.X, item.Y));
            }
            result.Add(new Z_Polygon(newVertices));
        }
    }
    else if (b is Polygon pol)
    {
        List<Z_Point> newVertices = new List<Z_Point>();
        foreach (var item in pol.Coordinates)
        {
            newVertices.Add(new Z_Point(item.X, item.Y));
        }
        result.Add(new Z_Polygon(newVertices));
    }

    return result;
}

额外验证建议

  • 用pol1.IsValid检查原始多边形是否自相交,自相交多边形会导致Buffer结果异常。
  • 负距离偏移前,可通过BufferOp.IsValidDistance判断偏移距离是否会导致多边形收缩至消失或自相交。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 13:50:44