/// <summary> /// Convert an input geometry instance to a valid geography instance. /// This function requires that the WKT coordinate values are longitude/latitude values, /// in that order and that a valid geography SRID value is supplied. /// </summary> /// <param name="geometry">Input Sql Geometry</param> /// <returns></returns> public static SqlGeography MakeValidGeographyFromGeometry(SqlGeometry geometry) { if (geometry.IsNull) { return(SqlGeography.Null); } if (geometry.STIsEmpty().Value) { return(CreateEmptyGeography(geometry.STSrid.Value)); } // Extract vertices from our input to be able to compute geography EnvelopeCenter var pointSetBuilder = new SqlGeographyBuilder(); geometry.Populate(new GeometryToPointGeographySink(pointSetBuilder)); SqlGeography center; try { center = pointSetBuilder.ConstructedGeography.EnvelopeCenter(); } catch (ArgumentException) { // Input is larger than a hemisphere. return(SqlGeography.Null); } // Construct Gnomonic projection centered on input geography var gnomonicProjection = SqlProjection.Gnomonic(center.Long.Value, center.Lat.Value); // Project, run geometry MakeValid and unproject var geometryBuilder = new SqlGeometryBuilder(); geometry.Populate(new VacuousGeometryToGeographySink(geometry.STSrid.Value, new Projector(gnomonicProjection, geometryBuilder))); var outGeometry = Geometry.MakeValidForGeography(geometryBuilder.ConstructedGeometry); try { return(gnomonicProjection.Unproject(outGeometry)); } catch (ArgumentException) { // Try iteratively to reduce the object to remove very close vertices. for (var tolerance = 1e-4; tolerance <= 1e6; tolerance *= 2) { try { return(gnomonicProjection.Unproject(outGeometry.Reduce(tolerance))); } catch (ArgumentException) { // keep trying } } return(SqlGeography.Null); } }
/// <summary> /// Computes ConvexHull of input geography and returns a polygon (unless all input points are collinear). /// </summary> /// <param name="geography">Input Sql Geography</param> /// <returns></returns> public static SqlGeography ConvexHullGeography(SqlGeography geography) { if (geography.IsNull || geography.STIsEmpty().Value) { return(geography); } var center = geography.EnvelopeCenter(); var gnomonicProjection = SqlProjection.Gnomonic(center.Long.Value, center.Lat.Value); var geometry = gnomonicProjection.Project(geography); return(gnomonicProjection.Unproject(geometry.MakeValid().STConvexHull())); }