/// <summary> /// Used to generate a regular cell as a set of simplices and save to a Pov-ray file. /// This will work for non-finite cells. /// </summary> internal static H3.Cell[] GenCell(Sphere[] simplex, Mesh mesh, Vector3D cen, bool ball, bool dual) { // We don't want to include the first mirror (which reflects across cells). Sphere[] mirrors = simplex.Skip(1).ToArray(); if (dual) { mirrors = new Sphere[] { simplex[0], simplex[1], simplex[2] } } ; //Sphere[] allMirrors = simplex.ToArray(); mirrors = simplex.ToArray(); // Simplices will be the "cells" in Recurse.CalcCells. H3.Cell.Facet[] simplexFacets = simplex.Select(m => new H3.Cell.Facet(m)).ToArray(); H3.Cell startingCell = new H3.Cell(simplexFacets); startingCell.Center = cen; startingCell.Mesh = mesh; //FCOrient( startingCell ); startingCell = startingCell.Clone(); // So our mirrors don't get munged after we reflect around later. //H3.Cell[] simplices = Recurse.CalcCells( mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball } ); H3.Cell[] simplices = Recurse.CalcCellsSmart(mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball }, (int)(2.5e6)); //H3.Cell[] simplices = new H3.Cell[] { startingCell }; // Layers. //int layer = 0; //return simplices.Where( s => s.Depths[0] <= layer /*&& s.Depths[0] == 3 && s.Depths[1] == 3*/ ).ToArray(); return(simplices.ToArray()); }
private static string H3Facet(H3.Cell cell, HashSet <Sphere> completed) { StringBuilder sb = new StringBuilder(); foreach (H3.Cell.Facet facet in cell.Facets) { if (completed.Contains(facet.Sphere)) { continue; } bool invert1 = !facet.Sphere.IsPointInside(cell.Center); sb.Append(string.Format("sphere {{ {0}, {1:G6}{2} material {{ sphereMat }} clipped_by {{ ball }}", FormatVec(facet.Sphere.Center), facet.Sphere.Radius, invert1 ? " inverse" : string.Empty)); H3.Cell.Facet[] others = cell.Facets.Except(new H3.Cell.Facet[] { facet }).ToArray(); foreach (H3.Cell.Facet otherFacet in others) { bool invert = !otherFacet.Sphere.IsPointInside(cell.Center); sb.Append(string.Format(" clipped_by {{ {0} }}", FormatSphereNoMaterial(otherFacet.Sphere, invert))); } sb.AppendLine(" }"); completed.Add(facet.Sphere); } return(sb.ToString()); }
private static void ReflectCellsRecursive(Sphere[] simplex, H3.Cell[] cells, Settings settings, List <H3.Cell> completedCells, HashSet <Vector3D> completedCellIds) { if (0 == cells.Length) { return; } List <H3.Cell> newCells = new List <H3.Cell>(); foreach (H3.Cell cell in cells) { //foreach( Sphere mirror in simplex ) //for( int m=0; m<simplex.Length; m++ ) for (int m = simplex.Length - 1; m >= 0; m--) { Sphere mirror = simplex[m]; //if( m == 2 ) // continue; //if( completedCellIds.Count > 1000 ) // return; //if( completedCellIds.Count > settings.MaxEdges/5 ) if (completedCellIds.Count > settings.MaxEdges * 3) { throw new System.Exception("Maxing out cells - will result in uneven filling."); } H3.Cell newCell = cell.Clone(); newCell.Reflect(mirror); // This tracks reflections across the cell facets. newCell.Depths[m]++; newCell.LastReflection = m; //if( newCell.Depths[0] > 2 ) // continue; if (!CellOk(newCell, settings)) { continue; } if (completedCellIds.Add(newCell.ID)) { // Haven't seen this cell yet, so // we'll need to recurse on it. newCells.Add(newCell); completedCells.Add(newCell); } } } ReflectCellsRecursive(simplex, newCells.ToArray(), settings, completedCells, completedCellIds); }
private static void ReflectCellsRecursive2(Sphere[] simplex, H3.Cell[] cells, Settings settings, List <H3.Cell> completedCells, HashSet <Vector3D> completedCellIds) { if (0 == cells.Length) { return; } List <H3.Cell> newCells = new List <H3.Cell>(); foreach (H3.Cell cell in cells) { //foreach( Sphere mirror in simplex ) for (int m = 0; m < simplex.Length; m++) { Sphere mirror = simplex[m]; if (completedCellIds.Count > 250000) { return; } H3.Cell newCell = cell.Clone(); newCell.Reflect(mirror); //if( !CellOk( newCell, settings ) ) bool cellOk = true; foreach (H3.Cell.Facet f in cell.Facets) { if (f.Sphere.Radius < 0.002) { cellOk = false; } } if (!cellOk) { continue; } // This tracks reflections across the cell facets. newCell.Depths[m]++; if (completedCellIds.Add(newCell.ID)) { // Haven't seen this cell yet, so // we'll need to recurse on it. newCells.Add(newCell); completedCells.Add(newCell); } } } ReflectCellsRecursive2(simplex, newCells.ToArray(), settings, completedCells, completedCellIds); }
private static H3.Cell[] GenTruss(Sphere[] simplex, Mesh mesh, Vector3D cen, bool ball) { // We don't want to include the first mirror (which reflects across cells). Sphere[] mirrors = simplex.Skip(1).ToArray(); Sphere[] allMirrors = simplex.ToArray(); // Simplices will be the "cells" in Recurse.CalcCells. H3.Cell.Facet[] simplexFacets = simplex.Select(m => new H3.Cell.Facet(m)).ToArray(); H3.Cell startingCell = new H3.Cell(simplexFacets); startingCell.Center = cen; //FCOrient( startingCell ); //return null; startingCell = startingCell.Clone(); // So our mirrors don't get munged after we reflect around later. H3.Cell[] simplices = Recurse.CalcCells(mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball }); //H3.Cell[] simplices = new H3.Cell[] { startingCell }; // Subsets //return simplices.Where( s => s.Depths[0] == 1 ).ToArray(); //return simplices.ToArray(); List <H3.Cell> final = new List <H3.Cell>(); final.AddRange(simplices); // Add in other truss cells. Recurse.Settings settings = new Recurse.Settings(); foreach (int[] reflections in TrussReflections()) { foreach (H3.Cell c in simplices) { H3.Cell clone = c.Clone(); foreach (int r in reflections) { clone.Reflect(allMirrors[r]); } if (Recurse.CellOk(clone, settings)) { final.Add(clone); } } } return(final.ToArray()); }
/// <summary> /// Face centered orientation. /// </summary> internal static void FCOrient(H3.Cell cell) { // First, need to scale so the lowest triangles are the same size, // then reorient so that one triangle is oriented along z axis, // then scale so that the triangle is flat. // Calculate how much we need to offset to make the cell facet flat. Mobius m = FCOrientMobius(cell.Facets[0].Sphere); foreach (H3.Cell.Facet f in cell.Facets) { H3Models.TransformInBall2(f.Sphere, m); } cell.Center = H3Models.TransformHelper(cell.Center, m); }
private static H3.Cell[] GenCell(Sphere[] simplex, Mesh mesh, Vector3D cen, Vector3D[] auxPoints, bool ball) { //Sphere[] mirrors = simplex.Skip(1).ToArray(); Sphere[] mirrors = simplex.ToArray(); H3.Cell.Facet[] simplexFacets = simplex.Select(m => new H3.Cell.Facet(m)).ToArray(); H3.Cell startingCell = new H3.Cell(simplexFacets); startingCell.Center = cen; startingCell.Mesh = mesh; startingCell.AuxPoints = auxPoints; startingCell = startingCell.Clone(); // So our mirrors don't get munged after we reflect around later. H3.Cell[] simplices = Recurse.CalcCells(mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball, Threshold = m_thresh }); //return simplices.Where( s => s.Depths[0] <= layer /*&& s.Depths[0] == 3 && s.Depths[1] == 3*/ ).ToArray(); return(simplices.ToArray()); }
public static H3.Cell PolyhedronToHighlight(Geometry g, int[] mirrors, Simplex simplex, Vector3D startingPoint) { if (mirrors.Length != 3) { throw new System.Exception("We need exactly three mirrors to generate a polyhedron."); } // In the general case, we can have 3 types of polygons, each being generated by choosing 2 of the 3 mirrors. // When fewer polygon types exist, GenFacet will return null, so we need to check that. List <H3.Cell.Facet> polyFacets = new List <H3.Cell.Facet>(); polyFacets.Add(GenFacet(g, mirrors[0], mirrors[1], simplex, startingPoint)); polyFacets.Add(GenFacet(g, mirrors[1], mirrors[2], simplex, startingPoint)); polyFacets.Add(GenFacet(g, mirrors[0], mirrors[2], simplex, startingPoint)); polyFacets.RemoveAll(f => f == null); HashSet <Vector3D> completedFacetIds = new HashSet <Vector3D>(); foreach (H3.Cell.Facet f in polyFacets) { completedFacetIds.Add(f.ID); } Recurse.GenPolyhedron(mirrors.Select(m => simplex.Facets[m]).ToArray(), polyFacets.ToArray(), polyFacets, completedFacetIds); H3.Cell cell = new H3.Cell(polyFacets.ToArray()); // Calc a center. XXX - totally wrong. Vector3D center = new Vector3D(); foreach (Vector3D v in cell.Verts) { center += v; } center /= cell.Verts.Count(); cell.Center = center; // Calc the spheres. foreach (H3.Cell.Facet f in cell.Facets) { f.CalcSphereFromVerts(g); } return(cell); }
internal static bool CellOk(H3.Cell cell) { foreach (H3.Cell.Facet f in cell.Facets) { if (f.Sphere.IsPlane) { continue; } if (f.Sphere.Radius < .05) { return(false); } } return(true); }
private static string H3Facet(H3.Cell cell, HashSet <Sphere> completed) { StringBuilder sb = new StringBuilder(); foreach (H3.Cell.Facet facet in cell.Facets) { //if( completed.Contains( facet.Sphere ) ) // continue; bool invert1 = !facet.Sphere.IsPointInside(cell.Center); if (facet.Sphere.Invert) { invert1 = !invert1; } //bool invert1 = CheckForInvert( facet.Sphere, cell.Center ); sb.Append(string.Format("{0} texture {{ facet_tex }} clipped_by {{ ball }}", FormatSphereNoMaterialOffset(facet.Sphere, invert1, false))); H3.Cell.Facet[] others = cell.Facets.Except(new H3.Cell.Facet[] { facet }).ToArray(); foreach (H3.Cell.Facet otherFacet in others) { bool invert = !otherFacet.Sphere.IsPointInside(cell.Center); if (otherFacet.Sphere.Invert) { invert = !invert; } //bool invert = CheckForInvert( otherFacet.Sphere, cell.Center ); sb.Append(string.Format(" clipped_by {{ {0} }}", FormatSphereNoMaterial(otherFacet.Sphere, invert))); } sb.AppendLine(" }"); completed.Add(facet.Sphere); } return(sb.ToString()); }
public static void Test() { HoneycombDef def = new HoneycombDef(5, 3, 4); Simplex simplex = new Simplex(); simplex.Facets = SimplexCalcs.Mirrors(def.P, def.Q, def.R); // Simplices will be the "cells" H3.Cell.Facet[] simplexFacets = simplex.Facets.Select(m => new H3.Cell.Facet(m)).ToArray(); H3.Cell startingCell = new H3.Cell(simplexFacets); startingCell.AuxPoints = SimplexCalcs.VertsBall(def.P, def.Q, def.R); startingCell.Center = HoneycombPaper.InteriorPointBall; var cells = CalcCells(simplex.Facets, new H3.Cell[] { startingCell }); // Get all the cell centers HashSet <Vector3D> centers = new HashSet <Vector3D>(); foreach (var cell in cells) { Vector3D cellCen = cell.AuxPoints[0]; centers.Add(cellCen); } // Colors. Dictionary <double, Color> colors = new Dictionary <double, Color>(new DoubleEqualityComparer()); System.Random rand = new System.Random(0); // Get all the in-spheres double inRad = startingCell.AuxPoints[1].Abs(); //inRad *= 1.16; List <Sphere> inSpheres = new List <Sphere>(); foreach (Vector3D c in centers) { Vector3D p = c; //SphericalModels.GnomonicToStereo( c ); Geometry g = Geometry.Hyperbolic; Vector3D cen; double rad; H3Models.Ball.DupinCyclideSphere(p, inRad, g, out cen, out rad); Sphere i = new Sphere(cen, rad); Color color; if (!colors.TryGetValue(c.Abs(), out color)) { Vector3D rgb = ColorUtil.CHSL2RGB(new Vector3D(rand.NextDouble() * 360, .5, .5)); rgb *= 255; color = Color.FromArgb(255, (int)rgb.X, (int)rgb.Y, (int)rgb.Z); colors[c.Abs()] = color; } i.Color = color; inSpheres.Add(i); } // Project sphere to unit sphere. List <Circle3D> circlesOnUnitSphere = new List <Circle3D>(); foreach (Sphere i in inSpheres) { if (i.Center.IsOrigin || i.Center.DNE || Infinity.IsInfinite(i.Center)) { continue; } Sphere orthogonal = new Sphere(new Vector3D(), RadiusOrthogonal(i)); Circle3D c = orthogonal.Intersection(i); // We need to scale this based on the size of the orthogonal sphere. c.Center /= orthogonal.Radius; c.Radius /= orthogonal.Radius; c.Color = i.Color; circlesOnUnitSphere.Add(c); } Circle3D unit = new Circle3D(); //circlesOnUnitSphere.Add( unit ); ProjectAndSave(circlesOnUnitSphere); }
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); }
public static void OneHoneycombGoursat(int[] active, string baseName, int baseHue, Settings settings = null) { // Setup parameters. int numEdges = 250000; if (settings != null) { active = settings.PovRay.Active; numEdges = settings.PovRay.NumEdges; baseName = string.Join("-", settings.Angles); } CalcThickness(active); if (settings != null) { H3.m_settings.AngularThickness = settings.PovRay.EdgeWidth; // ZZZ - should really stop using that settings class. } // Create the simplex. Simplex simplex = new Simplex(); if (settings != null) { simplex.InitializeGoursat(settings.Angles); } else { simplex.InitializeGoursat(); } // Map of labels for mirrors consistent with input scheme to Goursat function. // Map is from wikipedia labeling scheme to the indices our function generates. // // wiki == our index // 0100 == 0 // 0001 == 1 // 1000 == 2 // 0010 == 3 Func <int, int> mapMirror = i => { switch (i) { case 0: return(2); case 1: return(0); case 2: return(3); case 3: return(1); } throw new System.ArgumentException(); }; // We need to set this up before converting the mirrors. string mirrorsString = ActiveMirrorsString(active); string suffix = "_" + mirrorsString; // Convert our active mirrors into the Goursat tet indices. int[] polyMirrors = new int[] { 1, 2, 3 }; active = active.Select(i => mapMirror(i)).OrderBy(i => i).ToArray(); polyMirrors = polyMirrors.Select(i => mapMirror(i)).OrderBy(i => i).ToArray(); Vector3D startingPoint = IterateToStartingPoint(null, active, simplex); 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)); } bool doEdges = true; bool doCells = false; // Generate the honeycomb. H3.Cell.Edge[] edges = null; if (doEdges) { edges = Recurse.CalcEdgesSmart(simplex.Facets, startingEdges.ToArray(), numEdges); } // Highlighted cells. H3.Cell[] cellsToHighlight = null; if (doCells) { H3.Cell startingCell = PolyhedronToHighlight(Geometry.Hyperbolic, polyMirrors, simplex, startingPoint); cellsToHighlight = Recurse.CalcCells(simplex.Facets, new H3.Cell[] { startingCell }); //cellsToHighlight = new H3.Cell[] { startingCell }; } // plugin Wendy's nonuniform calcs here... //Nonuniform.Wendy( simplex, edges ); // Trim out half the edges (the ones we won't see in our Pov-Ray view). /*Vector3D lookFrom = new Vector3D( 1, 1, 1 ) * 0.7; * Vector3D lookAt = new Vector3D(); // pov-ray lookat * double thresh = -.01; * if( doEdges ) * edges = edges.Where( e => e.Start.Dot( lookAt ) > thresh || e.End.Dot( lookAt ) > thresh ).ToArray(); * //if( doCells ) * // cellsToHighlight = cellsToHighlight.Where( c => c.Center.Dot( lookAt ) > thresh ).ToArray(); // I don't think this works right */ string fileName = baseName + suffix; if (File.Exists(fileName + ".pov")) { File.Delete(fileName + ".pov"); //Console.WriteLine( string.Format( "Skipping {0}", fileName ) ); //return; } SetupBaseHueGoursat(fileName, mirrorsString, baseHue); if (doEdges) { H3.SaveToFile(fileName, edges, finite: true, append: true); } if (doCells) { HashSet <H3.Cell.Edge> cellEdges = new HashSet <H3.Cell.Edge>(new H3.Cell.EdgeEqualityComparer()); foreach (H3.Cell cell in cellsToHighlight) { cell.AppendAllEdges(cellEdges); } edges = cellEdges.ToArray(); H3.SaveToFile(fileName, edges, finite: true, append: true); H3.AppendFacets(fileName, cellsToHighlight); } }
internal static bool CellOk(H3.Cell cell, Settings s) { if (s.G == Geometry.Spherical) { return(true); } double thresh = s.Threshold; if (!cell.HasVerts) { //return cell.Depths.Sum() <= 20; foreach (H3.Cell.Facet f in cell.Facets) { //bool ball = s.Ball; bool radiusCutoff = true; if (radiusCutoff) { if (f.Sphere.IsPlane) { continue; } //double closestToOrigin = f.Sphere.Center.Abs() - f.Sphere.Radius; //if( closestToOrigin > thresh ) // return false; if (f.Sphere.Radius < thresh) { return(false); } } else { double max = 20; if (f.Sphere.IsPlane) { if (f.Sphere.Offset.Abs() > max) { return(false); } } else { if (f.Sphere.Center.Abs() > max) { return(false); } } } } return(true); } // Any vertex < threshold makes us ok. foreach (Vector3D v in cell.Verts) { if (v.Abs() < thresh) { return(true); } } return(false); }
/// <summary> /// Used to generate a regular cell as a set of simplices and save to a Pov-ray file. /// This will work for non-finite cells. /// </summary> private static H3.Cell[] GenCell( Sphere[] simplex, Mesh mesh, Vector3D cen, bool ball, bool dual ) { // We don't want to include the first mirror (which reflects across cells). Sphere[] mirrors = simplex.Skip( 1 ).ToArray(); if( dual ) mirrors = new Sphere[] { simplex[0], simplex[1], simplex[2] }; Sphere[] allMirrors = simplex.ToArray(); mirrors = simplex.ToArray(); // Simplices will be the "cells" in Recurse.CalcCells. H3.Cell.Facet[] simplexFacets = simplex.Select( m => new H3.Cell.Facet( m ) ).ToArray(); H3.Cell startingCell = new H3.Cell( simplexFacets ); startingCell.Center = cen; startingCell.Mesh = mesh; //FCOrient( startingCell ); startingCell = startingCell.Clone(); // So our mirrors don't get munged after we reflect around later. H3.Cell[] simplices = Recurse.CalcCells( mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball } ); //H3.Cell[] simplices = new H3.Cell[] { startingCell }; // Layers. int layer = 0; return simplices.Where( s => s.Depths[0] <= layer /*&& s.Depths[0] == 3 && s.Depths[1] == 3*/ ).ToArray(); //return simplices.ToArray(); }
/// <summary> /// This is like the GenCell method, but super hacked up for the Catacombs image with Henry. /// </summary> internal static void GenCellCatacombs( Sphere[] simplex, bool ball ) { // We don't want to include the first mirror (which reflects across cells). Sphere[] mirrors = simplex.Skip( 1 ).ToArray(); Sphere[] allMirrors = simplex.ToArray(); // Simplices will be the "cells" in Recurse.CalcCells. H3.Cell.Facet[] simplexFacets = simplex.Select( m => new H3.Cell.Facet( m ) ).ToArray(); // Offset cell boundary ever so slightly, to avoid artifacts of adjacent cells. Sphere toReflectLater = simplexFacets[0].Sphere.Clone(); //simplexFacets[0].Sphere = CoxeterImages.GeodesicOffset( simplexFacets[0].Sphere, ball ? -1e-6 : 1e-7, ball ); H3.Cell startingCell = new H3.Cell( simplexFacets ); startingCell = startingCell.Clone(); // So our mirrors don't get munged after we reflect around later. Vector3D cen = new Vector3D( 0.05, 0.01, -0.05 ); // 373, 438 //Vector3D cen = new Vector3D( 0.05, 0.01, 100 ); // 637 //cen.RotateXY( Math.PI / 2 ); // only if we also rotate simplex mirrors. XXX - make a setting. startingCell.Center = cen; H3.Cell[] simplices = Recurse.CalcCells( mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball } ); List<H3.Cell> simplicesFinal = new List<H3.Cell>(); List<int[]> reflectionSets = new List<int[]>(); // 1 reflects in x-axis // 3, 1 rotates right // 1, 3 rotates left reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 1, 3 } ); reflectionSets.Add( new int[] { 0, 3, 1, 2, 3, 1, 0, 3, 1, 2, 0, 3 } ); // 2 reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2, 3, 1, 3, 2, 3, 1 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2, 3, 1, 3, 2, 3, 1 } ); // 3 //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 3, 1, 0, 3, 1, 2 } ); reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 0, 3, 1, 3, 1, 0, 2 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 2 } ); // 5 //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 1, 2, 3, 1 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 2, 3, 1 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2, 3, 1, 3, 1, 0, 1, 3 } ); // baby //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2 } ); // maybe //reflectionSets.Add( new int[] { 0, 3, 1, 2, 3, 1, 0, 2, 1, 3 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 2, 3, 1, 0, 3, 1, 2 } ); // not great orientation // reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 2 } ); // big bool ceiling = true; if( ceiling ) simplicesFinal = simplices.ToList(); else { foreach( int[] set in reflectionSets ) { List<H3.Cell> copy = simplices.Select( s => s.Clone() ).ToList(); foreach( int r in set ) { foreach( H3.Cell cell in copy ) cell.Reflect( allMirrors[r] ); } simplicesFinal.AddRange( copy ); } } /* // A second cell. //toReflectLater = simplices[45].Facets[0].Sphere.Clone(); //toReflectLater = simplices.First( s => s.Depth == 2 ).Facets[0].Sphere.Clone(); foreach( H3.Cell cell in simplices ) cell.Reflect( toReflectLater ); // A third cell. toReflectLater = simplices[40].Facets[0].Sphere.Clone(); //toReflectLater = simplices.First( s => s.Depth == 4 ).Facets[0].Sphere.Clone(); foreach( H3.Cell cell in simplices ) cell.Reflect( toReflectLater ); foreach( H3.Cell cell in simplices ) cell.Depths = new int[4]; List<H3.Cell> simplicesFinal = Recurse.CalcCells2( mirrors, simplices ).ToList(); simplicesFinal = simplicesFinal.Where( s => s.Depths[0] % 3 == 1 && s.Depths[1] % 2 == 0 && s.Depths[2] % 2 == 1 ).ToList(); */ /* List<H3.Cell> simplicesFinal = new List<H3.Cell>(); //for( int d = 0; d < 1; d+=2 ) int d = 0; { //Sphere toReflect = simplices.First( s => s.Depth == d ).Facets[0].Sphere.Clone(); //Sphere toReflect = simplices.Where( s => s.Depth == d ).Skip(1).Take(1).First().Facets[0].Sphere.Clone(); List<H3.Cell> reflectionCells = simplices.Where( s => s.Depths[1] == d && s.Depths[0] % 2 == 0 ).Skip(0).Take(1).ToList(); foreach( Sphere toReflect in reflectionCells.Select( c => c.Facets[0].Sphere.Clone() ) ) { List<H3.Cell> thisCell = new List<H3.Cell>(); foreach( H3.Cell cell in simplices ) { H3.Cell clone = cell.Clone(); clone.Reflect( toReflect ); thisCell.Add( clone ); } //Sphere toReflect2 = thisCell.First( s => s.Depth1 == d + 3 && s.Depth0 % 2 == 0 ).Facets[0].Sphere.Clone(); //List<H3.Cell> reflectionCellsTemp = simplices.Where( s => Math.Abs( s.Depths[1] - d ) == 2 && s.Depths[0] % 2 == 0 ).ToList(); List<H3.Cell> reflectionCellsTemp = simplices.Where( s => s.Depths[1] == 2 && s.Depths[1] == s.Depths[0] + s.Depths[2] ).ToList(); List<H3.Cell> reflectionCells2 = reflectionCellsTemp;//.Where( ( x, i ) => i % 3 == 0 ).ToList(); // .Skip( 5 ).Take( 5 ).ToList(); foreach( Sphere toReflect2 in reflectionCells2.Select( c => c.Facets[0].Sphere.Clone() ) ) //Sphere toReflect2 = toReflectLater; { foreach( H3.Cell cell in thisCell ) { H3.Cell clone = cell.Clone(); clone.Reflect( toReflect2 ); simplicesFinal.Add( clone ); } } } }*/ int count = 0; foreach( H3.Cell cell in simplicesFinal ) { count++; //if( count % 2 == 0 ) // continue; /*if( count < 1 ) continue; if( count > 30 ) return; */ //int[] include = new int[] { 0, 1, 2, 3 }; int[] include = new int[] { 0 }; PovRay.AppendSimplex( cell.Facets.Select( f => f.Sphere ).ToArray(), cell.Center, include, "cell.pov" ); } }
private static H3.Cell[] GenTruss( Sphere[] simplex, Mesh mesh, Vector3D cen, bool ball ) { // We don't want to include the first mirror (which reflects across cells). Sphere[] mirrors = simplex.Skip( 1 ).ToArray(); Sphere[] allMirrors = simplex.ToArray(); // Simplices will be the "cells" in Recurse.CalcCells. H3.Cell.Facet[] simplexFacets = simplex.Select( m => new H3.Cell.Facet( m ) ).ToArray(); H3.Cell startingCell = new H3.Cell( simplexFacets ); startingCell.Center = cen; //FCOrient( startingCell ); //return null; startingCell = startingCell.Clone(); // So our mirrors don't get munged after we reflect around later. H3.Cell[] simplices = Recurse.CalcCells( mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball } ); //H3.Cell[] simplices = new H3.Cell[] { startingCell }; // Subsets //return simplices.Where( s => s.Depths[0] == 1 ).ToArray(); //return simplices.ToArray(); List<H3.Cell> final = new List<H3.Cell>(); final.AddRange( simplices ); // Add in other truss cells. Recurse.Settings settings = new Recurse.Settings(); foreach( int[] reflections in TrussReflections() ) foreach( H3.Cell c in simplices ) { H3.Cell clone = c.Clone(); foreach( int r in reflections ) clone.Reflect( allMirrors[r] ); if( Recurse.CellOk( clone, settings ) ) final.Add( clone ); } return final.ToArray(); }
/// <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(); } } }
/// <summary> /// This generates a honeycomb by reflecting in 4 mirrors of the fundamental simplex. /// </summary> public static void OneHoneycombNew( HoneycombDef imageData ) { int p = imageData.P; int q = imageData.Q; int r = imageData.R; double thickness = 0.1; 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 = 5/*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 ) }; edges = Recurse.CalcEdges( simplex, startingEdges, new Recurse.Settings() { G = g, Threshold = threshold } ); //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 = 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 = 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(); } } // Write the file bool pov = false; 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(); } }
public static void Generate(EHoneycomb honeycomb, H3.Settings settings) { // XXX - Block the same as in H3. Share code better. H3.Cell template = null; { int p, q, r; Honeycomb.PQR(honeycomb, out p, out q, out r); // Get data we need to generate the honeycomb. Polytope.Projection projection = Polytope.Projection.FaceCentered; double phi, chi, psi; H3.HoneycombData(honeycomb, out phi, out chi, out psi); H3.SetupCentering(honeycomb, settings, phi, chi, psi, ref projection); Tiling tiling = new Tiling(); TilingConfig config = new TilingConfig(p, q); tiling.GenerateInternal(config, projection); H3.Cell first = new H3.Cell(p, H3.GenFacets(tiling)); first.ToSphere(); // Work in ball model. first.ScaleToCircumSphere(1.0); first.ApplyMobius(settings.Mobius); template = first; } // Center Vector3D center = template.Center; // Face H3.Cell.Facet facet = template.Facets[0]; Sphere s = H3Models.Ball.OrthogonalSphereInterior(facet.Verts[0], facet.Verts[1], facet.Verts[2]); Vector3D face = s.Center; face.Normalize(); face *= DistOriginToOrthogonalSphere(s.Radius); // Edge Circle3D c; H3Models.Ball.OrthogonalCircleInterior(facet.Verts[0], facet.Verts[1], out c); Vector3D edge = c.Center; edge.Normalize(); edge *= DistOriginToOrthogonalSphere(c.Radius); // Vertex Vector3D vertex = facet.Verts[0]; Tet fundamental = new Tet(center, face, edge, vertex); // Recurse. int level = 1; Dictionary <Tet, int> completedTets = new Dictionary <Tet, int>(new TetEqualityComparer()); completedTets.Add(fundamental, level); List <Tet> tets = new List <Tet>(); tets.Add(fundamental); ReflectRecursive(level, tets, completedTets, settings); Shapeways mesh = new Shapeways(); foreach (KeyValuePair <Tet, int> kvp in completedTets) { if (Utils.Odd(kvp.Value)) { continue; } Tet tet = kvp.Key; // XXX - really want sphere surfaces here. mesh.Mesh.Triangles.Add(new Mesh.Triangle(tet.Verts[0], tet.Verts[1], tet.Verts[2])); mesh.Mesh.Triangles.Add(new Mesh.Triangle(tet.Verts[0], tet.Verts[3], tet.Verts[1])); mesh.Mesh.Triangles.Add(new Mesh.Triangle(tet.Verts[0], tet.Verts[2], tet.Verts[3])); mesh.Mesh.Triangles.Add(new Mesh.Triangle(tet.Verts[1], tet.Verts[3], tet.Verts[2])); } mesh.Mesh.Scale(settings.Scale); STL.SaveMeshToSTL(mesh.Mesh, H3.m_baseDir + "fundamental" + ".stl"); }
private static H3.Cell PolyhedronToHighlight( Geometry g, int[] mirrors, Simplex simplex, Vector3D startingPoint ) { if( mirrors.Length != 3 ) throw new System.Exception( "We need exactly three mirrors to generate a polyhedron." ); // In the general case, we can have 3 types of polygons, each being generated by choosing 2 of the 3 mirrors. // When fewer polygon types exist, GenFacet will return null, so we need to check that. List<H3.Cell.Facet> polyFacets = new List<H3.Cell.Facet>(); polyFacets.Add( GenFacet( g, mirrors[0], mirrors[1], simplex, startingPoint ) ); polyFacets.Add( GenFacet( g, mirrors[1], mirrors[2], simplex, startingPoint ) ); polyFacets.Add( GenFacet( g, mirrors[0], mirrors[2], simplex, startingPoint ) ); polyFacets.RemoveAll( f => f == null ); HashSet<Vector3D> completedFacetIds = new HashSet<Vector3D>(); foreach( H3.Cell.Facet f in polyFacets ) completedFacetIds.Add( f.ID ); Recurse.GenPolyhedron( mirrors.Select( m => simplex.Facets[m] ).ToArray(), polyFacets.ToArray(), polyFacets, completedFacetIds ); H3.Cell cell = new H3.Cell( polyFacets.ToArray() ); // Calc a center. XXX - totally wrong. Vector3D center = new Vector3D(); foreach( Vector3D v in cell.Verts ) center += v; center /= cell.Verts.Count(); cell.Center = center; // Calc the spheres. foreach( H3.Cell.Facet f in cell.Facets ) f.CalcSphereFromVerts( g ); return cell; }
/// <summary> /// This is like the GenCell method, but super hacked up for the Catacombs image with Henry. /// </summary> internal static void GenCellCatacombs(Sphere[] simplex, bool ball) { // We don't want to include the first mirror (which reflects across cells). Sphere[] mirrors = simplex.Skip(1).ToArray(); Sphere[] allMirrors = simplex.ToArray(); // Simplices will be the "cells" in Recurse.CalcCells. H3.Cell.Facet[] simplexFacets = simplex.Select(m => new H3.Cell.Facet(m)).ToArray(); // Offset cell boundary ever so slightly, to avoid artifacts of adjacent cells. Sphere toReflectLater = simplexFacets[0].Sphere.Clone(); //simplexFacets[0].Sphere = CoxeterImages.GeodesicOffset( simplexFacets[0].Sphere, ball ? -1e-6 : 1e-7, ball ); H3.Cell startingCell = new H3.Cell(simplexFacets); startingCell = startingCell.Clone(); // So our mirrors don't get munged after we reflect around later. Vector3D cen = new Vector3D(0.05, 0.01, -0.05); // 373, 438 //Vector3D cen = new Vector3D( 0.05, 0.01, 100 ); // 637 //cen.RotateXY( Math.PI / 2 ); // only if we also rotate simplex mirrors. XXX - make a setting. startingCell.Center = cen; H3.Cell[] simplices = Recurse.CalcCells(mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball }); List <H3.Cell> simplicesFinal = new List <H3.Cell>(); List <int[]> reflectionSets = new List <int[]>(); // 1 reflects in x-axis // 3, 1 rotates right // 1, 3 rotates left reflectionSets.Add(new int[] { 0, 3, 1, 3, 1, 0, 1, 3 }); reflectionSets.Add(new int[] { 0, 3, 1, 2, 3, 1, 0, 3, 1, 2, 0, 3 }); // 2 reflectionSets.Add(new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2, 3, 1, 3, 2, 3, 1 }); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2, 3, 1, 3, 2, 3, 1 } ); // 3 //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 3, 1, 0, 3, 1, 2 } ); reflectionSets.Add(new int[] { 0, 3, 1, 3, 1, 3, 0, 3, 1, 3, 1, 0, 2 }); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 3, 1, 2 } ); // 5 //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 3, 1, 0, 1, 2, 3, 1 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 2, 3, 1 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2, 3, 1, 3, 1, 0, 1, 3 } ); // baby //reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 0, 3, 1, 3, 1, 3, 1, 2 } ); // maybe //reflectionSets.Add( new int[] { 0, 3, 1, 2, 3, 1, 0, 2, 1, 3 } ); //reflectionSets.Add( new int[] { 0, 3, 1, 2, 3, 1, 0, 3, 1, 2 } ); // not great orientation // reflectionSets.Add( new int[] { 0, 3, 1, 3, 1, 2 } ); // big bool ceiling = true; if (ceiling) { simplicesFinal = simplices.ToList(); } else { foreach (int[] set in reflectionSets) { List <H3.Cell> copy = simplices.Select(s => s.Clone()).ToList(); foreach (int r in set) { foreach (H3.Cell cell in copy) { cell.Reflect(allMirrors[r]); } } simplicesFinal.AddRange(copy); } } /* * // A second cell. * //toReflectLater = simplices[45].Facets[0].Sphere.Clone(); * //toReflectLater = simplices.First( s => s.Depth == 2 ).Facets[0].Sphere.Clone(); * foreach( H3.Cell cell in simplices ) * cell.Reflect( toReflectLater ); * * // A third cell. * toReflectLater = simplices[40].Facets[0].Sphere.Clone(); * //toReflectLater = simplices.First( s => s.Depth == 4 ).Facets[0].Sphere.Clone(); * foreach( H3.Cell cell in simplices ) * cell.Reflect( toReflectLater ); * * foreach( H3.Cell cell in simplices ) * cell.Depths = new int[4]; * List<H3.Cell> simplicesFinal = Recurse.CalcCells2( mirrors, simplices ).ToList(); * simplicesFinal = simplicesFinal.Where( s => s.Depths[0] % 3 == 1 && s.Depths[1] % 2 == 0 && s.Depths[2] % 2 == 1 ).ToList(); */ /* * List<H3.Cell> simplicesFinal = new List<H3.Cell>(); * //for( int d = 0; d < 1; d+=2 ) * int d = 0; * { * //Sphere toReflect = simplices.First( s => s.Depth == d ).Facets[0].Sphere.Clone(); * //Sphere toReflect = simplices.Where( s => s.Depth == d ).Skip(1).Take(1).First().Facets[0].Sphere.Clone(); * List<H3.Cell> reflectionCells = simplices.Where( s => s.Depths[1] == d && s.Depths[0] % 2 == 0 ).Skip(0).Take(1).ToList(); * foreach( Sphere toReflect in reflectionCells.Select( c => c.Facets[0].Sphere.Clone() ) ) * { * List<H3.Cell> thisCell = new List<H3.Cell>(); * foreach( H3.Cell cell in simplices ) * { * H3.Cell clone = cell.Clone(); * clone.Reflect( toReflect ); * thisCell.Add( clone ); * } * * //Sphere toReflect2 = thisCell.First( s => s.Depth1 == d + 3 && s.Depth0 % 2 == 0 ).Facets[0].Sphere.Clone(); * //List<H3.Cell> reflectionCellsTemp = simplices.Where( s => Math.Abs( s.Depths[1] - d ) == 2 && s.Depths[0] % 2 == 0 ).ToList(); * List<H3.Cell> reflectionCellsTemp = simplices.Where( s => s.Depths[1] == 2 && s.Depths[1] == s.Depths[0] + s.Depths[2] ).ToList(); * List<H3.Cell> reflectionCells2 = reflectionCellsTemp;//.Where( ( x, i ) => i % 3 == 0 ).ToList(); // .Skip( 5 ).Take( 5 ).ToList(); * foreach( Sphere toReflect2 in reflectionCells2.Select( c => c.Facets[0].Sphere.Clone() ) ) * //Sphere toReflect2 = toReflectLater; * { * foreach( H3.Cell cell in thisCell ) * { * H3.Cell clone = cell.Clone(); * clone.Reflect( toReflect2 ); * simplicesFinal.Add( clone ); * } * } * } * }*/ int count = 0; foreach (H3.Cell cell in simplicesFinal) { count++; //if( count % 2 == 0 ) // continue; /*if( count < 1 ) * continue; * if( count > 30 ) * return; */ //int[] include = new int[] { 0, 1, 2, 3 }; int[] include = new int[] { 0 }; PovRay.AppendSimplex(cell.Facets.Select(f => f.Sphere).ToArray(), cell.Center, include, "cell.pov"); } }