示例#1
0
        public static void OneImage( HoneycombDef imageData, double t = 0.0 )
        {
            //string filename = "batch/" + imageData.FormatFilename();
            string filename = imageData.FormatFilename();
            //if( File.Exists( filename ) )
            //	return;

            int p = imageData.P, q = imageData.Q, r = imageData.R;
            Geometry gCell = Geometry2D.GetGeometry( p, q );
            Geometry gVertex = Geometry2D.GetGeometry( q, r );
            //if( !( gCell == Geometry.Hyperbolic || gVertex == Geometry.Hyperbolic ) )
            //if( !( gVertex == Geometry.Hyperbolic ) )
            //	return;

            Sphere[] mirrors = SimplexCalcs.Mirrors( p, q, r );

            //double bounds = gCell == Geometry.Spherical ? 9 : 1.1;
            double bounds =  1.1;
            bounds = 1;
            //bounds = 5;
            //bounds = 7;
            //bounds = 4.4;
            //bounds = 10;

            CoxeterImages imageCalculator = new CoxeterImages();

            int size = 200;
            CoxeterImages.Settings settings = new CoxeterImages.Settings()
            {
                Honeycomb = imageData,
                Width = size,
                Height = size,
                Bounds = bounds,
                Mirrors = mirrors,
                FileName = imageData.FormatFilename(),
            };

            imageCalculator.AutoCalcScale( settings );
            //settings.ColorScaling = 45.1;	// 437
            //settings.ColorScaling = 60; // 35.58;	// 438, 637 cathedral
            //settings.ColorScaling = 20;	// 373
            //settings.ColorScaling = 15; //464
            if( settings.ColorScaling < 1 )
                settings.ColorScaling = 15;

            settings.ColorScaling = 39;
            //size = 4320;
            size = 2500;
            //settings.Width = size * 4 / 3;
            settings.Width = size * 2;
            settings.Width = size;
            settings.Height = size;
            //settings.FileName = imageData.FormatFilename( "jpg" );
            settings.FileName = filename;

            imageCalculator.GenImage( settings, t );
        }
示例#2
0
        public static void DoStuff( string[] args )
        {
            int p, q, r;
            if( args.Length == 3 )
            {
                p = ReadArg( args[0] );
                q = ReadArg( args[1] );
                r = ReadArg( args[2] );
            }
            else
            {
                p = 3;
                q = 3;
                r = 7;
            }

            HoneycombDef imageData = new HoneycombDef( p, q, r );

            ////////////////////////////////////////////////////////////// Various things we've run over time.
            //Sandbox.CalcSelfSimilarityScale();
            //Sandbox.Check_pq_Distances();
            //HyperidealSquares();
            //S3.Hypercube();
            //R3.Geometry.Euclidean.GenEuclidean();
            //HoneycombGen.OneHoneycombOldCode();
            //CreateCellPovRay( imageData );
            //CreateCellSTL( imageData );
            //CreateSimplex( imageData );
            //HoneycombGen.OneHoneycombNew( new HoneycombDef() { P = imageData.P, Q = imageData.Q, R = imageData.R } );
            //SphericalAnimate( imageData );
            Program.OneImage( imageData );

            HoneycombDef[] scaleLarger = GetImageSet().Where( h =>
                Geometry2D.GetGeometry( h.P, h.Q ) == Geometry.Euclidean ||
                Geometry2D.GetGeometry( h.P, h.Q ) == Geometry.Spherical ).ToArray();
            int count = scaleLarger.Length;
            //foreach( HoneycombAndView h in scaleLarger )
            //	Trace.WriteLine( h.FormatFilename() );

            BatchRun();
        }
示例#3
0
        private static Sphere[] SphericalCellFacetMirrors( HoneycombDef imageData )
        {
            int p = imageData.P;
            int q = imageData.Q;
            int r = imageData.R;

            double inRadius = Honeycomb.InRadius( p, q, r );
            //inRadius *= 1.4;	// Experimenting with {3,3,u}

            Tiling tiling = new Tiling();
            TilingConfig config = new TilingConfig( p, q );
            tiling.GenerateInternal( config, imageData.Projection );

            Sphere[] mirrors = H3.GenFacetSpheres( tiling, inRadius )
                .Select( f => f.Sphere ).ToArray();

            return mirrors;
        }
示例#4
0
 private static string BaseName( HoneycombDef def )
 {
     return string.Format( "{0}{1}{2}", def.P, def.Q, def.R );
 }
