public static H3.Cell.Edge[] OneHoneycombOrthoscheme(HoneycombDef def, int[] active, int baseHue, Settings settings = null) { // Setup parameters. int numEdges = 250000; if (settings != null) { active = settings.PovRay.Active; def = new HoneycombDef(settings.P, settings.Q, settings.R); numEdges = settings.PovRay.NumEdges; } CalcThickness(active); if (settings != null) { H3.m_settings.AngularThickness = settings.PovRay.EdgeWidth; // ZZZ - should really stop using that settings class. } string baseName = BaseName(def); string mirrorsString = ActiveMirrorsString(active); string suffix = "-" + mirrorsString; string fileName = baseName + suffix; if (ViewPath != null) { fileName += string.Format("_{0:D4}", ViewPath.Step); } if (File.Exists(fileName + ".pov")) { File.Delete(fileName + ".pov"); //Console.WriteLine( string.Format( "Skipping {0}", fileName ) ); //return; } Program.Log(string.Format("Building {0}", fileName)); // The wiki mirrors are labeled in the reverse of ours. Func <int, int> mapMirror = i => 3 - i; active = active.Select(i => mapMirror(i)).OrderBy(i => i).ToArray(); Simplex simplex = new Simplex(); simplex.Facets = SimplexCalcs.Mirrors(def.P, def.Q, def.R); simplex.Verts = SimplexCalcs.VertsBall(def.P, def.Q, def.R); Vector3D startingPoint = IterateToStartingPoint(def, active, simplex); if (startingPoint.DNE) { return(null); } List <H3.Cell.Edge> startingEdges = new List <H3.Cell.Edge>(); foreach (int a in active) { Vector3D reflected = simplex.ReflectInFacet(startingPoint, a); startingEdges.Add(new H3.Cell.Edge(startingPoint, reflected)); //startingEdges.Add( new H3.Cell.Edge( simplex.Verts[0], simplex.Verts[3] ) ); // Used for Borromean Rings complement image. } if (false) { Vector3D[] kv = simplex.Verts.Select(v => HyperbolicModels.PoincareToKlein(v)).ToArray(); kv[3] = SimplexCalcs.VertexPointKlein(def.P, def.Q, def.R); Vector3D t = (kv[3] - kv[0]) * 0.5; Sphere gSphere = H3Models.Ball.OrthogonalSphereInterior(HyperbolicModels.KleinToPoincare(t)); gSphere = H3Models.BallToKlein(gSphere); Vector3D t2 = Euclidean3D.IntersectionPlaneLine(gSphere.Normal, gSphere.Offset, kv[3] - kv[2], kv[2]); //t2 = kv[2] + ( kv[3] - kv[2]) * 0.5; t = HyperbolicModels.KleinToPoincare(t); t2 = HyperbolicModels.KleinToPoincare(t2); startingEdges.Add(new H3.Cell.Edge(t, t2)); startingEdges.Add(new H3.Cell.Edge(t, simplex.ReflectInFacet(t, 3))); } // If we are doing a view path, transform our geometry. if (ViewPath != null) { //Vector3D p = new Vector3D( 0, 0, .5 ); Vector3D p = new Vector3D(0.08, 0.12, 0.07); simplex.Facets = simplex.Facets.Select(f => H3Models.Transform_PointToOrigin(f, p)).ToArray(); simplex.Verts = simplex.Verts.Select(v => H3Models.Transform_PointToOrigin(v, p)).ToArray(); startingEdges = startingEdges.Select(e => new H3.Cell.Edge( H3Models.Transform_PointToOrigin(e.Start, p), H3Models.Transform_PointToOrigin(e.End, p))).ToList(); } SetupBaseHue(fileName, mirrorsString, baseHue); Recurse.m_background = baseHue == -1 ? new Vector3D() : new Vector3D(baseHue, 1, .1); H3.Cell.Edge[] edges = Recurse.CalcEdgesSmart2(simplex.Facets, startingEdges.ToArray(), numEdges); //H3.Cell.Edge[] edges = Recurse.CalcEdges( simplex.Facets, startingEdges.ToArray(), // new Recurse.Settings() { ThreshType = Recurse.EdgeThreshType.Radial, Threshold = H3Models.Ball.FindLocationForDesiredRadius( settings.PovRay.EdgeWidth, 0.8/100 ) } ); //edges = edges.Where( e => e.Depths[0] % 2 == 1 ).ToArray(); // Used for Borromean Rings complement image. // Shapeways truncated 436. if (false) { if (true) { Mobius m = Mobius.Scale(1.0 / H3Models.UHS.ToE(Honeycomb.InRadius(def.P, def.Q, def.R))); double a = -Math.PI / 2 + Math.Asin(1 / Math.Sqrt(3)); edges = edges.Select(e => { Vector3D v1 = e.Start; Vector3D v2 = e.End; v1.RotateAboutAxis(new Vector3D(1, 0, 0), a); v2.RotateAboutAxis(new Vector3D(1, 0, 0), a); v1 = H3Models.Ball.ApplyMobius(m, v1); v2 = H3Models.Ball.ApplyMobius(m, v2); return(new H3.Cell.Edge(v1, v2)); }).ToArray(); double thresh = -.01; Vector3D looking = new Vector3D(0, 0, -1); edges = edges.Where(e => e.Start.Dot(looking) > thresh && e.End.Dot(looking) > thresh).ToArray(); Dictionary <H3.Cell.Edge, int> edgeDict = edges.ToDictionary(e => e, e => 1); H3.RemoveDanglingEdgesRecursive(edgeDict); edges = edgeDict.Keys.ToArray(); } else { Mobius m = Mobius.Scale(2); edges = edges.Select(e => { Vector3D v1 = e.Start; Vector3D v2 = e.End; v1 = H3Models.Ball.ApplyMobius(m, v1); v2 = H3Models.Ball.ApplyMobius(m, v2); return(new H3.Cell.Edge(v1, v2)); }).ToArray(); Dictionary <H3.Cell.Edge, int> edgeDict = edges.ToDictionary(e => e, e => 1); H3.RemoveDanglingEdgesRecursive(edgeDict); edges = edgeDict.Keys.ToArray(); } } //H3.m_settings.Output = H3.Output.STL; //H3.m_settings.Scale = 50; H3.SaveToFile(fileName, edges, finite: true, append: true); bool doCells = false; H3.Cell[] cellsToHighlight = null; if (doCells) { int[] polyMirrors = new int[] { 1, 2, 3 }; active = active.Select(i => mapMirror(i)).OrderBy(i => i).ToArray(); H3.Cell startingCell = PolyhedronToHighlight(Geometry.Hyperbolic, polyMirrors, simplex, startingPoint); cellsToHighlight = Recurse.CalcCells(simplex.Facets, new H3.Cell[] { startingCell }); H3.AppendFacets(fileName, cellsToHighlight); } return(edges); }
/// <summary> /// Our approach will be: /// (1) Generate a portion of one cell. /// (2) Reflect all facets in the central facet, to get things filled-in inside the central facet. (Trim small edges here?) /// (3) Copy this region around the plane, and go back to step (2) if density is not high enough. /// (4) Map to Ball, trimming edges that become too small. /// NOTE: All verts are on the boundary, so we can reflect around // in circles on the plane at infinity, rather than spheres. /// </summary> public static void GenerateExotic(EHoneycomb honeycomb, H3.Settings settings) { settings.AngularThickness = 0.17; Tiling tiling; Tile baseTile; GetAssociatedTiling(honeycomb, out tiling, out baseTile); List <H3.Cell.Edge> edges = new List <H3.Cell.Edge>(); foreach (Segment seg in baseTile.Boundary.Segments) { edges.Add(new H3.Cell.Edge(seg.P1, seg.P2)); } settings.Position = Polytope.Projection.FaceCentered; double scale = 1; Vector3D offset = new Vector3D(); if (settings.Position == Polytope.Projection.FaceCentered) { scale = FaceCenteredScale(baseTile.VertexCircle); offset = new Vector3D(); } else if (settings.Position == Polytope.Projection.EdgeCentered) { scale = EdgeCenteredScale(baseTile); offset = baseTile.Boundary.Segments[0].Midpoint; } int iterations = m_params.Iterations; for (int i = 0; i < iterations; i++) { edges = DoOneStep(edges, tiling, baseTile.VertexCircle); } edges = CopyAndProject(edges, tiling, scale, offset); if (m_params.RemoveDangling) { Dictionary <H3.Cell.Edge, int> edgeDict = edges.ToDictionary(e => e, e => 1); H3.RemoveDanglingEdgesRecursive(edgeDict); edges = edgeDict.Keys.ToList(); } string outputFileName = H3.m_baseDir + Honeycomb.String(honeycomb, false); System.IO.File.Delete(outputFileName); if (m_params.Output == H3.Output.STL) { outputFileName += ".stl"; // Now mesh the edges. Shapeways mesh = new Shapeways(); foreach (H3.Cell.Edge edge in edges) { // Append to the file vs. writing out all at once because I was running out of memory otherwise. mesh = new Shapeways(); int div; H3Models.Ball.LODThin(edge.Start, edge.End, out div); mesh.Div = div; H3.Util.AddToMeshInternal(mesh, edge.Start, edge.End); mesh.Mesh.Scale(settings.Scale); STL.AppendMeshToSTL(mesh.Mesh, outputFileName); } } else { outputFileName += ".pov"; PovRay.WriteH3Edges(new PovRay.Parameters() { AngularThickness = settings.AngularThickness, Halfspace = settings.Halfspace, ThinEdges = settings.ThinEdges, }, edges.ToArray(), outputFileName); } }