Example #1
0
        /// <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);
            }
        }
Example #2
0
        /// <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()));
        }