Ejemplo n.º 1
0
        /// <summary>
        /// Find the point that is the given distance from the start point in the direction of the end point.
        /// The distance must be less than the distance between these two points.
        /// </summary>
        /// <param name="start">Start Geography Point</param>
        /// <param name="end">End Geography Point</param>
        /// <param name="distance">Distance at which the point to be located</param>
        /// <returns></returns>
        public static SqlGeography InterpolateBetweenGeog(SqlGeography start, SqlGeography end, double distance)
        {
            // We need to check a few prerequisite.
            // We only operate on points.
            if (!start.IsPoint() || !end.IsPoint())
            {
                throw new ArgumentException(ErrorMessage.PointCompatible);
            }

            // The SRIDs also have to match
            var srid = start.STSrid.Value;

            if (srid != end.STSrid.Value)
            {
                throw new ArgumentException(ErrorMessage.SRIDCompatible);
            }

            // Finally, the distance has to fall between these points.
            var length = start.STDistance(end).Value;

            if (distance > length)
            {
                throw new ArgumentException(ErrorMessage.DistanceMustBeBetweenTwoPoints);
            }

            if (distance < 0)
            {
                throw new ArgumentException(ErrorMessage.DistanceMustBePositive);
            }

            // We'll just do this by binary search---surely this could be more efficient,
            // but this is relatively easy.
            //
            // Note that we can't just take the take the linear combination of end vectors because we
            // aren't working on a sphere.

            // We are going to do our binary search using 3D Cartesian values, however
            var startCart = SpatialUtil.GeographicToCartesian(start);
            var endCart   = SpatialUtil.GeographicToCartesian(end);

            SqlGeography current;
            double       currentDistance;

            // Keep refining until we slip below the THRESHOLD value.
            do
            {
                var currentCart = (startCart + endCart) / 2;
                current         = SpatialUtil.CartesianToGeographic(currentCart, srid);
                currentDistance = start.STDistance(current).Value;

                if (distance <= currentDistance)
                {
                    endCart = currentCart;
                }
                else
                {
                    startCart = currentCart;
                }
            } while (Math.Abs(currentDistance - distance) > Constants.Tolerance);

            return(current);
        }