Ejemplo n.º 1
0
        /// <summary>
        /// Encodes a coordinate on the sphere to the corresponding icosahedral face and
        /// containing 2D hex coordinates relative to that face center.
        /// </summary>
        /// <param name="g">The spherical coordinates to encode.</param>
        /// <param name="res">The desired H3 resolution for the encoding.</param>
        /// <returns>
        /// Tuple
        /// Item1: The resulting face
        /// Item2: The 2D hex coordinates of the cell containing the point.
        /// </returns>
        /// <!--
        /// faceijk.c
        /// void _geoToHex2d
        /// -->
        public static (int, Vec2d) ToHex2d(this GeoCoord g, int res)
        {
            var v3d = g.ToVec3d();

            var newFace = 0;

            // determine the icosahedron face
            decimal sqd = v3d.PointSquareDistance(Constants.FaceIjk.FaceCenterPoint[0]);

            for (var f = 1; f < Constants.H3.NUM_ICOSA_FACES; f++)
            {
                decimal sqdT = v3d.PointSquareDistance(Constants.FaceIjk.FaceCenterPoint[f]);
                if (!(sqdT < sqd))
                {
                    continue;
                }
                newFace = f;
                sqd     = sqdT;
            }

            // cos(r) = 1 - 2 * sin^2(r/2) = 1 - 2 * (sqd / 4) = 1 - sqd/2
            decimal r = DecimalEx.ACos(1 - sqd / 2.0m);

            if (r < Constants.H3.EPSILON)
            {
                return(newFace, new Vec2d());
            }
            // now have face and r, now find CCW theta from CII i-axis
            decimal theta =
                (
                    Constants.FaceIjk.FaceAxesAzRadsCii[newFace, 0] -
                    Constants.FaceIjk.FaceCenterGeo[newFace].AzimuthRadiansTo(g)
                    .NormalizeRadians()
                ).NormalizeRadians();

            // adjust theta for Class III (odd resolutions)
            if (res.IsResClassIii())
            {
                theta = (theta - Constants.H3.M_AP7_ROT_RADS).NormalizeRadians();
            }

            // perform gnomonic scaling of r
            r = DecimalEx.Tan(r);

            // scale for current resolution length u
            r /= Constants.H3.RES0_U_GNOMONIC;
            for (var i = 0; i < res; i++)
            {
                r *= Constants.FaceIjk.MSqrt7;
            }

            // we now have (r, theta) in hex2d with theta ccw from x-axes
            // convert to local x,y
            return(newFace,
                   new Vec2d
                   (
                       r * DecimalEx.Cos(theta),
                       r * DecimalEx.Sin(theta)
                   ));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// The great circle distance in radians between two spherical coordinates.
        /// This function uses the Haversine formula.
        /// For math details, see:
        ///     https://en.wikipedia.org/wiki/Haversine_formula
        ///     https://www.movable-type.co.uk/scripts/latlong.html
        /// </summary>
        /// <param name="a">the first lat/lng pair (in radians)</param>
        /// <param name="b">the second lat/lng pair (in radians)</param>
        /// <returns>
        /// the great circle distance in radians between a and b
        /// </returns>
        /// <!--
        /// geoCoord.c
        /// double H3_EXPORT(pointDistRads)
        /// -->
        public static decimal DistanceToRadians(this GeoCoord a, GeoCoord b)
        {
            decimal sinLat = DecimalEx.Sin((b.Latitude - a.Latitude) / 2.0m);
            decimal sinLng = DecimalEx.Sin((b.Longitude - a.Longitude) / 2.0m);
            decimal p      = sinLat * sinLat + DecimalEx.Cos(a.Latitude) *
                             DecimalEx.Cos(b.Latitude) * sinLng * sinLng;

            return(2 * DecimalEx.ATan2(DecimalEx.Sqrt(p), DecimalEx.Sqrt(1 - p)));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Calculate the 3D coordinate on unit sphere from the latitude and longitude.
        /// </summary>
        /// <param name="geo">The latitude and longitude of the point</param>
        /// <!--
        /// vec3d.c
        /// void _geoToVec3d
        /// -->
        public static Vec3d ToVec3d(this GeoCoord geo)
        {
            decimal r = DecimalEx.Cos(geo.Latitude);

            return(new Vec3d
                   (
                       DecimalEx.Cos(geo.Longitude) * r,
                       DecimalEx.Sin(geo.Longitude) * r,
                       DecimalEx.Sin(geo.Latitude)
                   ));
        }
Ejemplo n.º 4
0
 /// <summary>
 /// Determines the azimuth to p2 from p1 in radians
 /// </summary>
 /// <param name="p1">The first spherical coordinates</param>
 /// <param name="p2">The second spherical coordinates</param>
 /// <returns>The azimuth in radians from p1 to p2</returns>
 /// <!--
 /// geoCoord.c
 /// double _geoAzimuthRads
 /// -->
 internal static decimal AzimuthRadiansTo(this GeoCoord p1, GeoCoord p2)
 {
     return
         (DecimalEx.ATan2
          (
              DecimalEx.Cos(p2.Latitude) * DecimalEx.Sin(p2.Longitude - p1.Longitude),
              DecimalEx.Cos(p1.Latitude) * DecimalEx.Sin(p2.Latitude) -
              DecimalEx.Sin(p1.Latitude) * DecimalEx.Cos(p2.Latitude) *
              DecimalEx.Cos(p2.Longitude - p1.Longitude)
          ));
 }
Ejemplo n.º 5
0
        public void findSin()
        {
            Console.Write("Enter the number:\n");
            string stringConversions = Console.ReadLine();

            if (stringConversions.Contains("/"))
            {
                Fract.Fraction(stringConversions);
                FractionConverted = Fract.Fraction(stringConversions);
                Answer            = FractionConverted;
                Console.WriteLine($"Your answer is {Answer}.\n");
            }
            else
            {
                decimalConverted = Decimal.Parse(stringConversions);
                Answer           = DecimalEx.Sin(decimalConverted);
                Console.WriteLine($"Your answer is {Answer}.\n");
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Rotates about the origin. Returns a new matrix with the result.
        /// </summary>
        /// <param name="degrees">The degrees to rotate.</param>
        /// <param name="clockwise">If False, then + degrees rotates counter clockwise.
        /// If True, then + degrees rotates clockwise. Of course, if the sign of the degrees
        /// is -, then the rotation will be opposite whatever the + direction is.</param>
        public Transform2D Rotate(decimal degrees, bool clockwise = false)
        {
            var r = new Transform2D();

            var theta = DecimalEx.ToRad(degrees);

            if (clockwise)
            {
                theta *= -1;
            }

            //      0     1    2
            // 0   cos  -sin   0
            // 1   sin   cos   0
            // 2    0     0    1

            r[0, 0] = DecimalEx.Cos(theta);
            r[0, 1] = -DecimalEx.Sin(theta);
            r[1, 0] = DecimalEx.Sin(theta);
            r[1, 1] = DecimalEx.Cos(theta);

            return(r.Multiply(this));
        }
Ejemplo n.º 7
0
 public void Test(decimal d, decimal expected, decimal tolerance)
 {
     tolerance = Helper.GetScaledTolerance(expected, (int)tolerance, true);
     Assert.That(DecimalEx.Sin(d), Is.EqualTo(expected).Within(tolerance));
 }
Ejemplo n.º 8
0
        public void UpdateFilter()
        {
            var     A             = DecimalEx.Pow(10, Gain / 40m);
            var     w             = DecimalEx.TwoPi * Frequency / SampleRate;
            var     cosw          = DecimalEx.Cos(w);
            var     sinw          = DecimalEx.Sin(w);
            var     alpha         = sinw / (2 * Q);
            var     Am1cosw       = (A - 1m) * cosw;
            var     Ap1cosw       = (A + 1m) * cosw;
            var     TwoSqrtAalpha = 2m * DecimalEx.Sqrt(A) * alpha;
            decimal a0            = 1m;

            switch (Type)
            {
            case FilterType.Disabled:
                b0    = 1;
                b1    = b2 = a1 = a2 = 0;
                FP_b0 = 0x00800000;
                FP_b1 = FP_b2 = FP_a1 = FP_a2 = 0;
                return;

            case FilterType.EQ:
                b0 = 1m + alpha * A;
                b1 = a1 = -2m * cosw;
                b2 = 1m - alpha * A;
                a0 = 1m + alpha / A;
                a2 = 1m - alpha / A;
                break;

            case FilterType.Lowpass:
                b1 = 1m - cosw;
                b2 = b0 = b1 / 2m;
                a0 = 1m + alpha;
                a1 = -2m * cosw;
                a2 = 1m - alpha;
                break;

            case FilterType.Highpass:
                b1 = -1m - cosw;
                b0 = b2 = -b1 / 2m;
                a0 = 1m + alpha;
                a1 = -2m * cosw;
                a2 = 1m - alpha;
                break;

            case FilterType.Bandpass:
                b0 = alpha;
                b1 = 0;
                b2 = -alpha;
                a0 = 1m + alpha;
                a1 = -2m * cosw;
                a2 = 1m - alpha;
                break;

            case FilterType.Notch:
                b0 = b2 = 1m;
                a0 = 1m + alpha;
                a1 = b1 = -2m * cosw;
                a2 = 1m - alpha;
                break;

            case FilterType.LowShelf:
                b0 = A * (A + 1m - Am1cosw + TwoSqrtAalpha);
                b1 = 2m * A * (A - 1m - Ap1cosw);
                b2 = A * (A + 1m - Am1cosw - TwoSqrtAalpha);
                a0 = A + 1m + Am1cosw + TwoSqrtAalpha;
                a1 = -2m * (A - 1m + Ap1cosw);
                a2 = A + 1m + Am1cosw - TwoSqrtAalpha;
                break;

            case FilterType.HighShelf:
                b0 = A * (A + 1m + Am1cosw + TwoSqrtAalpha);
                b1 = -2m * A * (A - 1m + Ap1cosw);
                b2 = A * (A + 1m + Am1cosw - TwoSqrtAalpha);
                a0 = A + 1m - Am1cosw + TwoSqrtAalpha;
                a1 = 2m * (A - 1m - Ap1cosw);
                a2 = A + 1m - Am1cosw - TwoSqrtAalpha;
                break;

            case FilterType.Custom:
                break;
            }
            b0 /= a0;
            b1 /= a0;
            b2 /= a0;
            a1 /= a0;
            a2 /= a0;
            if (NegateA && Type != FilterType.Custom)
            {
                a1 *= -1m;
                a2 *= -1m;
            }
            FP_b0 = ToFP(b0);
            FP_b1 = ToFP(b1);
            FP_b2 = ToFP(b2);
            FP_a1 = ToFP(a1);
            FP_a2 = ToFP(a2);
            b0    = FromFP(FP_b0);
            b1    = FromFP(FP_b1);
            b2    = FromFP(FP_b2);
            a1    = FromFP(FP_a1);
            a2    = FromFP(FP_a2);
        }
Ejemplo n.º 9
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);
        }