Beispiel #1
0
 private static Vector3D Transform(Vector3D v)
 {
     //v *= 1.35;
     //v *= 2;
     v = H3Models.UHSToBall(v);
     return(v);
 }
Beispiel #2
0
        /// <summary>
        /// Calculates the point of our simplex that is at the middle of a face.
        /// </summary>
        private static Vector3D FaceCenterBall(int p, int q, int r)
        {
            Geometry cellGeometry = Geometry2D.GetGeometry(p, q);

            switch (cellGeometry)
            {
            case Geometry.Spherical:
            {
                Vector3D cellCenter = CellCenterBall(p, q, r);
                Sphere[] mirrors    = Mirrors(p, q, r, moveToBall: true);
                return(mirrors[0].ProjectToSurface(cellCenter));
            }

            case Geometry.Euclidean:
            {
                Sphere[] mirrors       = Mirrors(p, q, r, moveToBall: false);
                Vector3D faceCenterUHS = mirrors[0].Center;
                faceCenterUHS.Z += mirrors[0].Radius;
                return(H3Models.UHSToBall(faceCenterUHS));
            }

            case Geometry.Hyperbolic:
            {
                throw new System.NotImplementedException();
            }
            }

            throw new System.ArgumentException();
        }
Beispiel #3
0
        public static Vector3D[] VertsEuclidean()
        {
            int p = 4;
            int q = 3;

            //int r = 4;

            // Get a {q,p} tiling on the z=0 plane.
            Segment[] baseTileSegments = BaseTileSegments(q, p);

            // These will be unit length.
            Vector3D pFaceDirection    = H3Models.UHSToBall(baseTileSegments.First().P1);
            Vector3D pMidEdgeDirection = H3Models.UHSToBall(baseTileSegments.First().Midpoint);
            Vector3D pVertexDirection  = new Vector3D(0, 0, -1);

            // Order is same as facets (these are the points opposite facets).
            List <Vector3D> verts = new List <Vector3D>();

            verts.Add(new Vector3D());
            verts.Add(pFaceDirection * m_eScale);
            verts.Add(pMidEdgeDirection * Math.Sqrt(2) * m_eScale);
            verts.Add(pVertexDirection * Math.Sqrt(3) * m_eScale);

            // Apply rotations.
            double   rotation = Math.PI / 2;
            Vector3D zAxis    = new Vector3D(0, 0, 1);

            for (int i = 0; i < 4; i++)
            {
                verts[i].RotateAboutAxis(zAxis, rotation);
            }

            return(verts.ToArray());
        }
Beispiel #4
0
        /// <summary>
        /// Calculates the point of our simplex that is at a vertex.
        /// </summary>
        public static Vector3D VertexPointBall(int p, int q, int r)
        {
            Geometry vertexGeometry = Geometry2D.GetGeometry(q, r);

            if (vertexGeometry == Geometry.Hyperbolic)
            {
                // Outside the ball, and not in a good way.  Use the Klein version.
                //throw new System.NotImplementedException();
                return(new Vector3D(0, 0, -1));
            }

            // Get in UHS first.
            Sphere cellFacet = Mirrors(p, q, r, moveToBall: false).First();
            double rSquared  = Math.Pow(cellFacet.Radius, 2);
            double cSquared  = Math.Pow(cellFacet.Center.Abs(), 2);

            Vector3D uhs;

            if (Tolerance.Equal(rSquared, cSquared))                    // e.g. 363
            {
                uhs = new Vector3D();
            }
            else
            {
                double height = Math.Sqrt(rSquared - cSquared);
                uhs = new Vector3D(0, 0, height);
            }
            return(H3Models.UHSToBall(uhs));
        }
Beispiel #5
0
        private static H3.Cell.Edge[] ParameterizedFibers(Complex z)
        {
            List <H3.Cell.Edge> fibers = new List <H3.Cell.Edge>();

            double   scale = 0.1;
            Vector3D v1    = new Vector3D(0, -1);            // -i
            Vector3D v2    = Vector3D.FromComplex(z);

            int count = (int)Math.Round(Math.Sqrt(NumFibers), 0);

            for (int i = -count / 2; i < count / 2; i++)
            {
                for (int j = 1; j < count; j++)         // dilations should remain positive.
                {
                    double t1 = scale * i;
                    double t2 = scale * j;

                    // Apply the dilation first.
                    Vector3D _v1 = v1;
                    Vector3D _v2 = v2;
                    _v1   *= t2;
                    _v2   *= t2;
                    _v1.X += t1;
                    _v2.X += t1;

                    fibers.Add(new H3.Cell.Edge(
                                   H3Models.UHSToBall(_v1),
                                   H3Models.UHSToBall(_v2)));
                }
            }

            return(fibers.ToArray());
        }
