如何在一组简单多边形中分割一个多边形

本文关键字:分割 一个 多边形 简单多边形 一组 | 更新日期: 2023-09-27 18:12:36

我从SQL空间数据库(c#中的DbGeometry)中检索一个复杂多边形。复数意味着这个多边形被定义为一个外环和一个或多个内环(如甜甜圈)。

是否有一种简单的方法将这个复杂多边形转换成一组简单多边形。简单多边形是没有内环的多边形。

谢谢,明星之

如何在一组简单多边形中分割一个多边形

我已经使用DbGeometries一段时间了,本文提供了一个很好的工具来操作它。

我怀疑这不能像return myGeo.ExteriorRing;那么简单,所以,根据评论的要求,这里是我找到的一些代码(基于文章):

//handling of LineStrings (I use this to build WPF Path for example)
        private static object LineStringToSomething(DbGeometry sqlGeometry)
        {
            object result = null;
            DbGeometry curPoint;
            System.Windows.Point startPoint = new System.Windows.Point()
            {
                X = sqlGeometry.PointAt(1).XCoordinate.Value,
                Y = sqlGeometry.PointAt(1).YCoordinate.Value
            };
            curPoint = sqlGeometry.PointAt(1);
            for (int i = 2; i <= sqlGeometry.PointCount; i++)
            {
                //Do something with the line between curPoint and PointAt(i)
                curPoint = sqlGeometry.PointAt(i);
            }
            return result;
        }
        //Defines an extension method on DbGeometry objects
        //usage :
        // myOwnGeometry = myGeo.AsSimpleGeometry();
        public static object AsSimpleGeometry(this DbGeometry sqlGeometry)
        {
            object result = null;
            switch (sqlGeometry.SpatialTypeName.ToLower())
            {
                case "point":
                    //Here we found a point
                    return result;
                case "polygon":
                    // A Spacial Polygon is a collection of Rings
                    // A Ring is a Closed LineString, i.e. a collection of lines.
                    List<object> lotOfGeos = new List<object>();
                    // Outer Ring
                    return LineStringToSomething(sqlGeometry.ExteriorRing);
                    // Inner Rings (holes in the donut)
                    for (int i = 1; i <= sqlGeometry.InteriorRingCount; i++)
                    {
                        //just comment to ignore the inner loops
                        lotOfGeos.Add(LineStringToSomething(sqlGeometry.InteriorRingAt(i)));
                    }
                    return lotOfGeos;
                case "linestring":
                    // Return a PathFigure
                    return LineStringToSomething(sqlGeometry);
                case "multipoint":
                case "multilinestring":
                case "multipolygon":
                case "geometrycollection":
                    //Here we handle a collection of points, polygons and/or lines
                    List<object> moreGeos = new List<object>();
                    for (int i = 1; i <= sqlGeometry.ElementCount.Value; i++)
                    {
                        //Simply calling the same method on each item
                        moreGeos.Add(sqlGeometry.ElementAt(i).AsSimpleGeometry());
                    }
                    return moreGeos;
                default:
                    // Unrecognized Type
                    // Shall not happen
                    return null;
            }
        }

因为我不知道你到底想用几何图形实现什么,我不能更具体地处理地理数据(特别是在LineStringToSomething)

根据我的理解,你想要简化POLYGON或MULTIPOLYGON几何实例,从本质上删除所有孔。不清楚的是,当实例是MULTIPOLYGON时,您期望返回什么,但我假设您希望所有外部边界都在同一实例中。

因此我建议如下:

首先,定义一个方法来简化几何图形:

    using Microsoft.SqlServer.Types;
    using System.Data.Entity.Spatial;
    private static DbGeometry GetSimpleDbGeography(DbGeometry input)
    {
        // We can create geometry using Microsoft.SqlServer.Types.SqlGeometryBuilder
        // We have to use this to reconstruct the geometry we want from the input as DbGeometry.ExteriorRing() returns a LINESTRING which is no good to us
        SqlGeometryBuilder builder = new SqlGeometryBuilder();
        // We MUST set an SRID
        builder.SetSrid(0);
        OpenGisGeometryType ourType;
        // We must set the type
        if (input.SpatialTypeName.ToUpper() == "POLYGON")
            ourType = OpenGisGeometryType.Polygon;
        else if (input.SpatialTypeName.ToUpper() == "MULTIPOLYGON")
            ourType = OpenGisGeometryType.MultiPolygon;
        else
            throw new ArgumentException("Non Polygon received.");
        // Tell the Builder what we're creating
        builder.BeginGeometry(ourType);
        // This assumes we have a valid DbGeometry instance, otherwise .Value will cause an error
        int numberOfElements = input.ElementCount.Value;
        // Loop through each element, this will either be one (POLYGON) or more (MULTIPOLYGON)
        for (int i = 1; i < (numberOfElements + 1); i++)
        {
            // BeginGeometry only required for MULTIPOLYGON
            if (ourType == OpenGisGeometryType.MultiPolygon)
            {
                // Begin a POLYGON geometry
                builder.BeginGeometry(OpenGisGeometryType.Polygon);
            }
            // ElementAt() is not zero-based index
            DbGeometry element = input.ElementAt(i).ExteriorRing;
            // Start the figure with the first point
            builder.BeginFigure(element.StartPoint.XCoordinate.Value, element.StartPoint.YCoordinate.Value);
            // Lopp through remaining points
            for (int j = 2; j < (element.PointCount.Value + 1); j++)
            {
                // PointAt() is not zero-based index
                builder.AddLine(element.PointAt(j).XCoordinate.Value, element.PointAt(j).YCoordinate.Value);
            }
            // End the current polygon
            builder.EndFigure();
            // EndGeometry only required for MULTIPOLYGON
            if (ourType == OpenGisGeometryType.MultiPolygon)
            {
                // End the current Geometry
                builder.EndGeometry();
            }
        }
        // Finalise the geometry
        builder.EndGeometry();
        // Convert the construsted geometry back to a DbGeometry instance
        DbGeometry finalGeometry = DbGeometry.FromBinary(builder.ConstructedGeometry.STAsBinary().Buffer);
        return finalGeometry;
    }

现在简单地像这样调用:

// Two sample donuts
DbGeometry donut1 = DbGeometry.FromText("POLYGON((0 0, 3 0, 3 3, 0 3, 0 0),(1 1, 2 1, 2 2, 1 2, 1 1))", 0);
DbGeometry donut2 = DbGeometry.FromText("POLYGON((10 10, 13 10, 13 13, 10 13, 10 10),(11 11, 12 11, 12 12, 11 12, 11 11))", 0);
// A merged, double-donut
DbGeometry doubleDonut = donut1.Union(donut2);
// Produces POLYGON((0 0, 3 0, 3 3, 0 3, 0 0))
DbGeometry donut1_simple = GetSimpleDbGeography(donut1);
// Produces MULTIPOLYGON(((10 10, 13 10, 13 13, 10 13, 10 10)),((0 0, 3 0, 3 3, 0 3, 0 0)))
DbGeometry doubleDonut_simple = GetSimpleDbGeography(doubleDonut);

本质上,它重建了几何形状,但没有任何孔。我真的很享受把这些放在一起的挑战!!: -)