/// <summary> /// Surface area in radians^2 of spherical triangle on unit sphere. /// /// For the math, see: /// https://en.wikipedia.org/wiki/Spherical_trigonometry#Area_and_spherical_excess /// </summary> /// <param name="a">length of triangle side A in radians</param> /// <param name="b">length of triangle side B in radians</param> /// <param name="c">length of triangle side C in radians</param> /// <returns>area in radians^2 of triangle on unit sphere</returns> /// <!-- /// geoCoord.c /// double triangleEdgeLengthsToArea /// --> private static decimal TriangleEdgeLengthToArea(decimal a, decimal b, decimal c) { decimal s = (a + b + c) / 2; a = (s - a) / 2; b = (s - b) / 2; c = (s - c) / 2; s /= 2; return(4 * DecimalEx.ATan (DecimalEx.Sqrt(DecimalEx.Tan(s) * DecimalEx.Tan(a) * DecimalEx.Tan(b) * DecimalEx.Tan(c)))); }
/// <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> /// <returns>The spherical coordinates of the cell center point</returns> /// <!-- /// faceIjk.c /// void _hex2dToGeo /// --> public static GeoCoord ToGeoCoord(this Vec2d v, int face, int res, int substrate) { // calculate (r, theta) in hex2d decimal r = v.Magnitude; bool bSubstrate = substrate != 0; if (r < Constants.H3.EPSILON) { return(Constants.FaceIjk.FaceCenterGeo[face]); } decimal theta = DecimalEx.ATan2(v.Y, v.X); // scale for current resolution length u for (var i = 0; i < res; i++) { r /= Constants.FaceIjk.MSqrt7; } // scale accordingly if this is a substrate grid if (substrate != 0) { r /= 3.0m; if (res.IsResClassIii()) { r /= Constants.FaceIjk.MSqrt7; } } r *= Constants.H3.RES0_U_GNOMONIC; // perform inverse gnomonic scaling of r r = DecimalEx.ATan(r); // adjust theta for Class III // if a substrate grid, then it's already been adjusted for Class III if (!bSubstrate && res.IsResClassIii()) { theta = (theta + Constants.H3.M_AP7_ROT_RADS).NormalizeRadians(); } // find theta as an azimuth theta = (Constants.FaceIjk.FaceAxesAzRadsCii[face, 0] - theta).NormalizeRadians(); // now find the point at (r,theta) from the face center return(Constants.FaceIjk.FaceCenterGeo[face] .GetAzimuthDistancePoint(theta, r)); }
public void Test(decimal d, decimal expected, decimal tolerance) { tolerance = Helper.GetScaledTolerance(expected, (int)tolerance, true); Assert.That(DecimalEx.ATan(d), Is.EqualTo(expected).Within(tolerance)); }