Beispiel #6
0
        private Vector3D ApplyTransformationToSphere(Vector3D v, double t)
        {
            v = H3Models.BallToUHS(v);

            // 437 (hyperbolic)
            //v *= Math.Pow( 4.259171776329806, t*10-5 );

            // 36i (parabolic)
            //v += new Vector3D( Math.Cos( Math.PI / 6 ), Math.Sin( Math.PI / 6 ) ) * t;

            // iii (loxodromic)
            //Complex c = v.ToComplex();
            //double x = Math.Sqrt( 2 ) - 1;
            //Mobius m = new Mobius( new Complex( x, 0 ), Complex.One, new Complex( -x, 0 ) );

            // 12,12,12 loxodromic
            //m = new Mobius( new Complex( 0, 1 ), Complex.One, new Complex( 0, -1 ) );

            /*
             * c = m.Apply( c );
             * c *= Complex.Exp( new Complex( 2.5, 4 * Math.PI ) * t );
             * c = m.Inverse().Apply( c );
             * v = Vector3D.FromComplex( c );
             */

            // Center cell head in KolorEyes.
            Mobius m = new Mobius();

            m.UpperHalfPlane();
            v = m.Inverse().Apply(v);

            return(H3Models.UHSToBall(v));
        }
Beispiel #7
0
        /// <summary>
        /// Gets fibers for the only fibration with parallel (vs. ultraparallel) fibers.
        /// Returns result in the ball model.
        /// </summary>
        private static H3.Cell.Edge[] ParallelFibers()
        {
            List <H3.Cell.Edge> fibers = new List <H3.Cell.Edge>();

            double scale = 0.3;

            // Just a grid of vertical fibers.
            // We could do any kind of grid we want here really (square, hexagonal, random...)
            // Each would likely produce different results.
            // It'd be nice to figure out how to space out the results near the north pole.

            int count = (int)Math.Round(Math.Sqrt(NumFibers), 0);

            for (int i = -count / 2; i < count / 2; i++)
            {
                for (int j = -count / 2; j < count / 2; j++)
                {
                    //double off1 = Math.Pow( scale*i, 3 );
                    //double off2 = Math.Pow( scale*j, 3 );
                    double off1 = scale * i;
                    double off2 = scale * j;

                    Vector3D v1 = new Vector3D(off1, off2);
                    Vector3D v2 = new Vector3D(double.PositiveInfinity, 1);

                    // Don't use Infinity.InfinityVector, because we want to distiguish this point as being on the boundary.
                    fibers.Add(new H3.Cell.Edge(
                                   H3Models.UHSToBall(v1),
                                   H3Models.UHSToBall(v2)));
                }
            }

            return(fibers.ToArray());
        }
Beispiel #8
0
        private static List <H3.Cell.Edge> CopyAndProject(List <H3.Cell.Edge> regionEdges, Tiling tiling, double scale, Vector3D offset)
        {
            HashSet <H3.Cell.Edge> newEdges = new HashSet <H3.Cell.Edge>(new H3.Cell.EdgeEqualityComparer());
            //foreach( Tile tile in tiling.Tiles )	// Needed for doing full ball (rather than just half of it)
            Tile tile = tiling.Tiles.First();

            {
                foreach (H3.Cell.Edge edge in regionEdges)
                {
                    // Translation
                    // The isometry is necessary for the 363, but seems to mess up 636
                    Vector3D start = tile.Isometry.Apply(edge.Start) + offset;
                    Vector3D end   = tile.Isometry.Apply(edge.End) + offset;
                    //Vector3D start = edge.Start + tile.Center + offset;
                    //Vector3D end = edge.End + tile.Center + offset;

                    // Scaling
                    start *= scale;
                    end   *= scale;

                    // Projections
                    start = H3Models.UHSToBall(start);
                    end   = H3Models.UHSToBall(end);

                    H3.Cell.Edge transformed = new H3.Cell.Edge(start, end);
                    if (EdgeOkBall(transformed))
                    {
                        newEdges.Add(transformed);
                    }
                }
            }

            return(newEdges.ToList());
        }
