/// <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); }
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)); }