示例#5
0
        public static void ParacompactSet()
        {
            List<int[]> toRun = new List<int[]>();
            toRun.Add( new int[] { 0, 1 } );
            toRun.Add( new int[] { 0, 2 } );
            toRun.Add( new int[] { 0, 3 } );
            toRun.Add( new int[] { 1, 2 } );
            toRun.Add( new int[] { 1, 3 } );
            toRun.Add( new int[] { 2, 3 } );
            toRun.Add( new int[] { 0, 1, 2 } );
            toRun.Add( new int[] { 0, 1, 3 } );
            toRun.Add( new int[] { 0, 2, 3 } );
            toRun.Add( new int[] { 1, 2, 3 } );
            toRun.Add( new int[] { 0, 1, 2, 3 } );

            //toRun.Clear();
            //toRun.Add( new int[] { 0, 1, 3 } );

            int baseHue = 0;
            HoneycombDef def;

            baseHue = 135;
            def = new HoneycombDef( 6, 3, 3 );
            foreach( int[] active in toRun )
                Paracompact( def, active, baseHue );

            baseHue = 220;
            def = new HoneycombDef( 6, 3, 4 );
            foreach( int[] active in toRun )
                Paracompact( def, active, baseHue );

            baseHue = 180;
            def = new HoneycombDef( 6, 3, 5 );
            foreach( int[] active in toRun )
                Paracompact( def, active, baseHue );

            baseHue = 255;
            def = new HoneycombDef( 6, 3, 6 );
            foreach( int[] active in toRun )
                Paracompact( def, active, baseHue );

            baseHue = 105;
            def = new HoneycombDef( 3, 6, 3 );
            foreach( int[] active in toRun )
                Paracompact( def, active, baseHue );

            baseHue = 300;
            def = new HoneycombDef( 4, 4, 3 );
            foreach( int[] active in toRun )
                Paracompact( def, active, baseHue );

            baseHue = 0;
            def = new HoneycombDef( 4, 4, 4 );
            foreach( int[] active in toRun )
                Paracompact( def, active, baseHue );
        }
示例#6
0
        public static void Paracompact( HoneycombDef def, int[] active, int baseHue )
        {
            string baseName = BaseName( def );
            string mirrorsString = ActiveMirrorsString( active );
            string suffix = "-" + mirrorsString;
            string fileName = baseName + suffix;

            if( File.Exists( fileName + ".pov" ) )
            {
                Console.WriteLine( string.Format( "Skipping {0}", fileName ) );
                return;
            }

            Console.WriteLine( string.Format( "Building {0}", fileName ) );
            CalcThickness( active );

            // 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( active, simplex );
            if( startingPoint.DNE )
                return;
            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 ) );
            }

            SetupBaseHue( fileName, mirrorsString, baseHue );
            Recurse.m_background = new Vector3D( baseHue, 1, .1 );

            H3.Cell.Edge[] edges = Recurse.CalcEdgesSmart2( simplex.Facets, startingEdges.ToArray() );
            H3.SaveToFile( fileName, edges, finite: true, append: true );
        }
示例#7
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();
            }
        }
示例#8
0
        private static double AnimColorScaling( HoneycombDef imageData )
        {
            return 10;

            int p = imageData.P, q = imageData.Q, r = imageData.R;
            Sphere[] mirrors = SimplexCalcs.Mirrors( p, q, r );

            int size = 200;
            CoxeterImages.Settings settings = new CoxeterImages.Settings()
            {
                Honeycomb = imageData,
                Width = size*2,
                Height = size,
                Bounds = 1.0,
                Mirrors = mirrors,
                FileName = string.Empty,
            };

            CoxeterImages imageCalculator = new CoxeterImages();
            imageCalculator.AutoCalcScale( settings );
            return settings.ColorScaling;
        }
示例#9
0
        private static void SphericalAnimate( HoneycombDef imageData )
        {
            double colorScaling = AnimColorScaling( imageData );

            int fps = 30;
            //int frames = 60 * fps;
            int frames = 5;
            for( int i = 0; i < frames; i++ )
            {
                string num = i.ToString();
                num = num.PadLeft( 3, '0' );

                double t = (double)i/frames;
                string filename = "batch/" + imageData.FormatFilename( string.Empty ) + "_" + num + ".png";
                OneAnimationFrame( imageData, filename, colorScaling, t );
            }
        }
示例#10
0
        private static void OneAnimationFrame( HoneycombDef imageData, string filename, double colorScaling, double t = 0.0 )
        {
            int p = imageData.P, q = imageData.Q, r = imageData.R;
            Sphere[] mirrors = SimplexCalcs.Mirrors( p, q, r );

            int size = 750;
            size = 1024;
            CoxeterImages.Settings settings = new CoxeterImages.Settings()
            {
                Honeycomb = imageData,
                Width = size*2,
                Height = size,
                Bounds = 1.0,
                Mirrors = mirrors,
                FileName = filename,
            };

            CoxeterImages imageCalculator = new CoxeterImages();
            settings.ColorScaling = colorScaling;
            imageCalculator.GenImage( settings, t );
        }