Beispiel #9
0
        private static H3.Cell.Edge CalcFiber(Vector3D boundaryPointBall)
        {
            bool parallel = false;

            if (parallel)
            {
                Vector3D v2 = new Vector3D(0, 0, -1);                   // Really we can pick any boundary point.
                return(new H3.Cell.Edge(boundaryPointBall, v2));
            }
            else
            {
                // If the point is above the real line, it will have been connected to z.
                // If below the real line, it will have been connected to -i
                // If on the real line, it's degenerate.
                Vector3D pUHS = H3Models.BallToUHS(boundaryPointBall);
                if (Tolerance.Equal(pUHS.Y, 0))
                {
                    return(null);
                }

                Vector3D z      = Vector3D.FromComplex(ZParam);
                Vector3D minusi = new Vector3D(0, -1);

                double dilation    = double.NaN;
                double translation = double.NaN;
                if (pUHS.Y > 0)
                {
                    dilation    = pUHS.Y / z.Y;
                    z          *= dilation;
                    translation = pUHS.X - z.X;
                    z.X        += translation;
                    if (H3Models.UHSToBall(z) != boundaryPointBall)
                    {
                        throw new System.Exception();
                    }

                    minusi   *= dilation;
                    minusi.X += translation;
                    return(new H3.Cell.Edge(H3Models.UHSToBall(minusi), boundaryPointBall));
                    //return null;
                }
                else
                {
                    dilation    = pUHS.Y / -1;
                    minusi     *= dilation;
                    translation = pUHS.X - minusi.X;
                    minusi.X   += translation;
                    if (H3Models.UHSToBall(minusi) != boundaryPointBall)
                    {
                        throw new System.Exception();
                    }

                    z   *= dilation;
                    z.X += translation;
                    return(new H3.Cell.Edge(boundaryPointBall, H3Models.UHSToBall(z)));
                    //return null;
                }
            }
        }
Beispiel #10
0
        public static void Cell633()
        {
            TilingConfig config = new TilingConfig(6, 3, maxTiles: 20000);
            Tiling       tiling = new Tiling();

            tiling.GenerateInternal(config, Polytope.Projection.VertexCentered);

            double edgeLength = Honeycomb.EdgeLength(6, 3, 3);

            double z      = 0.25;
            double offset = H3Models.UHS.ToEHorizontal(edgeLength, z);
            double scale  = offset / tiling.Tiles.First().Boundary.Segments.First().Length;

            foreach (Tile tile in tiling.Tiles)
            {
                tile.Transform(Mobius.Scale(scale));
            }

            Vector3D dummy;
            double   radius;

            H3Models.UHS.Geodesic(new Vector3D(0, 0, z), new Vector3D(scale, 0, z), out dummy, out radius);
            Vector3D midradius = H3Models.UHSToBall(new Vector3D(0, 0, radius));
            double   temp      = midradius.Z;
            double   temp2     = (1 - temp) / 2;
            double   temp3     = temp + temp2;
            double   temp4     = temp3;

            Vector3D circumradius = H3Models.UHSToBall(new Vector3D(0, 0, z));

            temp  = circumradius.Z;
            temp2 = (1 - temp) / 2;
            temp3 = temp + temp2;
            temp4 = temp3;

            // Checking

            /*
             * Vector3D test = new Vector3D( offset, 0, z );
             * test = H3Models.UHSToBall( test );
             * double edgeLength2 = DonHatch.e2hNorm( test.Abs() );
             * edgeLength2 += 0;
             */

            HashSet <H3.Cell.Edge> edges = new HashSet <H3.Cell.Edge>();

            foreach (Tile tile in tiling.Tiles)
            {
                foreach (Segment seg in tile.Boundary.Segments)
                {
                    H3.Cell.Edge edge = new H3.Cell.Edge(
                        H3Models.UHSToBall(seg.P1 + new Vector3D(0, 0, z)),
                        H3Models.UHSToBall(seg.P2 + new Vector3D(0, 0, z)));
                    edges.Add(edge);
                }
            }

            PovRay.WriteH3Edges(new PovRay.Parameters(), edges.ToArray(), "edges.pov");
        }
Beispiel #11
0
 /// <summary>
 /// Returns the 6 simplex edges in the Ball model.
 /// </summary>
 public static H3.Cell.Edge[] SimplexEdgesBall(int p, int q, int r)
 {
     H3.Cell.Edge[] edges = SimplexEdgesUHS(p, q, r);
     foreach (H3.Cell.Edge e in edges)
     {
         e.Start = H3Models.UHSToBall(e.Start);
         e.End   = H3Models.UHSToBall(e.End);
     }
     return(edges);
 }
Beispiel #12
0
 void CalcFibers(Vector3D[] basePoints, List <H3.Cell.Edge> fibers, double t)
 {
     foreach (Vector3D v in basePoints)
     {
         H3.Cell.Edge e = CalcFiberFromBase(v);
         if (e != null)
         {
             e.Color = Color(Transform(H3Models.UHSToBall(v), t));
         }
         fibers.Add(Transform(e, t));
     }
 }
Beispiel #13
0
        public static Vector3D EdgeMidpointSpherical(int p, int q, int r)
        {
            // Get a {q,p} tiling on the z=0 plane.
            Segment[] baseTileSegments = BaseTileSegments(q, p);

            Vector3D direction = H3Models.UHSToBall(baseTileSegments.First().Midpoint);

            direction.Normalize();
            double midRadius = Spherical2D.s2eNorm(Honeycomb.MidRadius(p, q, r));

            return(direction * midRadius);
        }
Beispiel #14
0
        public static void Create(HoneycombDef def, string filename)
        {
            int p = def.P;
            int q = def.Q;
            int r = def.R;

            double   scale = 5.0;
            Vector3D cen   = HoneycombPaper.InteriorPointBall;

            Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: false);

            // Apply transformations.
            simplex = simplex.Select(s =>
            {
                Sphere.ScaleSphere(s, scale);
                return(H3Models.UHSToBall(s));
            }).ToArray();

            for (int i = 0; i < 4; i++)
            {
                if (simplex[i].IsPointInside(cen))
                {
                    simplex[i].Invert = true;
                }
            }

            Sphere[] simplexForColorScale = SimplexCalcs.Mirrors(p, q, r, moveToBall: true);
            CoxeterImages.Settings temp   = HoneycombPaper.AutoCalcScale(def, simplexForColorScale);
            int maxDepth = (int)temp.ColorScaling;

            bool ball = true;
            bool dual = false;

            H3.Cell[] simplicesFinal = HoneycombPaper.GenCell(simplex, null, cen, ball, dual);

            simplicesFinal = simplicesFinal.Where(s => s.Depths[0] < 1).ToArray();
            //simplicesFinal = simplicesFinal.Where( s => s.)

            // Output the facets.
            using (StreamWriter sw = File.CreateText(filename))                 // We need to reuse this StreamWriter (vs. calling AppendSimplex) for performance.
            {
                sw.WriteLine("#include \"hyper_ball.pov\"");
                int[] include = new int[] { 0 };
                foreach (H3.Cell cell in simplicesFinal)
                {
                    Sphere[] facets = cell.Facets.Select(f => f.Sphere).ToArray();
                    int      depth  = cell.Depths[0] + 1;
                    Color    c      = Coloring.ColorAlongHexagon(maxDepth, depth);
                    PovRay.AddSimplex(sw, facets, cell.Center, include, filename, Coloring.ToVec(c));
                }
            }
        }
Beispiel #15
0
        public static Vector3D FaceCenterSpherical(int p, int q, int r)
        {
            // Get a {q,p} tiling on the z=0 plane.
            Segment[] baseTileSegments = BaseTileSegments(q, p);

            // This will be unit length.
            Vector3D pFaceDirection = H3Models.UHSToBall(baseTileSegments.First().P1);

            // In-radius is in conformal model
            double inRadius = Spherical2D.s2eNorm(Honeycomb.InRadius(p, q, r));

            return(pFaceDirection * inRadius);
        }
Beispiel #16
0
        /// <summary>
        /// XXX - Need to make this a function of clock, so it probably needs to not be static.
        /// </summary>
        /// <param name="basePointUHS"></param>
        /// <returns>A base point in the disk, possibly transformed.</returns>
        Vector3D Transform(Vector3D basePointUHS, double t)
        {
            if (!Ball)
            {
                return(basePointUHS);
            }

            Vector3D basePointDisk = H3Models.UHSToBall(basePointUHS);

            // Apply transformations.
            // XXX - make this a mobius we pass in, so we can edit it on the outside.
            //basePointDisk.RotateAboutAxis( new Vector3D( 0, 1, 0 ), 2 * Math.PI * t );

            return(basePointDisk);
        }
Beispiel #17
0
        /// <summary>
        /// Get a distribution of points on a sphere.
        /// The points are the vertices of a geodesic dome.
        /// </summary>
        private static Vector3D[] SpherePoints()
        {
            List <Vector3D> spherePoints = new List <Vector3D>();
            TilingConfig    config       = new TilingConfig(3, 5);
            Tiling          tiling       = new Tiling();

            tiling.GenerateInternal(config);

            Tile baseTile = tiling.Tiles.First();

            Vector3D[] templateTextureCoords = TextureHelper.TextureCoords(baseTile.Boundary, Geometry.Spherical, doGeodesicDome: true);
            foreach (Tile tile in tiling.Tiles)
            {
                Isometry isom = new Isometry();
                isom.CalculateFromTwoPolygons(baseTile, tile, Geometry.Spherical);
                Vector3D[] textureCoords = Isometry.TransformVertices(templateTextureCoords, isom.Inverse());
                spherePoints.AddRange(textureCoords);
            }

            return(spherePoints.Select(p => H3Models.UHSToBall(p)).Distinct().ToArray());
        }
