public void InitializeGoursat() { //Vector3D[] test = SimplexCalcs.GoursatTetrahedron( 3.5, 3.8, 3.1, 2.2, 2.01, 2.1 ); // Example values from paper. //Verts = SimplexCalcs.GoursatTetrahedron( 2, 4, 3, 2, 3, 3 ); // 4,3,3,3 //Verts = SimplexCalcs.GoursatTetrahedron( 2, 5, 3, 2, 3, 3 ); // 5,3,3,3 //Verts = SimplexCalcs.GoursatTetrahedron( 2, 4, 3, 2, 4, 3 ); // 4,3,4,3 //Verts = SimplexCalcs.GoursatTetrahedron( 2, 4, 3, 2, 5, 3 ); // 4,3,5,3 //Verts = SimplexCalcs.GoursatTetrahedron( 2, 5, 3, 2, 5, 3 ); // 5,3,5,3 //Verts = SimplexCalcs.GoursatTetrahedron( 3, 5, 3, 2, 2, 2 ); // 5,3^1,1 //Verts = SimplexCalcs.GoursatTetrahedron( 3, 2, 2, 2, 5, 3 ); // 5,3^1,1 alt (to avoid vertices at origin). // Paracompact doesn't work :( //Verts = SimplexCalcs.GoursatTetrahedron( 2, 6, 3, 2, 6, 3 ); // 6,3,6,3 // Regular Verts = SimplexCalcs.GoursatTetrahedron(2, 5, 3, 2, 4, 2); // 5,3,4 //Verts = SimplexCalcs.GoursatTetrahedron( 2, 4, 3, 2, 5, 2 ); // 4,3,5 //Verts = SimplexCalcs.GoursatTetrahedron( 2, 5, 3, 2, 5, 2 ); // 5,3,5 //Verts = SimplexCalcs.GoursatTetrahedron( 2, 5, 2, 2, 5, 3 ); // 5,3,5 (Alt) //Verts = SimplexCalcs.GoursatTetrahedron( 2, 3, 5, 2, 3, 2 ); // 3,5,3 // Spherical doesn't work :( //Verts = SimplexCalcs.GoursatTetrahedron( 2, 5, 3, 2, 3, 2 ); // 5,3,3 Facets = SimplexCalcs.Mirrors(Verts); }
public static Sphere[] Mirrors(int p, int q, int r, ref Vector3D cellCenter, bool moveToBall = true, double scaling = -1) { Geometry g = Util.GetGeometry(p, q, r); if (g == Geometry.Spherical) { // These are in the ball model. Sphere[] result = SimplexCalcs.MirrorsSpherical(p, q, r); return(result); } else if (g == Geometry.Euclidean) { return(SimplexCalcs.MirrorsEuclidean()); } // This is a rotation we'll apply to the mirrors at the end. // This is to try to make our image outputs have vertical bi-lateral symmetry and the most consistent in all cases. // NOTE: + is CW, not CCW. (Because the way I did things, our images have been reflected vertically, and I'm too lazy to go change this.) double rotation = Math.PI / 2; // Some construction points we need. Vector3D p1, p2, p3; Segment seg = null; TilePoints(p, q, out p1, out p2, out p3, out seg); // // Construct in UHS // Geometry cellGeometry = Geometry2D.GetGeometry(p, q); Vector3D center = new Vector3D(); double radius = 0; if (cellGeometry == Geometry.Spherical) { // Finite or Infinite r // Spherical trig double halfSide = Geometry2D.GetTrianglePSide(q, p); double mag = Math.Sin(halfSide) / Math.Cos(Util.PiOverNSafe(r)); mag = Math.Asin(mag); // e.g. 43j //mag *= 0.95; // Move mag to p1. mag = Spherical2D.s2eNorm(mag); H3Models.Ball.DupinCyclideSphere(p1, mag, Geometry.Spherical, out center, out radius); } else if (cellGeometry == Geometry.Euclidean) { center = p1; radius = p1.Dist(p2) / Math.Cos(Util.PiOverNSafe(r)); } else if (cellGeometry == Geometry.Hyperbolic) { if (Infinite(p) && Infinite(q) && FiniteOrInfinite(r)) { //double iiiCellRadius = 2 - Math.Sqrt( 2 ); //Circle3D iiiCircle = new Circle3D() { Center = new Vector3D( 1 - iiiCellRadius, 0, 0 ), Radius = iiiCellRadius }; //radius = iiiCellRadius; // infinite r //center = new Vector3D( 1 - radius, 0, 0 ); // For finite r, it was easier to calculate cell facet in a more symmetric position, // then move into position with the other mirrors via a Mobius transformation. double rTemp = 1 / (Math.Cos(Util.PiOverNSafe(r)) + 1); Mobius m = new Mobius(); m.Isometry(Geometry.Hyperbolic, -Math.PI / 4, new Vector3D(0, Math.Sqrt(2) - 1)); Vector3D c1 = m.Apply(new Vector3D(1 - 2 * rTemp, 0, 0)); Vector3D c2 = c1; c2.Y *= -1; Vector3D c3 = new Vector3D(1, 0); Circle3D c = new Circle3D(c1, c2, c3); radius = c.Radius; center = c.Center; } else if (Infinite(p) && Finite(q) && FiniteOrInfinite(r)) { // http://www.wolframalpha.com/input/?i=r%2Bx+%3D+1%2C+sin%28pi%2Fp%29+%3D+r%2Fx%2C+solve+for+r // radius = 2 * Math.Sqrt( 3 ) - 3; // Appolonian gasket wiki page //radius = Math.Sin( Math.PI / q ) / ( Math.Sin( Math.PI / q ) + 1 ); //center = new Vector3D( 1 - radius, 0, 0 ); // For finite r, it was easier to calculate cell facet in a more symmetric position, // then move into position with the other mirrors via a Mobius transformation. double rTemp = 1 / (Math.Cos(Util.PiOverNSafe(r)) + 1); Mobius m = new Mobius(); m.Isometry(Geometry.Hyperbolic, 0, p2); Vector3D findingAngle = m.Inverse().Apply(new Vector3D(1, 0)); double angle = Math.Atan2(findingAngle.Y, findingAngle.X); m.Isometry(Geometry.Hyperbolic, angle, p2); Vector3D c1 = m.Apply(new Vector3D(1 - 2 * rTemp, 0, 0)); Vector3D c2 = c1; c2.Y *= -1; Vector3D c3 = new Vector3D(1, 0); Circle3D c = new Circle3D(c1, c2, c3); radius = c.Radius; center = c.Center; } else if (Finite(p) && Infinite(q) && FiniteOrInfinite(r)) { radius = p2.Abs(); // infinite r radius = DonHatch.asinh(Math.Sinh(DonHatch.e2hNorm(p2.Abs())) / Math.Cos(Util.PiOverNSafe(r))); // hyperbolic trig // 4j3 //m_jOffset = radius * 0.02; //radius += m_jOffset ; radius = DonHatch.h2eNorm(radius); center = new Vector3D(); rotation *= -1; } else if (/*Finite( p ) &&*/ Finite(q)) { // Infinite r //double mag = Geometry2D.GetTrianglePSide( q, p ); // Finite or Infinite r double halfSide = Geometry2D.GetTrianglePSide(q, p); double mag = DonHatch.asinh(Math.Sinh(halfSide) / Math.Cos(Util.PiOverNSafe(r))); // hyperbolic trig H3Models.Ball.DupinCyclideSphere(p1, DonHatch.h2eNorm(mag), out center, out radius); } else { throw new System.NotImplementedException(); } } Sphere cellBoundary = new Sphere() { Center = center, Radius = radius }; Sphere[] interior = InteriorMirrors(p, q); Sphere[] surfaces = new Sphere[] { cellBoundary, interior[0], interior[1], interior[2] }; // Apply rotations. bool applyRotations = true; if (applyRotations) { foreach (Sphere s in surfaces) { RotateSphere(s, rotation); } p1.RotateXY(rotation); } // Apply scaling bool applyScaling = scaling != -1; if (applyScaling) { //double scale = 1.0/0.34390660467269524; //scale = 0.58643550768408892; foreach (Sphere s in surfaces) { Sphere.ScaleSphere(s, scaling); } } bool facetCentered = false; if (facetCentered) { PrepForFacetCentering(p, q, surfaces, ref cellCenter); } // Move to ball if needed. if (moveToBall) { surfaces = MoveToBall(surfaces, ref cellCenter); } return(surfaces); }
/// <summary> /// Returns the 6 simplex edges in the UHS model. /// </summary> public static H3.Cell.Edge[] SimplexEdgesUHS(int p, int q, int r) { // Only implemented for honeycombs with hyperideal cells right now. if (!(Geometry2D.GetGeometry(p, q) == Geometry.Hyperbolic)) { throw new System.NotImplementedException(); } Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: false); Circle[] circles = simplex.Select(s => H3Models.UHS.IdealCircle(s)).ToArray(); Vector3D[] defPoints = new Vector3D[6]; Vector3D dummy; Euclidean2D.IntersectionLineCircle(circles[1].P1, circles[1].P2, circles[0], out defPoints[0], out dummy); Euclidean2D.IntersectionLineCircle(circles[2].P1, circles[2].P2, circles[0], out defPoints[1], out dummy); Euclidean2D.IntersectionLineCircle(circles[1].P1, circles[1].P2, circles[3], out defPoints[2], out dummy); Euclidean2D.IntersectionLineCircle(circles[2].P1, circles[2].P2, circles[3], out defPoints[3], out dummy); Circle3D c = simplex[0].Intersection(simplex[3]); Vector3D normal = c.Normal; normal.RotateXY(Math.PI / 2); Vector3D intersection; double height, off; Euclidean2D.IntersectionLineLine(c.Center, c.Center + normal, circles[1].P1, circles[1].P2, out intersection); off = (intersection - c.Center).Abs(); height = Math.Sqrt(c.Radius * c.Radius - off * off); intersection.Z = height; defPoints[4] = intersection; Euclidean2D.IntersectionLineLine(c.Center, c.Center + normal, circles[2].P1, circles[2].P2, out intersection); off = (intersection - c.Center).Abs(); height = Math.Sqrt(c.Radius * c.Radius - off * off); intersection.Z = height; defPoints[5] = intersection; // Hyperideal vertex too? bool order = false; H3.Cell.Edge[] edges = null; if (Geometry2D.GetGeometry(q, r) == Geometry.Hyperbolic) { edges = new H3.Cell.Edge[] { new H3.Cell.Edge(new Vector3D(), new Vector3D(0, 0, 10)), new H3.Cell.Edge(defPoints[4], defPoints[5], order), new H3.Cell.Edge(defPoints[0], defPoints[4], order), new H3.Cell.Edge(defPoints[1], defPoints[5], order), new H3.Cell.Edge(defPoints[2], defPoints[4], order), new H3.Cell.Edge(defPoints[3], defPoints[5], order), }; } else { Vector3D vPointUHS = H3Models.BallToUHS(VertexPointBall(p, q, r)); defPoints[0] = defPoints[1] = vPointUHS; edges = new H3.Cell.Edge[] { new H3.Cell.Edge(vPointUHS, new Vector3D(0, 0, 10)), new H3.Cell.Edge(defPoints[4], defPoints[5], order), new H3.Cell.Edge(defPoints[0], defPoints[4], order), new H3.Cell.Edge(defPoints[1], defPoints[5], order), new H3.Cell.Edge(defPoints[2], defPoints[4], order), new H3.Cell.Edge(defPoints[3], defPoints[5], order), }; } return(edges); }
public void InitializeGoursat(int[] dihedrals) { Verts = SimplexCalcs.GoursatTetrahedron(dihedrals[0], dihedrals[1], dihedrals[2], dihedrals[3], dihedrals[4], dihedrals[5]); Facets = SimplexCalcs.Mirrors(Verts); }