Created
February 24, 2012 23:06
-
-
Save JeffJacobson/1904431 to your computer and use it in GitHub Desktop.
SqlGeometry <-> ESRI SOAP Geometry conversion extensions for .NET
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Wsdot.GIS.Geometry.Conversion | |
{ | |
using System; | |
using System.Collections.Generic; | |
using ESRI.ArcGIS.SOAP; | |
using Microsoft.SqlServer.Types; | |
public static class SqlGeoemtryExtensions | |
{ | |
/// <summary> | |
/// Converts a <see cref="PolygonN"/> object into a <see cref="SqlGeometry"/> object. | |
/// </summary> | |
/// <param name="geometry">The geometry to be converted.</param> | |
/// <param name="wkid"> | |
/// The Well-Known ID of the Spatial Reference of <paramref name="geometry"/>. | |
/// This parameter can be set to <see langword="null"/> if <paramref name="geometry"/> | |
/// has a non-null <see cref="Geometry.SpatialReference"/> property with a WKID. | |
/// </param> | |
/// <returns>A <see cref="SqlGeometry"/> object</returns> | |
public static SqlGeometry ToSqlGeometry(this PolygonN geometry, int? wkid) | |
{ | |
if (geometry == null) throw new ArgumentNullException("geometry"); | |
if (!wkid.HasValue) | |
{ | |
SpatialReference sr = geometry.SpatialReference; | |
if (sr != null && sr.WKIDSpecified) | |
{ | |
wkid = sr.WKID; | |
} | |
else | |
{ | |
throw new ArgumentException("The wkid was not specified and the line did not contain wkid information"); | |
} | |
} | |
SqlGeometryBuilder geoBuilder = new SqlGeometryBuilder(); | |
geoBuilder.SetSrid(wkid.Value); | |
geoBuilder.BeginGeometry(OpenGisGeometryType.Polygon); | |
foreach (Ring path in geometry.RingArray) | |
{ | |
geoBuilder.AddCurve(path, false); | |
} | |
geoBuilder.EndGeometry(); | |
return geoBuilder.ConstructedGeometry; | |
} | |
/// <summary> | |
/// Converts a <see cref="PolylineN"/> object into a <see cref="SqlGeometry"/> object. | |
/// </summary> | |
/// <param name="geometry">The geometry to be converted.</param> | |
/// <param name="wkid"> | |
/// The Well-Known ID of the Spatial Reference of <paramref name="geometry"/>. | |
/// This parameter can be set to <see langword="null"/> if <paramref name="geometry"/> | |
/// has a non-null <see cref="Geometry.SpatialReference"/> property with a WKID. | |
/// </param> | |
/// <returns>A <see cref="SqlGeometry"/> object</returns> | |
public static SqlGeometry ToSqlGeometry(this PolylineN line, int? wkid) | |
{ | |
if (line == null) throw new ArgumentNullException("line"); | |
if (!wkid.HasValue) | |
{ | |
SpatialReference sr = line.SpatialReference; | |
if (sr != null && sr.WKIDSpecified) | |
{ | |
wkid = sr.WKID; | |
} | |
else | |
{ | |
throw new ArgumentException("The wkid was not specified and the line did not contain wkid information"); | |
} | |
} | |
SqlGeometryBuilder geoBuilder = new SqlGeometryBuilder(); | |
geoBuilder.SetSrid(wkid.Value); | |
geoBuilder.BeginGeometry(OpenGisGeometryType.Polygon); | |
foreach (Path path in line.PathArray) | |
{ | |
geoBuilder.AddCurve(path, true); | |
} | |
geoBuilder.EndGeometry(); | |
return geoBuilder.ConstructedGeometry; | |
} | |
/// <summary> | |
/// Gets the spatial reference WKID from a <see cref="RecordSet"/>. | |
/// </summary> | |
/// <param name="recordSet">A <see cref="RecordSet"/> containing spatial data.</param> | |
/// <param name="geometryFieldIndex"> | |
/// If you know ahead of time which field in <paramref name="recordSet"/> contains geometry, | |
/// you can set that value here. Otherwise you can set this to null and all of the fields will | |
/// be searched until a geometry field is found. | |
/// </param> | |
/// <returns></returns> | |
public static int GetWkid(this RecordSet recordSet, int? geometryFieldIndex) | |
{ | |
SpatialReference sr = GetSpatialReference(recordSet, ref geometryFieldIndex); | |
return sr.WKID; | |
} | |
public static SpatialReference GetSpatialReference(this RecordSet recordSet, ref int? geometryFieldIndex) | |
{ | |
Field[] fields = recordSet.Fields.FieldArray; | |
Field geoField = null; | |
// If the user explicitly specified the geometry field index, use that. | |
if (geometryFieldIndex.HasValue && fields.Length > geometryFieldIndex) | |
{ | |
geoField = fields[geometryFieldIndex.Value]; | |
if (geoField.Type != esriFieldType.esriFieldTypeGeometry) geoField = null; | |
} | |
// If the user didn't specify a geometry field index or they specified a field that wasn't really a geometry field, search for a geometry field. | |
if (geoField == null) | |
{ | |
for (int i = 0; i < fields.Length; i++) | |
{ | |
Field f = fields[i]; | |
if (f.Type == esriFieldType.esriFieldTypeGeometry) | |
{ | |
geoField = f; | |
geometryFieldIndex = i; | |
break; | |
} | |
} | |
} | |
// If no geometry field was found... | |
if (geoField == null) | |
{ | |
throw new ArgumentException("The record set does not appear to contain a geometry field, and is thus not supported by this method.", "recordSet"); | |
} | |
SpatialReference sr = geoField.GeometryDef.SpatialReference; | |
if (!sr.WKIDSpecified) | |
{ | |
throw new NotSupportedException("The Spatial Reference of this record set does not have a WKID and is thus not supported by this method."); | |
} | |
return sr; | |
} | |
private static void GetPointAndSegmentArrays(this Curve curve, out Point[] points, out Segment[] segments) | |
{ | |
Path path = curve as Path; | |
if (path != null) | |
{ | |
points = path.PointArray; | |
segments = path.SegmentArray; | |
} | |
else | |
{ | |
Ring ring = curve as Ring; | |
points = ring.PointArray; | |
segments = ring.SegmentArray; | |
} | |
} | |
private static void AddCurve(this SqlGeometryBuilder geoBuilder, Curve curve, bool addAsNewGeometry) | |
{ | |
if (addAsNewGeometry) | |
{ | |
geoBuilder.BeginGeometry(OpenGisGeometryType.LineString); | |
} | |
bool figBegun = false; | |
Point[] pointArray; | |
Segment[] segmentArray; | |
curve.GetPointAndSegmentArrays(out pointArray, out segmentArray); | |
if (pointArray != null) | |
{ | |
foreach (PointN p in pointArray) | |
{ | |
if (!figBegun) | |
{ | |
geoBuilder.BeginFigure(p); | |
figBegun = true; | |
} | |
else | |
{ | |
geoBuilder.AddPoint(p); | |
} | |
} | |
} | |
else if (segmentArray != null) | |
{ | |
foreach (Segment seg in segmentArray) | |
{ | |
if (!figBegun) | |
{ | |
geoBuilder.BeginFigure(seg.FromPoint); | |
} | |
else | |
{ | |
geoBuilder.AddPoint(seg.FromPoint); | |
} | |
geoBuilder.AddPoint(seg.ToPoint); | |
} | |
} | |
geoBuilder.EndFigure(); | |
if (addAsNewGeometry) | |
{ | |
geoBuilder.EndGeometry(); | |
} | |
} | |
private static void AddPoints<T>(this SqlGeometryBuilder geoBuilder, IEnumerable<T> points) where T : Point | |
{ | |
foreach (T p in points) | |
{ | |
geoBuilder.AddPoint(p); | |
} | |
} | |
private static void BeginFigure(this SqlGeometryBuilder geoBuilder, Point point) | |
{ | |
PointN pointN = point as PointN; | |
if (pointN != null) | |
{ | |
double? m = pointN.MSpecified ? pointN.M : new double?(); | |
double? z = pointN.ZSpecified ? pointN.Z : new double?(); | |
geoBuilder.BeginFigure(pointN.X, pointN.Y, z, m); | |
} | |
else | |
{ | |
throw new NotSupportedException("Only points of type PointN are supported by this method."); | |
} | |
} | |
private static void AddPoint(this SqlGeometryBuilder geoBuilder, Point point) | |
{ | |
PointN pointN = point as PointN; | |
if (pointN != null) | |
{ | |
double? m = pointN.MSpecified ? pointN.M : new double?(); | |
double? z = pointN.ZSpecified ? pointN.Z : new double?(); | |
geoBuilder.AddLine(pointN.X, pointN.Y, z, m); | |
} | |
else | |
{ | |
throw new NotSupportedException("Only points of type PointN are supported by this method."); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment