The RTM version of SQL Server 2008 and recently release of the CLR updates with Visual Studio 2008 SP1 gave us the SqlGeometryBuilder and SqlGeographyBuilder classes to work with. These are very handy, simple APIs but, well, lets just say that the documentation on them is a bit lacking (Isaac Kunen's as some discussion of them at Our Upcoming Builder API). This morning, I wanted to write a few bits of .NET code that did the same work as this T-SQL statement:
declare @p geometry = geometry::STGeomFromText('MULTIPOLYGON(((-77.054700 38.872957,-77.057962 38.872620,-77.058547 38.870079,-77.055592 38.868840,-77.053217 38.870656,-77.054700 38.872957),(-77.056972 38.870639,-77.055851 38.870219,-77.054875 38.870864,-77.055452 38.871804,-77.056784 38.871655,-77.056972 38.870639)),((-77.056408 38.875290,-77.056947 38.875224,-77.057466 38.873598,-77.057273 38.872737,-77.055335 38.873020,-77.055499 38.874058,-77.056408 38.875290)))',4326);
The trick here is how do you delimit the rings of a polygon and how do you make a collection? It helps to keep four simple rules in mind:
- After instantiating the Builder, immediately set the Spatial Reference ID (SRID) you want to use. You must do this before you define any elements in the collection.
- In the case of a collection type, you need to call .BeginGeometry passing in a member of the OpenGisGeometryType enumeration for the desired collection.
- Each figure in the collection needs to started with a call to .BeginGeometry as well.
- Collection members must be well-formed. The collection must also be well-formed.
Keeping all that in mind, here's example method for constructing the geometry shown above:
private static SqlGeometry CreateMultipolygon() {
// Create a new Geometry Builder to work with
SqlGeometryBuilder gb = new SqlGeometryBuilder();
// Set the Spatial Reference ID to 1
gb.SetSrid(1);
// Start the collection
gb.BeginGeometry(OpenGisGeometryType.MultiPolygon);
// Start the first element in this collection
gb.BeginGeometry(OpenGisGeometryType.Polygon);
// Define the first element (figure)
gb.BeginFigure(-77.054700,38.872957);
gb.AddLine(-77.057962, 38.872620);
gb.AddLine(-77.058547, 38.870079);
gb.AddLine(-77.055592, 38.868840);
gb.AddLine(-77.053217, 38.870656);
gb.AddLine(-77.054700, 38.872957);
// End the first element (figure)
gb.EndFigure();
// Define the second figure
gb.BeginFigure(-77.056972, 38.870639);
gb.AddLine(-77.055851, 38.870219);
gb.AddLine(-77.054875, 38.870864);
gb.AddLine(-77.055452, 38.871804);
gb.AddLine(-77.056784, 38.871655);
gb.AddLine(-77.056972, 38.870639);
gb.EndFigure();
// End the first polygon
gb.EndGeometry();
// Define the second polygon
gb.BeginGeometry(OpenGisGeometryType.Polygon);
gb.BeginFigure(-77.056408, 38.875290);
gb.AddLine(-77.056947, 38.875224);
gb.AddLine(-77.057466, 38.873598);
gb.AddLine(-77.057273, 38.872737);
gb.AddLine(-77.055335, 38.873020);
gb.AddLine(-77.055499, 38.874058);
gb.AddLine(-77.056408, 38.875290);
gb.EndFigure();
gb.EndGeometry();
// End (close) the collection
gb.EndGeometry();
// Return that as a SqlGeometry instance
return gb.ConstructedGeometry;
}