Exemplo n.º 1
0
        /// <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());
        }
Exemplo n.º 2
0
        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());
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 4
0
        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);
        }
Exemplo n.º 5
0
        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());
        }
Exemplo n.º 6
0
        /// <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);
        }
Exemplo n.º 7
0
 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());
 }
Exemplo n.º 8
0
        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);
        }
Exemplo n.º 9
0
        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);
        }
Exemplo n.º 10
0
        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());
        }
Exemplo n.º 11
0
        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);
        }
Exemplo n.º 12
0
        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);
        }
Exemplo n.º 13
0
        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);
            }
        }
Exemplo n.º 14
0
        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);
        }
Exemplo n.º 15
0
        /// <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();
        }
Exemplo n.º 16
0
        /// <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" );
            }
        }
Exemplo n.º 17
0
        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();
        }
Exemplo n.º 18
0
        /// <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;
                    }
                }
            }
        }
Exemplo n.º 19
0
        /// <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();
                }
            }
        }
Exemplo n.º 20
0
        /// <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();
            }
        }
Exemplo n.º 21
0
        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");
        }
Exemplo n.º 22
0
        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;
        }
Exemplo n.º 23
0
        /// <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");
            }
        }