/// <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> /// <param name="face">The icosahedral face containing the spherical coordinates.</param> /// <param name="v">The 2D hex coordinates of the cell containing the point.</param> /// <!-- Based off 3.1.1 --> public static void _geoToHex2d(GeoCoord g, int res, ref int face, ref Vec2d v) { Vec3d v3d = new Vec3d(); Vec3d._geoToVec3d(g, ref v3d); // determine the icosahedron face face = 0; double sqd = Vec3d._pointSquareDist(faceCenterPoint[0], v3d); for (int f = 1; f < Constants.NUM_ICOSA_FACES; f++) { double sqdT = Vec3d._pointSquareDist(faceCenterPoint[f], v3d); if (sqdT < sqd) { face = f; sqd = sqdT; } } // cos(r) = 1 - 2 * sin^2(r/2) = 1 - 2 * (sqd / 4) = 1 - sqd/2 double r = Math.Acos(1 - sqd / 2); if (r < Constants.EPSILON) { v.x = 0.0; v.y = 0.0; return; } // now have face and r, now find CCW theta from CII i-axis double theta = GeoCoord._posAngleRads(faceAxesAzRadsCII[face, 0] - GeoCoord._posAngleRads(GeoCoord._geoAzimuthRads(faceCenterGeo[face], g))); // adjust theta for Class III (odd resolutions) if (H3Index.isResClassIII(res)) { theta = GeoCoord._posAngleRads(theta - Constants.M_AP7_ROT_RADS); } // perform gnomonic scaling of r r = Math.Tan(r); // scale for current resolution length u r /= Constants.RES0_U_GNOMONIC; for (int i = 0; i < res; i++) { r *= M_SQRT7; } // we now have (r, theta) in hex2d with theta ccw from x-axes // convert to local x,y v.x = r * Math.Cos(theta); v.y = r * Math.Sin(theta); }
/// <summary> /// Determines the center point in spherical coordinates of a cell given by 2D /// hex coordinates on a particular icosahedral face. /// </summary> /// <param name="v">The 2D hex coordinates of the cell.</param> /// <param name="face">The icosahedral face upon which the 2D hex coordinate system is centered</param> /// <param name="res">The H3 resolution of the cell</param> /// <param name="substrate">Indicates whether or not this grid is actually a substrate /// grid relative to the specified resolution.</param> /// <param name="g">The spherical coordinates of the cell center point.</param> /// <!-- Based off 3.1.1 --> public static void _hex2dToGeo(ref Vec2d v, int face, int res, int substrate, ref GeoCoord g) { // calculate (r, theta) in hex2d double r = Vec2d._v2dMag(v); if (r < Constants.EPSILON) { g = faceCenterGeo[face]; return; } double theta = Math.Atan2(v.y, v.x); // scale for current resolution length u for (int i = 0; i < res; i++) { r /= M_SQRT7; } // scale accordingly if this is a substrate grid if (substrate > 0) { r /= 3.0; if (H3Index.isResClassIII(res)) { r /= M_SQRT7; } } r *= Constants.RES0_U_GNOMONIC; // perform inverse gnomonic scaling of r r = Math.Atan(r); // adjust theta for Class III // if a substrate grid, then it's already been adjusted for Class III if (substrate == 0 && H3Index.isResClassIII(res)) { theta = GeoCoord._posAngleRads(theta + Constants.M_AP7_ROT_RADS); } // find theta as an azimuth theta = GeoCoord._posAngleRads(faceAxesAzRadsCII[face, 0] - theta); // now find the point at (r,theta) from the face center GeoCoord._geoAzDistanceRads(ref faceCenterGeo[face], theta, r, ref g); }