示例#11
0
        private static double GetScalingOld( HoneycombDef imageData )
        {
            // pqi, pir (3qr, p3r, pq3)
            // Q = 3 = 50, Q = 7 = 130
            double scaling = 50 + (imageData.Q - 3) * 20;
            if( /*imageData.P == -1 ||*/ imageData.Q == -1 )
                scaling = 130;

            // iqr
            //scaling = 100; (blue)
            // scaling = 50; (when purple, did constant 50)

            // Reverse: What did I use this for?
            /*scaling = 130 - ( imageData.Q - 3 ) * 20;
            if( imageData.Q == -1 )
                scaling = 50;*/

            // Euclidean cells/vertex figures.
            scaling = 75;

            // Gray scale
            //scaling = 35;

            return scaling;
        }
示例#12
0
        private static void CreateSimplex( HoneycombDef imageData )
        {
            int p = imageData.P;
            int q = imageData.Q;
            int r = imageData.R;

            Vector3D cen = CellCenBall;
            bool ball = true;
            Sphere[] simplex = SimplexCalcs.Mirrors( p, q, r, ref cen, moveToBall: ball );

            // Offset as we do for the boundary images.
            //Sphere s = H3Models.UHSToBall( simplex[0] );
            //s = CoxeterImages.GeodesicOffset( s, 0.02, ball: true );

            if( m_toKlein )
                simplex = simplex.Select( s => H3Models.BallToKlein( s ) ).ToArray();

            int[] include = new int[] { 0, 1, 2, 3 };	// All facets
            //int[] include = new int[] { 1 };
            File.Delete( "simplex.pov" );
            PovRay.AppendSimplex( simplex, cen, include, "simplex.pov" );

            if( false )
            {
                H3.Cell.Edge[] edges = SimplexCalcs.SimplexEdgesUHS( p, q, r );
                PovRay.WriteEdges( new PovRay.Parameters { Halfspace = true, AngularThickness = 0.03 },
                    Geometry.Hyperbolic, edges, "simplex.pov", append: true );
            }
        }
示例#13
0
        /// <summary>
        /// Create an STL file for a cell.
        /// This will be a 2D surface of triangles, which will need to be thickened using an external program.
        /// Currently only works for cells with both hyperideal vertices and cells.
        /// </summary>
        private static void CreateCellSTL( HoneycombDef imageData )
        {
            int p = imageData.P;
            int q = imageData.Q;
            int r = imageData.R;

            bool ball = false;
            Sphere[] simplex = SimplexCalcs.Mirrors( p, q, r, moveToBall: ball );
            H3.Cell.Edge[] edges;
            if( ball )
                edges = SimplexCalcs.SimplexEdgesBall( p, q, r );
            else
                edges = SimplexCalcs.SimplexEdgesUHS( p, q, r );

            // Two edges of one simplex facet.
            int div = 5;
            H3.Cell.Edge e1 = edges[2];
            H3.Cell.Edge e2 = edges[3];
            Vector3D[] points1, points2;
            if( ball )
            {
                points1 = H3Models.Ball.GeodesicPoints( e1.Start, e1.End, 2 * div );
                points2 = H3Models.Ball.GeodesicPoints( e2.Start, e2.End, 2 * div );
            }
            else
            {
                points1 = H3Models.UHS.GeodesicPoints( e1.Start, e1.End, 2 * div );
                points2 = H3Models.UHS.GeodesicPoints( e2.Start, e2.End, 2 * div );
            }

            Sphere cellSphere = simplex[0];

            // Because one vertex the facet triangle is hyperideal, it will actually look like a square.
            List<Vector3D[]> allPoints = new List<Vector3D[]>();
            for( int i = 0; i < points1.Length; i++ )
            {
                Vector3D p1 = points1[i];
                Vector3D p2 = points2[i];

                // NOTE: This arc is not generally geodesic!
                Vector3D[] arcPoints;
                if( i == points1.Length - 1 )
                {
                    arcPoints = ball ?
                        H3Models.Ball.GeodesicPoints( p1, p2, div ) :
                        H3Models.UHS.GeodesicPoints( p1, p2, div );
                }
                else
                {
                    Circle3D c = Circle3D.FromCenterAnd2Points( cellSphere.Center, p1, p2 );
                    double angleTot = (p1 - c.Center).AngleTo( p2 - c.Center );
                    arcPoints = Shapeways.CalcArcPoints( cellSphere.Center, cellSphere.Radius, p1, c.Normal, -angleTot, div );
                }
                //Vector3D[] arcPoints = new Vector3D[] { p1, p2 };
                allPoints.Add( arcPoints );
            }

            // Create the triangles for the patch.
            Mesh mesh = new Mesh();
            for( int i = 0; i < allPoints.Count - 1; i++ )
            {
                Vector3D[] arc1 = allPoints[i];
                Vector3D[] arc2 = allPoints[i + 1];

                for( int j = 0; j < arc1.Length - 1; j++ )
                {
                    // Points of (i,j) box;
                    Vector3D p1 = arc1[j];
                    Vector3D p2 = arc2[j];
                    Vector3D p3 = arc1[j + 1];
                    Vector3D p4 = arc2[j + 1];

                    mesh.Triangles.Add( new Mesh.Triangle( p1, p2, p3 ) );
                    mesh.Triangles.Add( new Mesh.Triangle( p2, p4, p3 ) );
                }
            }

            // Face centered orientation.
            // XXX - We need to do this prior to mesh generation, so the mesh isn't stretched out by these transformations.
            bool faceCentered = true;

            Vector3D cen = CellCenBall;
            if( faceCentered )
                SimplexCalcs.PrepForFacetCentering( p, q, simplex, ref cen );

            Mobius mUHS = SimplexCalcs.FCOrientMobius( p, q );
            Mobius mBall = FCOrientMobius( H3Models.UHSToBall( cellSphere ) );

            simplex = simplex.Select( s =>
            {
                s = H3Models.UHSToBall( s );
                H3Models.TransformInBall2( s, mBall );
                return s;
            } ).ToArray();

            {
                for( int i = 0; i < mesh.Triangles.Count; i++ )
                {
                    Mesh.Triangle tri = mesh.Triangles[i];

                    if( faceCentered )
                    {
                        tri.a = mUHS.ApplyToQuaternion( tri.a );
                        tri.b = mUHS.ApplyToQuaternion( tri.b );
                        tri.c = mUHS.ApplyToQuaternion( tri.c );
                    }

                    tri.a = H3Models.UHSToBall( tri.a );
                    tri.b = H3Models.UHSToBall( tri.b );
                    tri.c = H3Models.UHSToBall( tri.c );

                    if( faceCentered )
                    {
                        tri.a = H3Models.TransformHelper( tri.a, mBall );
                        tri.b = H3Models.TransformHelper( tri.b, mBall );
                        tri.c = H3Models.TransformHelper( tri.c, mBall );
                    }
                    mesh.Triangles[i] = tri;
                }

                if( faceCentered )
                    cen = H3Models.TransformHelper( cen, mBall );
            }

            // Now we need to reflect around this fundamental patch.
            bool dual = false;
            H3.Cell[] simplicesFinal = GenCell( simplex, mesh, cen, ball, dual );

            System.IO.File.Delete( "cell.stl" );
            foreach( H3.Cell cell in simplicesFinal )
                STL.AppendMeshToSTL( cell.Mesh, "cell.stl" );
            //STL.AppendMeshToSTL( simplicesFinal[0].Mesh, "cell.stl" );
        }
