/// <summary> /// Calculate basePoints along a circle defined by a center on the z axis, and going through the point (0,0,1). /// .5 is horosphere, 1 is geodesic /// Result is in UHS model /// </summary> private static Vector3D[] BasePointsCircle(double centerUHS) { if (centerUHS > 1) { centerUHS = 1; } if (centerUHS < 0) { centerUHS = 0; } if (centerUHS == 0) { return new Vector3D[] { new Vector3D() } } ; bool hyperbolicOffsets = true; if (hyperbolicOffsets) { // h-distance between each point. double d = 0.1; // We need to work in 2D first, then we'll switch to xz plane. Circle circle = new Circle(new Vector3D(0, 1), new Vector3D(0, 1 - 2 * centerUHS), new Vector3D(centerUHS, 1 - centerUHS)); // XXX - check to make sure total distance won't wrap around the circle. List <Vector3D> points = new List <Vector3D>(); int count = 75; for (int i = -count; i <= count; i++) { double currentD = d * i; // Angle t around a circle with center c and radius r to get an h-distance. // https://en.wikipedia.org/wiki/Poincar%C3%A9_half-plane_model // http://www.wolframalpha.com/input/?i=d+%3D+arcosh%281%2B%28%28r*sin%28t%29%29%5E2%2B%28r*cos%28t%29-r%29%5E2%29%2F%282*%28c%2Br%29*%28c%2Br*cos%28t%29%29%29%29%2C+solve+for+t double c = circle.Center.Y; double r = circle.Radius; double coshd = DonHatch.cosh(currentD); double numerator = c * c - c * (c + r) * coshd + c * r + r * r; double denominator = r * ((c + r) * coshd - c); double angle = Math.Acos(numerator / denominator); if (i < 0) { angle *= -1; } points.Add(new Vector3D(r * Math.Sin(angle), 0, c + r * Math.Cos(angle))); /* * // XXX - This was my first attempt, but this code only works for geodesics, not general arcs! * // Equidistant lines in UHS will all be lines through the origin. * // In the following formula, x is the angle to use to get h-spaced equidistant line a distance d away. * // http://www.wolframalpha.com/input/?i=d+%3D+arccosh%28sec%28x%29%29%2C+solve+for+x * double angle = Math.Acos( 1.0 / DonHatch.cosh( currentD ) ); * angle = Math.PI/2 - angle; * if( i < 0 ) * angle *= -1; * * Vector3D p1, p2; * Euclidean2D.IntersectionLineCircle( new Vector3D(), new Vector3D( Math.Cos(angle), Math.Sin(angle) ), circle, out p1, out p2 ); * Vector3D highest = p1.Y > p2.Y ? p1 : p2; * points.Add( new Vector3D( highest.X, 0, highest.Y ) ); */ } return(points.ToArray()); } else { // equal euclidean spacing. Circle3D c = new Circle3D(new Vector3D(0, 0, 1), new Vector3D(0, 0, 1 - 2 * centerUHS), new Vector3D(centerUHS, 0, 1 - centerUHS)); return(c.Subdivide(125)); } }