Looking for the opposite of SqlGeometryBuilder: Ho

2019-09-15 15:48发布

I know how to compose a SqlGeometry using SqlGeometryBuilder, for example:

// using Microsoft.SqlServer.Types;
SqlGeometryBuilder geometryBuilder = new SqlGeometryBuilder();
geometryBuilder.SetSrid(…);
geometryBuilder.BeginGeometry(OpenGisGeometryType.Polygon);
geometryBuilder.BeginFigure(0, 0);
geometryBuilder.AddLine(…);
…
geometryBuilder.EndFigure();
geometryBuilder.EndGeometry();

SqlGeometry geometry = geometryBuilder.ConstructedGeometry;

Once a SqlGeometry is built, it's pretty much an opaque object, and inspecting its constituent parts (e.g. the line segments its boundary is made up from, and those lines' end points) using the ST… methods methods (STNumPoints, STPointN, STNumCurves, STCurveN, STBoundary, etc.) feels a little cumbersome to me.

Is there something in Microsoft.SqlServer.Types or the .NET Framework Class Library that is the logical opposite of SqlGeometryBuilder, i.e. something that I could use to decompose a SqlGeometry into its constituent parts? I imagine that what I am looking for might possibly make use of the visitor pattern.

1条回答
一夜七次
2楼-- · 2019-09-15 16:34

The Microsoft.SqlServer.Types API does offer functionality opposite to SqlGeometryBuilder, in the form of the SqlGeometry.Populate(IGeometrySink110) method.

This method accepts an object implementing the IGeometrySink110 interface, whose definition very closely mirrors that of SqlGeometryBuilder. The method will "replay" the method calls that were used on a SqlGeometryBuilder in order to construct the SqlGeometry.

For example, given the SqlGeometry geometry as shown in the question above, as well as the following IGeometrySink110 implementation:

class ConsoleGeometrySink : IGeometrySink110
{
    public void SetSrid(int srid)
    {
        Console.WriteLine($"SetSrid(srid: {srid})");
    }
    public void BeginGeometry(OpenGisGeometryType type)
    {
        Console.WriteLine($"BeginGeometry(type: {type})");
    }
    public void BeginFigure(double x, double y, double? z, double? m)
    {
        Console.WriteLine($"BeginFigure(x: {x}, y: {y}, z: {z}, m: {m})");
    }
    public void AddCircularArc(double x1, double y1, double? z1, double? m1,
                               double x2, double y2, double? z2, double? m2)
    {
        Console.WriteLine($"AddCircularArc(x1: {x1}, y1: {y1}, z1: {z1}, m1: {m1}, " + 
                                         $"x2: {x2}, y2: {y2}, z2: {z2}, m2: {m2})");
    }
    public void AddLine(double x, double y, double? z, double? m)
    {
        Console.WriteLine($"AddLine(x: {x}, y: {y}, z: {z}, m: {m})");
    }
    public void EndFigure()
    {
        Console.WriteLine($"EndFigure()");
    }
    public void EndGeometry()
    {
        WriteLine($"EndGeometry()");
    }
}

Calling geometry.Populate(new ConsoleGeometrySink()) would output the following:

SetSrid(srid: …)
BeginGeometry(type: Polygon)
BeginFigure(x: 0, y: 0, z: , m: )
AddLine(…)
…
EndFigure()
EndGeometry()

which mirrors exactly the original steps performed to build the SqlGeometry.

查看更多
登录 后发表回答