Beispiel #18
0
        public static Sphere[] MirrorsEuclidean()
        {
            int p = 4;
            int q = 3;

            //int r = 4;

            // Get a {q,p} tiling on the z=0 plane.
            Segment[] baseTileSegments = BaseTileSegments(q, p);

            // This will be unit length.
            Vector3D pFaceDirection = H3Models.UHSToBall(baseTileSegments.First().P1);

            // NOTES:
            //	Center is the plane normal.
            //	Cell face is only one with an offset
            //  This is constructed already in the ball.
            Sphere cellBoundary = new Sphere()
            {
                Center = -pFaceDirection, Offset = pFaceDirection * m_eScale, Radius = double.PositiveInfinity
            };

            Sphere[] interior = InteriorMirrors(p, q);
            interior = interior.Select(s => H3Models.UHSToBall(s)).ToArray();
            Sphere[] surfaces = new Sphere[] { cellBoundary, interior[0], interior[1], interior[2] };

            // Apply rotations.
            bool applyRotations = false;

            if (applyRotations)
            {
                double rotation = Math.PI / 2;
                foreach (Sphere s in surfaces)
                {
                    RotateSphere(s, rotation);
                }
            }

            return(surfaces);
        }
Beispiel #19
0
        /// <summary>
        /// Calculates the point of our simplex that is at the middle of an edge.
        /// </summary>
        private static Vector3D MidEdgePointBall(int p, int q, int r)
        {
            // We need the mid-radius, but we have to do the calculation
            // with our Euclidean simplex mirrors (to avoid infinities that happen in the formulas).
            Circle3D edge = HoneycombEdgeUHS(p, q, r);

            if (edge.Radius == 0)
            {
                return(edge.Center);
            }

            Geometry cellGeometry = Geometry2D.GetGeometry(p, q);

            switch (cellGeometry)
            {
            case Geometry.Spherical:
            {
                Sphere sphereInBall = H3Models.UHSToBall(new Sphere()
                    {
                        Center = edge.Center, Radius = edge.Radius
                    });
                Vector3D mid = sphereInBall.ProjectToSurface(new Vector3D());                           // Project origin to sphere.
                return(mid);
            }

            case Geometry.Euclidean:
            {
                Vector3D mid = H3Models.UHSToBall(edge.Center + new Vector3D(0, 0, edge.Radius));
                return(mid);
            }

            case Geometry.Hyperbolic:
            {
                throw new System.NotImplementedException();
            }
            }

            throw new System.ArgumentException();
        }
Beispiel #20
0
        /// <summary>
        /// Mirrors for Spherical geometry, in the ball model.
        /// </summary>
        public static Sphere[] MirrorsSpherical(int p, int q, int r)
        {
            // Get a {q,p} tiling on the z=0 plane.
            Segment[] baseTileSegments = BaseTileSegments(q, p);

            // This will be unit length.
            Vector3D pFaceDirection = H3Models.UHSToBall(baseTileSegments.First().P1);

            // In-radius is in conformal model
            double   inRadius         = Spherical2D.s2eNorm(Honeycomb.InRadius(p, q, r));
            double   centerOfSphereNE = (1 - inRadius) / (1 + inRadius);
            Vector3D center;
            double   radius;

            H3Models.Ball.DupinCyclideSphere(-pFaceDirection * centerOfSphereNE, 1.0 /*geodesic circle*/, Geometry.Spherical, out center, out radius);
            Sphere cellBoundary = new Sphere()
            {
                Center = center, Radius = radius, Invert = true
            };

            Sphere[] interior = InteriorMirrors(p, q);
            interior = interior.Select(s => H3Models.UHSToBall(s)).ToArray();
            Sphere[] surfaces = new Sphere[] { cellBoundary, interior[0], interior[1], interior[2] };

            // Apply rotations.
            bool applyRotations = false;

            if (applyRotations)
            {
                double rotation = Math.PI / 2;
                foreach (Sphere s in surfaces)
                {
                    RotateSphere(s, rotation);
                }
            }

            return(surfaces);
        }
Beispiel #21
0
        /// <summary>
        /// This allows us to change the model we have on the plane.
        /// We usually want UHS, but for Pov-Ray mapping these images to a sphere, we need to have it be an equirectangular projection
        /// NOTE: The bounds should be set to 1.0 for this to work! v.X and v.Y must be in-between -1 and 1. (also, don't rotate simplex mirrors, for POV-Ray anyway)
        /// </summary>
        private Vector3D PlaneModelToBall(Vector3D v, double t = 0.0)
        {
            bool equirectangular = false;

            if (!equirectangular)
            {
                // Normal UHS (sterographic projection).
                return(H3Models.UHSToBall(v));
            }
            else
            {
                // If you want output to have twice the width.
                double xScale = 2;
                v.X /= xScale;

                // http://mathworld.wolfram.com/EquirectangularProjection.html
                // y is the latitude
                // x is the longitude
                // Assume inputs go from -1 to 1.
                Vector3D spherical = new Vector3D(1, Math.PI / 2 * (1 - v.Y), v.X * Math.PI);
                Vector3D onBall    = SphericalCoords.SphericalToCartesian(spherical);
                return(ApplyTransformationToSphere(onBall, t));
            }
        }
