예제 #1
0
        /// <summary>
        /// Computes the point on the sphere a specified azimuth and distance from
        /// another point.
        /// </summary>
        /// <param name="p1">The first spherical coordinates.</param>
        /// <param name="azimuth">The desired azimuth from p1.</param>
        /// <param name="distance">The desired distance from p1, must be non-negative.</param>
        /// <returns>The spherical coordinates at the desired azimuth and distance from p1.</returns>
        /// <!--
        /// geoCoord.c
        /// void _geoAzDistanceRads
        /// -->
        internal static GeoCoord GetAzimuthDistancePoint(this GeoCoord p1, decimal azimuth, decimal distance)
        {
            if (distance < Constants.H3.EPSILON)
            {
                return(p1);
            }

            azimuth = azimuth.NormalizeRadians().ConstrainToPiAccuracy();
            var p2 = new GeoCoord();

            // check for due north/south azimuth
            if (azimuth < Constants.H3.EPSILON ||
                Math.Abs(azimuth - Constants.H3.M_PI) < Constants.H3.EPSILON)
            {
                if (azimuth < Constants.H3.EPSILON) // due north
                {
                    p2 = p2.SetLatitude(p1.Latitude + distance);
                }
                else // due south
                {
                    p2 = p2.SetLatitude(p1.Latitude - distance);
                }

                if (Math.Abs(p2.Latitude - Constants.H3.M_PI_2) < Constants.H3.EPSILON) // north pole
                {
                    p2 = new GeoCoord(Constants.H3.M_PI_2, 0.0m);
                }
                else if (Math.Abs(p2.Latitude + Constants.H3.M_PI_2) < Constants.H3.EPSILON) // south pole
                {
                    p2 = new GeoCoord(-Constants.H3.M_PI_2, 0.0m);
                }
                else
                {
                    p2 = p2.SetLongitude(p1.Longitude.ConstrainLongitude());
                }
            }
            else // Not due north or south
            {
                decimal sinLatitude = DecimalEx.Sin(p1.Latitude) * DecimalEx.Cos(distance) +
                                      DecimalEx.Cos(p1.Latitude) * DecimalEx.Sin(distance) * DecimalEx.Cos(azimuth);
                sinLatitude = sinLatitude.ConstrainToPiAccuracy();
                if (sinLatitude > 1.0m)
                {
                    sinLatitude = 1.0m;
                }

                if (sinLatitude < -1.0m)
                {
                    sinLatitude = 1.0m;
                }

                p2 = p2.SetLatitude(DecimalEx.ASin(sinLatitude).ConstrainToPiAccuracy());

                if (Math.Abs(p2.Latitude - Constants.H3.M_PI_2) < Constants.H3.EPSILON) // north pole
                {
                    p2 = new GeoCoord(Constants.H3.M_PI_2, 0.0m);
                }
                else if (Math.Abs(p2.Latitude + Constants.H3.M_PI_2) < Constants.H3.EPSILON) // south pole
                {
                    p2 = new GeoCoord(-Constants.H3.M_PI_2, 0.0m);
                }
                else
                {
                    decimal sinLongitude = DecimalEx.Sin(azimuth) * DecimalEx.Sin(distance) / DecimalEx.Cos(p2.Latitude);
                    decimal cosLongitude = (DecimalEx.Cos(distance) - DecimalEx.Sin(p1.Latitude) * DecimalEx.Sin(p2.Latitude)) /
                                           DecimalEx.Cos(p1.Latitude) / DecimalEx.Cos(p2.Latitude);
                    if (sinLongitude > 1.0m)
                    {
                        sinLongitude = 1.0m;
                    }

                    if (sinLongitude < -1.0m)
                    {
                        sinLongitude = -1.0m;
                    }

                    if (cosLongitude > 1.0m)
                    {
                        cosLongitude = 1.0m;
                    }

                    if (cosLongitude < -1.0m)
                    {
                        cosLongitude = -1.0m;
                    }

                    p2 = p2.SetLongitude
                         (
                        (p1.Longitude + DecimalEx.ATan2(sinLongitude, cosLongitude))
                        .ConstrainLongitude().ConstrainToPiAccuracy()
                         );
                }
            }

            return(p2);
        }
예제 #2
0
 public void Test(decimal d, decimal expected, decimal tolerance)
 {
     tolerance = Helper.GetScaledTolerance(expected, (int)tolerance, true);
     Assert.That(DecimalEx.ASin(d), Is.EqualTo(expected).Within(tolerance));
 }