我从SQL空间数据库中检索一个复杂的多边形,在C#中检索一个DbGeometry。复合意味着该多边形被定义为外环和一个或多个内环(如甜甜圈)。
是否有一种简单的方法可以在一组简单多边形中转换此复杂多边形。简单的多边形是没有内圈的plygon。
谢谢, 的Mickaël
答案 0 :(得分:0)
我已经和DbGeometries玩了一段时间,this article提供了一个很好的工具来操纵它。
我怀疑这不能像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
中)
答案 1 :(得分:0)
根据我的理解,您希望简化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);
基本上,它会按原样重新创建几何体,但没有任何孔。我真的很喜欢把它放在一起的挑战! : - )