Beispiel #22
0
        private static void HoneycombFiniteVertexFig(HoneycombDef def, int lod, Dictionary <Vector3D, H3.Cell> complete)
        {
            int p = def.P;
            int q = def.Q;
            int r = def.R;

            double   scale = 1.0;
            Vector3D vUHS  = H3Models.BallToUHS(SimplexCalcs.VertexPointBall(p, q, r));

            if (Geometry2D.GetGeometry(q, r) != Geometry.Hyperbolic)                // Vertex-centered if possible
            {
                scale = 1.0 / vUHS.Z;
            }
            System.Func <Vector3D, Vector3D> trans = v =>
            {
                v  = H3Models.BallToUHS(v);
                v *= scale;
                v  = H3Models.UHSToBall(v);
                return(v);
            };

            bool ball = true;

            Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: ball);
            simplex = simplex.Select(s =>
            {
                s = H3Models.BallToUHS(s);
                Sphere.ScaleSphere(s, scale);
                s = H3Models.UHSToBall(s);
                return(s);
            }).ToArray();
            H3.Cell.Edge[] edges = SimplexCalcs.SimplexEdgesBall(p, q, r);

            // Two edges of the simplex facet.
            // NOTE: This contruction only works for material triangles, and matches the construction in the TextureHelper.
            m_div = TextureHelper.SetLevels(lod);
            int[]           elementIndices = TextureHelper.TextureElements(1, lod);
            List <Vector3D> points         = new List <Vector3D>();

            H3.Cell.Edge e1 = edges[2];
            H3.Cell.Edge e2 = edges[3];
            Vector3D     p1 = trans(e1.Start), p2 = trans(e1.End), p3 = trans(e2.End);

            Vector3D[] points1 = H3Models.Ball.GeodesicPoints(p2, p1, m_div);
            Vector3D[] points2 = H3Models.Ball.GeodesicPoints(p3, p1, m_div);
            for (int i = 0; i < m_div; i++)
            {
                points.AddRange(H3Models.Ball.GeodesicPoints(points1[i], points2[i], m_div - i));
            }
            points.Add(p1);

            Mesh mesh = new Mesh();

            for (int i = 0; i < elementIndices.Length / 3; i++)
            {
                int      idx1 = i * 3;
                int      idx2 = i * 3 + 1;
                int      idx3 = i * 3 + 2;
                Vector3D v1   = points[elementIndices[idx1]];
                Vector3D v2   = points[elementIndices[idx2]];
                Vector3D v3   = points[elementIndices[idx3]];
                mesh.Triangles.Add(new Mesh.Triangle(v1, v2, v3));
            }

            // AuxPoints will be used for multiple things.
            // - The first is a definition point for a face, so we can check for duplicates.
            // - We'll also store the points for the 3 edges of our fundamental triangle.
            List <Vector3D> auxPoints = new List <Vector3D>();
            {
                auxPoints.Add((p1 + p2 + p3) / 3);
                auxPoints.AddRange(points1);
                auxPoints.AddRange(points2.Reverse());
                auxPoints.AddRange(H3Models.Ball.GeodesicPoints(points2[0], points1[0], m_div));
            }

            Vector3D cen = HoneycombPaper.InteriorPointBall;

            H3.Cell[] simplices = GenCell(simplex, mesh, cen, auxPoints.ToArray(), ball);

            // Existing cells take precedence.
            foreach (H3.Cell c in simplices)
            {
                Vector3D t = c.AuxPoints[0];
                H3.Cell  dummy;
                if (!complete.TryGetValue(t, out dummy))
                {
                    complete[t] = c;
                }
            }
        }
Beispiel #23
0
 internal static Sphere SphereFuncUHS(Vector3D v)
 {
     return(H3Models.BallToUHS(SphereFuncBall(Geometry.Hyperbolic, H3Models.UHSToBall(v))));
 }
Beispiel #24
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();
                }
            }
        }
