如何在一组简单多边形中分割一个多边形
本文关键字:分割 一个 多边形 简单多边形 一组 | 更新日期: 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);
本质上,它重建了几何形状,但没有任何孔。我真的很享受把这些放在一起的挑战!!: -)