private static H3.Cell.Facet GenFacet(Geometry g, int mirror1, int mirror2, Simplex simplex, Vector3D startingPoint) { List <Sphere> mirrors = new List <Sphere>(); mirrors.Add(simplex.Facets[mirror1]); mirrors.Add(simplex.Facets[mirror2]); List <H3.Cell.Edge> startingEdges = new List <H3.Cell.Edge>(); Vector3D reflected = simplex.ReflectInFacet(startingPoint, mirror1); startingEdges.Add(new H3.Cell.Edge(startingPoint, reflected)); reflected = simplex.ReflectInFacet(startingPoint, mirror2); startingEdges.Add(new H3.Cell.Edge(startingPoint, reflected)); startingEdges.RemoveAll(e => e.Start == e.End); if (startingEdges.Count == 0) { return(null); } H3.Cell.Edge[] completedEdges = Recurse.CalcEdges(mirrors.ToArray(), startingEdges.ToArray(), new Recurse.Settings() { G = g }); if (completedEdges.Length == 1) { return(null); } List <Vector3D> facetVerts = new List <Vector3D>(); H3.Cell.Edge edge = completedEdges.First(); Vector3D start = edge.Start; Vector3D current = edge.End; facetVerts.Add(edge.End); while (current != start) { edge = completedEdges.First(e => e != edge && (e.Start == current || e.End == current)); current = edge.Start == current ? edge.End : edge.Start; facetVerts.Add(current); } return(new H3.Cell.Facet(facetVerts.ToArray())); }
private static void CreateCellPovRay(HoneycombDef def, string filename, double t = 0) { int p = def.P; int q = def.Q; int r = def.R; //Vector3D trans = new Vector3D( 1.0/3, 0 ) * (2 + 2 * Math.Sin( Math.PI / 6 )) * t; //double scale = 1.8; Vector3D trans = new Vector3D(); double scale = 1.0; Vector3D[] sVerts = null; // SimplexCalcs.VertsBall( p, q, r ); Vector3D vUHS = H3Models.BallToUHS(SimplexCalcs.VertexPointBall(p, q, r)); // Just did this for everything. Non-general position working better and will make all heads consistent. scale = 2.0; if (Geometry2D.GetGeometry(q, r) != Geometry.Hyperbolic) // Vertex-centered if possible { scale = 1.0 / vUHS.Z; } //else if( Geometry2D.GetGeometry( p, q ) == Geometry.Hyperbolic ) // Make the biggest head somewhat smaller. // scale = 2.0; Vector3D cen = InteriorPointBall; /*var kleinVerts = sVerts.Select( v => HyperbolicModels.PoincareToKlein( v ) ); * Vector3D avg = new Vector3D(); * foreach( Vector3D v in kleinVerts ) * avg += v; * avg /= kleinVerts.Count(); * Vector3D cen = HyperbolicModels.KleinToPoincare( avg );*/ cen = H3Models.BallToUHS(cen); cen += trans; //cen *= scale; cen = H3Models.UHSToBall(cen); Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: false); // Apply transformations. simplex = simplex.Select(s => { Sphere.TranslateSphere(s, trans); Sphere.ScaleSphere(s, scale); return(H3Models.UHSToBall(s)); }).ToArray(); for (int i = 0; i < 4; i++) { if (simplex[i].IsPointInside(cen)) { simplex[i].Invert = true; } } Sphere[] simplexForColorScale = SimplexCalcs.Mirrors(p, q, r, moveToBall: true); CoxeterImages.Settings temp = AutoCalcScale(def, simplexForColorScale); int maxDepth = (int)temp.ColorScaling; //Random rand = new Random( p+q+r ); //int randOffset = rand.Next( maxDepth ); bool ball = true; bool dual = false; H3.Cell[] simplicesFinal = GenCell(simplex, null, cen, ball, dual); using (StreamWriter sw = File.CreateText(filename)) // We need to reuse this StreamWriter (vs. calling AppendSimplex) for performance. { sw.WriteLine("#include \"hyper_ball.pov\""); //int[] include = new int[] { 0, 1, 2, 3 }; int[] include = new int[] { 0 }; if (dual) { include = new int[] { 3 } } ; // Output the facets. foreach (H3.Cell cell in simplicesFinal) { Sphere[] facets = cell.Facets.Select(f => f.Sphere).ToArray(); if (m_toKlein) { facets = facets.Select(s => H3Models.BallToKlein(s)).ToArray(); } int depth = cell.Depths[0] + 1; Color c = Coloring.ColorAlongHexagon(maxDepth, depth); if (cell.Depths.Sum() % 2 == 0) { c = Coloring.Inverse(c); } PovRay.AddSimplex(sw, facets, cell.Center, include, filename, Coloring.ToVec(c)); } /*include = new int[] { 1, 2, 3 }; * foreach( H3.Cell cell in simplicesFinal ) * { * Sphere[] facets = cell.Facets.Select( f => f.Sphere ).ToArray(); * Color c = Color.Red; * Vector3D cv = Coloring.ToVec( c ); * cv.W = 0.9; * PovRay.AddSimplex( sw, facets, cell.Center, include, filename, cv ); * }*/ } // Output the edges/verts. bool includeEdges = false; if (includeEdges) { sVerts = sVerts.Select(v => { v = H3Models.BallToUHS(v); v += trans; v *= scale; return(H3Models.UHSToBall(v)); }).ToArray(); H3.Cell.Edge[] edges = Recurse.CalcEdges(simplex.Skip(1).ToArray(), new H3.Cell.Edge[] { new H3.Cell.Edge(sVerts[2], sVerts[3], order: false) }, new Recurse.Settings() { Threshold = 0.01 }); PovRay.WriteH3Edges(new PovRay.Parameters { AngularThickness = 0.01 }, edges, filename, append: true); HashSet <Vector3D> verts = new HashSet <Vector3D>(); foreach (H3.Cell.Edge e in edges) { verts.Add(e.End); } PovRay.WriteVerts(new PovRay.Parameters { AngularThickness = 0.02 }, Geometry.Hyperbolic, verts.ToArray(), filename, append: true); } }
/// <summary> /// Wendy's 77 /// </summary> public static void Wendy(Simplex simplex, H3.Cell.Edge[] edges) { H3.Cell startingCell = null; Vector3D start = startingCell.Verts.First(); Func <Vector3D, Vector3D> findAntipode = input => { Vector3D antipode = new Vector3D(); double max = double.MinValue; foreach (Vector3D v in startingCell.Verts) { double d = H3Models.Ball.HDist(v, input); if (d > max) { max = d; antipode = v; } } return(antipode); }; H3.Cell.Edge[] diagonals = new H3.Cell.Edge[] { new H3.Cell.Edge(start, findAntipode(start)) }; diagonals = Recurse.CalcEdges(simplex.Facets, diagonals, new Recurse.Settings() { Threshold = 0.9983 }); // diagonals includes too much at this point (it includes all icosahedra diagonals, but we only want one diagonal from each cell). // We need to begin at 4 start points, and branch out from each to find the ones we want. var vertsToDiagonals = FindConnectedEdges(diagonals); var connectedEdges = FindConnectedEdges(edges); // Get all edges (not diagonals) connected to start. List <H3.Cell.Edge> connectedToStart = connectedEdges[start]; Vector3D startOpp = connectedToStart[0].Opp(start); List <H3.Cell.Edge> connectedToStartOpp = connectedEdges[startOpp]; // We need to pick 4 of these edges, arranged in a tetrahedron for our starting points. List <Vector3D> startingPoints = new List <Vector3D>(); List <double> distances = new List <double>(); // View1 //startingPoints.Add( start ); //foreach( Vector3D v in connectedToStartOpp.Select( e => e.Opp( startOpp ) ) ) // distances.Add( H3Models.Ball.HDist( startingPoints.First(), v ) ); //startingPoints.Add( connectedToStartOpp[10].Opp( startOpp ) ); //startingPoints.Add( connectedToStartOpp[13].Opp( startOpp ) ); //startingPoints.Add( connectedToStartOpp[14].Opp( startOpp ) ); // View2 startingPoints.Add(startOpp); foreach (Vector3D v in connectedToStart.Select(e => e.Opp(start))) { distances.Add(H3Models.Ball.HDist(startingPoints.First(), v)); } startingPoints.Add(connectedToStart[10].Opp(start)); startingPoints.Add(connectedToStart[13].Opp(start)); startingPoints.Add(connectedToStart[14].Opp(start)); distances.Clear(); distances.Add(H3Models.Ball.HDist(startingPoints[1], startingPoints[2])); distances.Add(H3Models.Ball.HDist(startingPoints[1], startingPoints[3])); distances.Add(H3Models.Ball.HDist(startingPoints[2], startingPoints[3])); distances.Add(H3Models.Ball.HDist(startingPoints[0], startingPoints[1])); distances.Add(H3Models.Ball.HDist(startingPoints[0], startingPoints[2])); distances.Add(H3Models.Ball.HDist(startingPoints[0], startingPoints[3])); double dist = 3.097167; Func <Vector3D[], H3.Cell.Edge[]> RemoveVerts = starting => { List <H3.Cell.Edge> keepers = new List <H3.Cell.Edge>(); HashSet <Vector3D> removedVerts = new HashSet <Vector3D>(); Recurse.BranchAlongVerts(starting.ToArray(), vertsToDiagonals, removedVerts); foreach (H3.Cell.Edge e in edges) { if (removedVerts.Contains(e.Start) || removedVerts.Contains(e.End)) { continue; } keepers.Add(e); } return(keepers.ToArray()); }; edges = RemoveVerts(startingPoints.ToArray()); bool done = false; while (!done) { done = true; var newConnectedEdges = FindConnectedEdges(edges); foreach (Vector3D v in newConnectedEdges.Keys) { List <H3.Cell.Edge> oldEdgeList = connectedEdges[v]; List <H3.Cell.Edge> newEdgeList = newConnectedEdges[v]; // Only work edges that were full originally. if (oldEdgeList.Count != 20) { continue; } // We need at least two to find the rest. int newCount = newEdgeList.Count; if (newCount > 16 && newCount < 19) { List <H3.Cell.Edge> removed = oldEdgeList.Except(newEdgeList, new H3.Cell.EdgeEqualityComparer()).ToList(); H3.Cell.Edge[] toTrim = newEdgeList.FindAll(e => { foreach (H3.Cell.Edge alreadyRemoved in removed) { double d = H3Models.Ball.HDist(alreadyRemoved.Opp(v), e.Opp(v)); if (!Tolerance.Equal(dist, d, 0.00001)) { return(false); } } return(true); }).ToArray(); edges = RemoveVerts(toTrim.Select(e => e.Opp(v)).ToArray()); done = false; } if (newCount == 20) { done = false; } } } }
/// <summary> /// This generates a honeycomb by reflecting in 4 mirrors of the fundamental simplex. /// This "new" method is now old. /// </summary> public static void OneHoneycombNew(HoneycombDef imageData) { int p = imageData.P; int q = imageData.Q; int r = imageData.R; double thickness = 0.05; double thicknessSpherical = Spherical2D.s2eNorm(thickness); double thicknessHyperbolic = R3.Math.DonHatch.h2eNorm(thickness); double threshold = 1; H3.Cell.Edge[] edges = null; H3.Cell[] cellsToHighlight = null; Sphere[] simplex = null; Vector3D vertex = new Vector3D(); Geometry g = Util.GetGeometry(p, q, r); if (g == Geometry.Spherical) { thickness = thicknessSpherical /*.07 for 333*/ /* 0.05for 433*/ /*.025 for 533,335*/; threshold = 10000; simplex = SimplexCalcs.MirrorsSpherical(p, q, r); vertex = SimplexCalcs.VertexSpherical(p, q, r); // Ugly special casing for 333, since it has a vertex project to infinity. if (p == 3 && q == 3 && r == 3) { SpecialCase333(); } } else if (g == Geometry.Euclidean) { thickness = thickness / 2; threshold = 1 /*20*/; //SimplexCalcs.CalcEScale(); simplex = SimplexCalcs.MirrorsEuclidean(); Vector3D[] verts = SimplexCalcs.VertsEuclidean(); vertex = verts[2]; } else { thickness = thicknessHyperbolic; threshold = 0.01; simplex = SimplexCalcs.Mirrors(p, q, r); Vector3D[] verts = SimplexCalcs.VertsBall(p, q, r); vertex = verts[2]; //Vector3D[] simplexVerts = SimplexCalcs.VertsBall( p, q, r ); //H3.Cell.Edge edge = new H3.Cell.Edge( simplexVerts[2], simplexVerts[3] ); //H3.Cell.Edge edge = SimplexCalcs.HoneycombEdgeBall( p, q, r ); //H3.Cell.Edge[] startingEdges = new H3.Cell.Edge[] { edge }; //H3.Cell.Edge[] edges = Recurse.CalcEdgesSmart2( simplex, startingEdges ); // Vertex Centered. bool vertexCentered = false; if (vertexCentered) { Vector3D v = SimplexCalcs.VertexPointBall(p, q, r); v = H3Models.BallToUHS(v); double scale = 1.0 / v.Abs(); edges = edges.Select(e => { Vector3D start = H3Models.UHSToBall(H3Models.BallToUHS(e.Start) * scale); Vector3D end = H3Models.UHSToBall(H3Models.BallToUHS(e.End) * scale); return(new H3.Cell.Edge(start, end)); }).ToArray(); } // Code to show endpoints of 535 /*using( StreamWriter sw = File.CreateText( "535_points.pov" ) ) * { * HashSet<Vector3D> verts = new HashSet<Vector3D>(); * foreach( H3.Cell.Edge e in edges ) * { * verts.Add( Sterographic.SphereToPlane( e.Start ) ); * verts.Add( Sterographic.SphereToPlane( e.End ) ); * } * * foreach( Vector3D vert in verts ) * if( !Infinity.IsInfinite( vert ) ) * sw.WriteLine( PovRay.Sphere( new Sphere() { Center = vert, Radius = 0.01 } ) ); * }*/ } // Recurse bool dual = false; { H3.Cell.Edge[] startingEdges = null; if (dual) { startingEdges = new H3.Cell.Edge[] { SimplexCalcs.DualEdgeBall(simplex) } } ; else { //startingEdges = new H3.Cell.Edge[] { SimplexCalcs.HoneycombEdgeBall( simplex, vertex ) }; Vector3D[] verts = SimplexCalcs.VertsEuclidean(); Vector3D v1 = verts[0] + 2 * verts[2]; // adjacent cube center Vector3D corner = verts[3]; startingEdges = new H3.Cell.Edge[] { new H3.Cell.Edge(v1, corner) }; } edges = Recurse.CalcEdges(simplex, startingEdges, new Recurse.Settings() { G = g, Threshold = threshold }); edges = edges.Where(e => { int sum = e.Depths.Count(d => d == 0); return(true); }).ToArray(); //CullHalfOfEdges( ref edges ); // No need to cull edges in spherical case. // This was just to generate some images for 350-cell paper. //edges = Cull120Cell( edges ); Simplex tet = new Simplex(); tet.Facets = simplex; if (dual) { H3.Cell.Edge[] oneDualCell = edges.Where(e => e.Depths[2] == 0).ToArray(); simplex = simplex.Skip(1).ToArray(); edges = Recurse.CalcEdges(simplex, oneDualCell, new Recurse.Settings() { G = g, Threshold = threshold }); int[] polyMirrors = new int[] { 0, 1, 3 }; H3.Cell startingCell = HoneycombGen.PolyhedronToHighlight(g, polyMirrors, tet, new Vector3D()); cellsToHighlight = Recurse.CalcCells(simplex, new H3.Cell[] { startingCell }); //cellsToHighlight = new H3.Cell[] { startingCell }; //cellsToHighlight = cellsToHighlight.Skip( 7 ).ToArray(); } else { int[] polyMirrors = new int[] { 1, 2, 3 }; H3.Cell startingCell = HoneycombGen.PolyhedronToHighlight(g, polyMirrors, tet, vertex); //cellsToHighlight = Recurse.CalcCells( simplex, new H3.Cell[] { startingCell } ); cellsToHighlight = new H3.Cell[] { startingCell }; } // Include just one cell? bool includeOne = false; if (includeOne) { edges = edges.Where(e => e.Depths[0] == 0).ToArray(); //cellsToHighlight = cellsToHighlight.Where( c => c.Depths[0] == 0 ).ToArray(); } } // Rotate bool rotate = false; if (rotate) { CompoundOfFive24Cells(ref edges); } // Write the file bool pov = true; if (pov) { string filename = string.Format("{0}{1}{2}.pov", p, q, r); PovRay.WriteEdges(new PovRay.Parameters() { AngularThickness = thickness }, g, edges, filename, append: false); //File.Delete( filename ); //PovRay.AppendFacets( cellsToHighlight, filename ); HashSet <Vector3D> verts = new HashSet <Vector3D>(); foreach (H3.Cell.Edge e in edges) { verts.Add(e.Start); verts.Add(e.End); } /*foreach( Vector3D v in verts ) * { * Vector3D t = v; * t.Normalize(); * t *= 0.9; * System.Diagnostics.Trace.WriteLine( string.Format( "light_source {{ <{0},{1},{2}> White*.2 }}", t.X, t.Y, t.Z ) ); * }*/ /* * // Include the standard pov stuff, so we can batch this. * string fileName = imageData.FormatFilename( string.Empty ); * using( StreamWriter sw = File.CreateText( fileName + ".pov" ) ) * { * sw.WriteLine( "#include \"C:\\Users\\hrn\\Documents\\roice\\povray\\paper\\H3.pov\"" ); * } * * bool dummy = true; // Doesn't matter for Pov-Ray, just Shapeways meshes. * H3.SaveToFile( fileName, edges, dummy, append: true ); */ } else { if (g == Geometry.Spherical) { edges = edges.Where(e => e.Start.Valid() && e.End.Valid() && !Infinity.IsInfinite(e.Start) && !Infinity.IsInfinite(e.End)).ToArray(); S3.EdgesToStl(edges); } else { throw new System.NotImplementedException(); } } }