Beispiel #25
0
        private static void CreateCellPovRay(HoneycombDef def, string filename, double t = 0)
        {
            int p = def.P;
            int q = def.Q;
            int r = def.R;

            //Vector3D trans = new Vector3D( 1.0/3, 0 ) * (2 + 2 * Math.Sin( Math.PI / 6 )) * t;
            //double scale = 1.8;
            Vector3D trans = new Vector3D();
            double   scale = 1.0;

            Vector3D[] sVerts = null;               // SimplexCalcs.VertsBall( p, q, r );

            Vector3D vUHS = H3Models.BallToUHS(SimplexCalcs.VertexPointBall(p, q, r));

            // Just did this for everything.  Non-general position working better and will make all heads consistent.
            scale = 2.0;

            if (Geometry2D.GetGeometry(q, r) != Geometry.Hyperbolic)                // Vertex-centered if possible
            {
                scale = 1.0 / vUHS.Z;
            }
            //else if( Geometry2D.GetGeometry( p, q ) == Geometry.Hyperbolic ) // Make the biggest head somewhat smaller.
            //	scale = 2.0;

            Vector3D cen = InteriorPointBall;

            /*var kleinVerts = sVerts.Select( v => HyperbolicModels.PoincareToKlein( v ) );
             * Vector3D avg = new Vector3D();
             * foreach( Vector3D v in kleinVerts )
             *      avg += v;
             * avg /= kleinVerts.Count();
             * Vector3D cen = HyperbolicModels.KleinToPoincare( avg );*/
            cen  = H3Models.BallToUHS(cen);
            cen += trans;
            //cen *= scale;
            cen = H3Models.UHSToBall(cen);

            Sphere[] simplex = SimplexCalcs.Mirrors(p, q, r, moveToBall: false);

            // Apply transformations.
            simplex = simplex.Select(s =>
            {
                Sphere.TranslateSphere(s, trans);
                Sphere.ScaleSphere(s, scale);
                return(H3Models.UHSToBall(s));
            }).ToArray();

            for (int i = 0; i < 4; i++)
            {
                if (simplex[i].IsPointInside(cen))
                {
                    simplex[i].Invert = true;
                }
            }

            Sphere[] simplexForColorScale = SimplexCalcs.Mirrors(p, q, r, moveToBall: true);
            CoxeterImages.Settings temp   = AutoCalcScale(def, simplexForColorScale);
            int maxDepth = (int)temp.ColorScaling;
            //Random rand = new Random( p+q+r );
            //int randOffset = rand.Next( maxDepth );

            bool ball = true;
            bool dual = false;

            H3.Cell[] simplicesFinal = GenCell(simplex, null, cen, ball, dual);

            using (StreamWriter sw = File.CreateText(filename))                 // We need to reuse this StreamWriter (vs. calling AppendSimplex) for performance.
            {
                sw.WriteLine("#include \"hyper_ball.pov\"");

                //int[] include = new int[] { 0, 1, 2, 3 };
                int[] include = new int[] { 0 };
                if (dual)
                {
                    include = new int[] { 3 }
                }
                ;

                // Output the facets.
                foreach (H3.Cell cell in simplicesFinal)
                {
                    Sphere[] facets = cell.Facets.Select(f => f.Sphere).ToArray();
                    if (m_toKlein)
                    {
                        facets = facets.Select(s => H3Models.BallToKlein(s)).ToArray();
                    }

                    int   depth = cell.Depths[0] + 1;
                    Color c     = Coloring.ColorAlongHexagon(maxDepth, depth);
                    if (cell.Depths.Sum() % 2 == 0)
                    {
                        c = Coloring.Inverse(c);
                    }
                    PovRay.AddSimplex(sw, facets, cell.Center, include, filename, Coloring.ToVec(c));
                }

                /*include = new int[] { 1, 2, 3 };
                 * foreach( H3.Cell cell in simplicesFinal )
                 * {
                 *      Sphere[] facets = cell.Facets.Select( f => f.Sphere ).ToArray();
                 *      Color c = Color.Red;
                 *      Vector3D cv = Coloring.ToVec( c );
                 *      cv.W = 0.9;
                 *      PovRay.AddSimplex( sw, facets, cell.Center, include, filename, cv );
                 * }*/
            }

            // Output the edges/verts.
            bool includeEdges = false;

            if (includeEdges)
            {
                sVerts = sVerts.Select(v =>
                {
                    v  = H3Models.BallToUHS(v);
                    v += trans;
                    v *= scale;
                    return(H3Models.UHSToBall(v));
                }).ToArray();

                H3.Cell.Edge[] edges = Recurse.CalcEdges(simplex.Skip(1).ToArray(),
                                                         new H3.Cell.Edge[] { new H3.Cell.Edge(sVerts[2], sVerts[3], order: false) },
                                                         new Recurse.Settings()
                {
                    Threshold = 0.01
                });
                PovRay.WriteH3Edges(new PovRay.Parameters {
                    AngularThickness = 0.01
                }, edges, filename, append: true);

                HashSet <Vector3D> verts = new HashSet <Vector3D>();
                foreach (H3.Cell.Edge e in edges)
                {
                    verts.Add(e.End);
                }
                PovRay.WriteVerts(new PovRay.Parameters {
                    AngularThickness = 0.02
                }, Geometry.Hyperbolic, verts.ToArray(), filename, append: true);
            }
        }
