예제 #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)
                   ));
        }
예제 #2
0
 public void Test(decimal d, decimal expected, decimal tolerance)
 {
     tolerance = Helper.GetScaledTolerance(expected, (int)tolerance, true);
     Assert.That(DecimalEx.ACos(d), Is.EqualTo(expected).Within(tolerance));
 }