示例#14
0
        private static void CreateCellPovRay( HoneycombDef imageData )
        {
            int p = imageData.P;
            int q = imageData.Q;
            int r = imageData.R;

            // Calculate scale to make vertex centered.
            //Vector3D v = SimplexCalcs.VertexPointBall( p, q, r );
            //v = H3Models.BallToUHS( v );

            /*double t = Math.Sqrt( 1 - Math.Pow( v.Abs(), 2 ) );
            v = new Vector3D( t, 0, v.Z );
            v = H3Models.BallToUHS( v );
            Vector3D v2 = H3Models.BallToUHS( new Vector3D( 1, 0, 0 ) );
            t = v.Abs() / v2.Abs();
            v = H3Models.UHSToBall( new Vector3D( t, 0, 0 ) );*/

            double scale = Geometry2D.GetNormalizedCircumRadius( p, q );

            Vector3D cen = CellCenBall;
            cen = H3Models.BallToUHS( cen );

            bool ball = true;
            bool dual = false;
            Sphere[] simplex = SimplexCalcs.Mirrors( p, q, r, ref cen, moveToBall: ball/*, scaling: 1.0/v.Abs()*/ );
            //Sphere[] simplex = SimplexCalcs.Mirrors( p, q, r, moveToBall: ball/*, scaling: 1.0/v.Abs()*/ );
            //Sphere[] simplex = SimplexCalcs.Mirrors( p, q, r, moveToBall: ball, scaling: 1.0 / scale );
            H3.Cell[] simplicesFinal = GenCell( simplex, null, cen, ball, dual );

            System.IO.File.Delete( "cell.pov" );
            foreach( H3.Cell cell in simplicesFinal )
            {
                //int[] include = new int[] { 0, 1, 2, 3 };
                int[] include = new int[] { 0 };
                if( dual )
                    include = new int[] { 3 };

                Sphere[] facets = cell.Facets.Select( f => f.Sphere ).ToArray();
                if( m_toKlein )
                    facets = facets.Select( s => H3Models.BallToKlein( s ) ).ToArray();

                PovRay.AppendSimplex( facets, cell.Center, include, "cell.pov" );
            }
        }