Beispiel #26
0
        /// <summary>
        /// This will return an altered facet to create true apparent 2D tilings (proper bananas) on the boundary.
        /// Notes:
        ///		The input simplex must be in the ball model.
        ///		The first mirror of the simplex (the one that mirrors across cells) is the one we end up altering.
        /// </summary>
        public static Sphere AlteredFacetForTrueApparent2DTilings(Sphere[] simplex)
        {
            //Sphere m = H3Models.BallToUHS( simplex[0] );
            //Sphere t = new Sphere() { Center = m.Center, Radius = m.Radius*100 };
            //return H3Models.UHSToBall( t );

            // We first need to find the size of the apparent 2D disk surrounding the leg.
            // This is also the size of the apparent cell head disk of the dual.
            // So we want to get the midsphere (insphere would also work) of the dual cell with that head,
            // then calculate the intersection of that with the boundary.
            Sphere cellMirror = simplex[0];

            if (cellMirror.IsPlane)
            {
                throw new System.NotImplementedException();
            }

            // The point centered on a face is the closest point of the cell mirror to the origin.
            // This will be the point centered on an edge on the dual cell.
            Vector3D facePoint = cellMirror.ProjectToSurface(new Vector3D());

            // Reflect it to get 3 more points on our midsphere.
            Vector3D reflected1 = simplex[1].ReflectPoint(facePoint);
            Vector3D reflected2 = simplex[2].ReflectPoint(reflected1);
            Vector3D reflected3 = simplex[0].ReflectPoint(reflected2);
            Sphere   midSphere  = Sphere.From4Points(facePoint, reflected1, reflected2, reflected3);

            // Get the ideal circles of the cell mirror and midsphere.
            // Note: The midsphere is not geodesic, so we can't calculate it the same.
            Sphere cellMirrorUHS   = H3Models.BallToUHS(cellMirror);
            Circle cellMirrorIdeal = H3Models.UHS.IdealCircle(cellMirrorUHS);

            Sphere   ball = new Sphere();
            Circle3D midSphereIdealBall = ball.Intersection(midSphere);               // This should exist because we've filtered for honeycombs with hyperideal verts.
            Circle3D midSphereIdealUHS  = H3Models.BallToUHS(midSphereIdealBall);
            Circle   midSphereIdeal     = new Circle {
                Center = midSphereIdealUHS.Center, Radius = midSphereIdealUHS.Radius
            };

            // The intersection point of our cell mirror and the disk of the apparent 2D tiling
            // gives us "ideal" points on the apparent 2D boundary. These points will be on the new cell mirror.
            Vector3D i1, i2;

            if (2 != Euclidean2D.IntersectionCircleCircle(cellMirrorIdeal, midSphereIdeal, out i1, out i2))
            {
                //throw new System.ArgumentException( "Since we have hyperideal vertices, we should have an intersection with 2 points." );

                // Somehow works in the euclidean case.
                // XXX - Make this better.
                return(H3Models.UHSToBall(new Sphere()
                {
                    Center = Vector3D.DneVector(), Radius = double.NaN
                }));
            }

            double bananaThickness = 0.025;

            //bananaThickness = 0.15;
            bananaThickness = 0.05;

            // Transform the intersection points to a standard Poincare disk.
            // The midsphere radius is the scale of the apparent 2D tilings.
            double   scale  = midSphereIdeal.Radius;
            Vector3D offset = midSphereIdeal.Center;

            i1 -= offset;
            i2 -= offset;
            i1 /= scale;
            i2 /= scale;
            Circle3D banana = H3Models.Ball.OrthogonalCircle(i1, i2);
            Vector3D i3     = H3Models.Ball.ClosestToOrigin(banana);

            i3 = Hyperbolic2D.Offset(i3, -bananaThickness);

            // Transform back.
            i1 *= scale; i2 *= scale; i3 *= scale;
            i1 += offset; i2 += offset; i3 += offset;

            // Construct our new simplex mirror with these 3 points.
            Circle3D c = new Circle3D(i1, i2, i3);

            Sphere result = new Sphere()
            {
                Center = c.Center, Radius = c.Radius
            };

            return(H3Models.UHSToBall(result));
        }
Beispiel #27
0
 private static Sphere[] MoveToBall(Sphere[] surfaces, ref Vector3D cellCenter)
 {
     Sphere[] result = surfaces.Select(s => H3Models.UHSToBall(s)).ToArray();
     cellCenter = H3Models.UHSToBall(cellCenter);
     return(result);
 }