示例#1
0
        /// <summary>
        /// A correct implementation of shrink tile.
        /// hmmmm, is "scaling" even well defined in non-E geometries? Am I really looking for an equidistant curve?
        /// Sadly, even if I figure out what is best, I fear changing out usage of the incorrect one below in MagicTile,
        /// because of the possibility of breaking existing puzzles.
        /// </summary>
        internal static void ShrinkTileCorrect(ref Tile tile, double shrinkFactor)
        {
            System.Func <Vector3D, double, Vector3D> scaleFunc = null;
            switch (tile.Geometry)
            {
            case Geometry.Euclidean:
            {
                scaleFunc = (v, s) => v * s;
                break;
            }

            case Geometry.Spherical:
            {
                scaleFunc = (v, s) =>
                {
                    // Move to spherical norm, scale, then move back to euclidean.
                    double scale = Spherical2D.s2eNorm((Spherical2D.e2sNorm(v.Abs()) * s));
                    v.Normalize();
                    return(v * scale);
                };
                break;
            }

            case Geometry.Hyperbolic:
            {
                throw new System.NotImplementedException();
            }
            }
        }
示例#2
0
        private static void HopfFibration(Tiling tiling)
        {
            int       segDivisions = 10;
            Shapeways mesh         = new Shapeways();

            HashSet <Vector3D> done = new HashSet <Vector3D>();

            foreach (Tile tile in tiling.Tiles)
            {
                foreach (Segment seg in tile.Boundary.Segments)
                {
                    if (done.Contains(seg.Midpoint))
                    {
                        continue;
                    }

                    // Subdivide the segment, and project points to S2.
                    Vector3D[] points = seg.Subdivide(segDivisions).Select(v => Spherical2D.PlaneToSphere(v)).ToArray();
                    foreach (Vector3D point in points)
                    {
                        Vector3D[] circlePoints = OneHopfCircle(point);
                        ProjectAndAddS3Points(mesh, circlePoints, shrink: false);
                    }

                    done.Add(seg.Midpoint);
                }
            }

            STL.SaveMeshToSTL(mesh.Mesh, @"D:\p4\R3\sample\out1.stl");
        }
示例#3
0
        public static double GetNormalizedCircumRadius(int p, double q)
        {
            double hypot = GetTriangleHypotenuse(p, q);

            switch (Geometry2D.GetGeometry(p, q))
            {
            case Geometry.Spherical:
                return(Spherical2D.s2eNorm(hypot) * DiskRadius);

            case Geometry.Euclidean:
                return(EuclideanHypotenuse);

            case Geometry.Hyperbolic:
            {
                if (Infinity.IsInfinite(hypot))
                {
                    return(DiskRadius);
                }

                return(DonHatch.h2eNorm(hypot) * DiskRadius);
            }
            }

            Debug.Assert(false);
            return(1);
        }
示例#4
0
        // Gets the distance between two points.
        private double Dist(Vector3D p1, Vector3D p2)
        {
            switch (this.Metric)
            {
            case Metric.Spherical:
            {
                // ZZZ - Is it too expensive to build up a mobius every time?
                //		 I wonder if there is a better way.
                Mobius m = new Mobius();
                m.Isometry(Geometry.Spherical, 0, -p1);
                Vector3D temp = m.Apply(p2);
                return(Spherical2D.e2sNorm(temp.Abs()));
            }

            case Metric.Euclidean:
            {
                return((p2 - p1).Abs());
            }

            case Metric.Hyperbolic:
            {
                // ZZZ - Is it too expensive to build up a mobius every time?
                //		 I wonder if there is a better way.
                Mobius m = new Mobius();
                m.Isometry(Geometry.Hyperbolic, 0, -p1);
                Vector3D temp = m.Apply(p2);
                return(DonHatch.e2hNorm(temp.Abs()));
            }
            }

            throw new System.NotImplementedException();
        }
示例#5
0
        public static void CalcEScale()
        {
            // Euclidean scale is arbitrary, but put it in the middle of the projections of 433 and 435.
            double r3 = Spherical2D.s2eNorm(Honeycomb.CircumRadius(4, 3, 3));
            double r5 = DonHatch.h2eNorm(Honeycomb.CircumRadius(4, 3, 5));

            m_eScale = (r3 + r5) / (2 * Math.Sqrt(3));
        }
示例#6
0
        private static void HopfFibration(Tiling tiling)
        {
            int       segDivisions    = 10;
            int       circleDivisions = 125;
            Shapeways mesh            = new Shapeways();

            HashSet <Vector3D> done = new HashSet <Vector3D>();

            foreach (Tile tile in tiling.Tiles)
            {
                foreach (Segment seg in tile.Boundary.Segments)
                {
                    if (done.Contains(seg.Midpoint))
                    {
                        continue;
                    }

                    // Subdivide the segment, and project points to S2.
                    Vector3D[] points = seg.Subdivide(segDivisions).Select(v => Spherical2D.PlaneToSphere(v)).ToArray();
                    foreach (Vector3D point in points)
                    {
                        // Get the hopf circle and add to mesh.
                        // http://en.wikipedia.org/wiki/Hopf_fibration#Explicit_formulae
                        double a      = point.X;
                        double b      = point.Y;
                        double c      = point.Z;
                        double factor = 1 / (Math.Sqrt(1 + c));
                        if (Tolerance.Equal(c, -1))
                        {
                            continue;
                        }

                        List <Vector3D> circlePoints = new List <Vector3D>();
                        double          angleInc     = 2 * Math.PI / circleDivisions;
                        double          angle        = 0;
                        for (int i = 0; i <= circleDivisions; i++)
                        {
                            double sinTheta = Math.Sin(angle);
                            double cosTheta = Math.Cos(angle);
                            circlePoints.Add(new Vector3D(
                                                 (1 + c) * cosTheta,
                                                 a * sinTheta - b * cosTheta,
                                                 a * cosTheta + b * sinTheta,
                                                 (1 + c) * sinTheta));

                            angle += angleInc;
                        }

                        bool shrink = false;
                        ProjectAndAddS3Points(mesh, circlePoints.ToArray(), shrink);
                    }

                    done.Add(seg.Midpoint);
                }
            }

            STL.SaveMeshToSTL(mesh.Mesh, @"D:\p4\R3\sample\out1.stl");
        }
示例#7
0
        /// <summary>
        /// Outputs edges to an stl file.
        /// </summary>
        public void Output()
        {
            System.Func <Vector3D, Vector3D> p2s       = v => Spherical2D.PlaneToSphere(v);
            System.Func <Vector3D, Vector3D> transform = v => H3Models.Ball.ApplyMobius(Mobius.Scale(3), v);

            double min  = double.MaxValue;
            Cell   cell = m_cells.First();

            foreach (Vector3D v1 in cell.Tiles[0].Boundary.Vertices)
            {
                foreach (Vector3D v2 in cell.Tiles[1].Boundary.Vertices)
                {
                    min = Math.Min(min, p2s(v1).Dist(p2s(v2)));
                }
            }

            // XXX - code below so ugly to read!

            Dictionary <TileVertex, TileVertex> vMap = new Dictionary <TileVertex, TileVertex>();

            for (int tile_i = 0; tile_i < cell.Tiles.Length; tile_i++)
            {
                for (int tile_j = tile_i + 1; tile_j < cell.Tiles.Length; tile_j++)
                {
                    for (int vertex_i = 0; vertex_i < cell.Tiles[tile_i].Boundary.Vertices.Length; vertex_i++)
                    {
                        for (int vertex_j = 0; vertex_j < cell.Tiles[tile_j].Boundary.Vertices.Length; vertex_j++)
                        {
                            Vector3D v1 = cell.Tiles[tile_i].Boundary.Vertices[vertex_i];
                            Vector3D v2 = cell.Tiles[tile_j].Boundary.Vertices[vertex_j];

                            if (Tolerance.Equal(p2s(v1).Dist(p2s(v2)), min))
                            {
                                vMap[new TileVertex(tile_i, vertex_i)] = new TileVertex(tile_j, vertex_j);
                            }
                        }
                    }
                }
            }

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

            foreach (Cell c in m_cells)
            {
                foreach (KeyValuePair <TileVertex, TileVertex> kvp in vMap)
                {
                    Vector3D v1 = transform(p2s(c.Tiles[kvp.Key.Item1].Boundary.Vertices[kvp.Key.Item2]));
                    Vector3D v2 = transform(p2s(c.Tiles[kvp.Value.Item1].Boundary.Vertices[kvp.Value.Item2]));
                    edges.Add(new H3.Cell.Edge(v1, v2));
                }
            }

            //H3.m_settings.ThinEdges = true;
            H3.SaveToFile("ultrainf", edges.ToArray(), finite: false);
        }
示例#8
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);
        }
示例#9
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);
        }
示例#10
0
        /// <summary>
        /// Helper to project points from S3 -> S2, then add an associated curve.
        /// </summary>
        private static void ProjectAndAddS3Points(Shapeways mesh, Vector3D[] pointsS3, bool shrink)
        {
            // Project to S3, then to R3.
            List <Vector3D> projected = new List <Vector3D>();

            foreach (Vector3D v in pointsS3)
            {
                v.Normalize();
                Vector3D c = v.ProjectTo3DSafe(1.0);

                // Pull R3 into a smaller open disk.
                if (shrink)
                {
                    double mag = Math.Atan(c.Abs());
                    c.Normalize();
                    c *= mag;
                }

                projected.Add(c);
            }

            System.Func <Vector3D, double> sizeFunc = v =>
            {
                // Constant thickness.
                // return 0.08;

                double sphericalThickness = 0.002;

                double abs = v.Abs();
                if (shrink)
                {
                    abs = Math.Tan(abs);                        // The unshrunk abs.
                }
                // The thickness at this vector location.
                double result = Spherical2D.s2eNorm(Spherical2D.e2sNorm(abs) + sphericalThickness) - abs;

                if (shrink)
                {
                    result *= Math.Atan(abs) / abs;                             // shrink it back down.
                }
                return(result);
            };

            mesh.AddCurve(projected.ToArray(), sizeFunc);
        }
示例#11
0
        public static double GetNormalizedCircumRadius(int p, int q)
        {
            Geometry g = Geometry2D.GetGeometry(p, q);

            double hypot = GetTriangleHypotenuse(p, q);

            switch (g)
            {
            case Geometry.Spherical:
                return(Spherical2D.s2eNorm(hypot) * DiskRadius);

            case Geometry.Euclidean:
                return(EuclideanHypotenuse);

            case Geometry.Hyperbolic:
                return(DonHatch.h2eNorm(hypot) * DiskRadius);
            }

            Debug.Assert(false);
            return(1);
        }
示例#12
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);
        }
示例#13
0
        public static Sphere[] Mirrors(int p, int q, int r, ref Vector3D cellCenter, bool moveToBall = true, double scaling = -1)
        {
            Geometry g = Util.GetGeometry(p, q, r);

            if (g == Geometry.Spherical)
            {
                // These are in the ball model.
                Sphere[] result = SimplexCalcs.MirrorsSpherical(p, q, r);
                return(result);
            }
            else if (g == Geometry.Euclidean)
            {
                return(SimplexCalcs.MirrorsEuclidean());
            }

            // This is a rotation we'll apply to the mirrors at the end.
            // This is to try to make our image outputs have vertical bi-lateral symmetry and the most consistent in all cases.
            // NOTE: + is CW, not CCW. (Because the way I did things, our images have been reflected vertically, and I'm too lazy to go change this.)
            double rotation = Math.PI / 2;

            // Some construction points we need.
            Vector3D p1, p2, p3;
            Segment  seg = null;

            TilePoints(p, q, out p1, out p2, out p3, out seg);

            //
            // Construct in UHS
            //

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

            Vector3D center = new Vector3D();
            double   radius = 0;

            if (cellGeometry == Geometry.Spherical)
            {
                // Finite or Infinite r

                // Spherical trig
                double halfSide = Geometry2D.GetTrianglePSide(q, p);
                double mag      = Math.Sin(halfSide) / Math.Cos(Util.PiOverNSafe(r));
                mag = Math.Asin(mag);

                // e.g. 43j
                //mag *= 0.95;

                // Move mag to p1.
                mag = Spherical2D.s2eNorm(mag);
                H3Models.Ball.DupinCyclideSphere(p1, mag, Geometry.Spherical, out center, out radius);
            }
            else if (cellGeometry == Geometry.Euclidean)
            {
                center = p1;
                radius = p1.Dist(p2) / Math.Cos(Util.PiOverNSafe(r));
            }
            else if (cellGeometry == Geometry.Hyperbolic)
            {
                if (Infinite(p) && Infinite(q) && FiniteOrInfinite(r))
                {
                    //double iiiCellRadius = 2 - Math.Sqrt( 2 );
                    //Circle3D iiiCircle = new Circle3D() { Center = new Vector3D( 1 - iiiCellRadius, 0, 0 ), Radius = iiiCellRadius };
                    //radius = iiiCellRadius;	// infinite r
                    //center = new Vector3D( 1 - radius, 0, 0 );

                    // For finite r, it was easier to calculate cell facet in a more symmetric position,
                    // then move into position with the other mirrors via a Mobius transformation.
                    double rTemp = 1 / (Math.Cos(Util.PiOverNSafe(r)) + 1);
                    Mobius m     = new Mobius();
                    m.Isometry(Geometry.Hyperbolic, -Math.PI / 4, new Vector3D(0, Math.Sqrt(2) - 1));
                    Vector3D c1 = m.Apply(new Vector3D(1 - 2 * rTemp, 0, 0));
                    Vector3D c2 = c1;
                    c2.Y *= -1;
                    Vector3D c3 = new Vector3D(1, 0);
                    Circle3D c  = new Circle3D(c1, c2, c3);

                    radius = c.Radius;
                    center = c.Center;
                }
                else if (Infinite(p) && Finite(q) && FiniteOrInfinite(r))
                {
                    // http://www.wolframalpha.com/input/?i=r%2Bx+%3D+1%2C+sin%28pi%2Fp%29+%3D+r%2Fx%2C+solve+for+r
                    // radius = 2 * Math.Sqrt( 3 ) - 3;	// Appolonian gasket wiki page
                    //radius = Math.Sin( Math.PI / q ) / ( Math.Sin( Math.PI / q ) + 1 );
                    //center = new Vector3D( 1 - radius, 0, 0 );

                    // For finite r, it was easier to calculate cell facet in a more symmetric position,
                    // then move into position with the other mirrors via a Mobius transformation.
                    double rTemp = 1 / (Math.Cos(Util.PiOverNSafe(r)) + 1);
                    Mobius m     = new Mobius();
                    m.Isometry(Geometry.Hyperbolic, 0, p2);
                    Vector3D findingAngle = m.Inverse().Apply(new Vector3D(1, 0));
                    double   angle        = Math.Atan2(findingAngle.Y, findingAngle.X);

                    m.Isometry(Geometry.Hyperbolic, angle, p2);
                    Vector3D c1 = m.Apply(new Vector3D(1 - 2 * rTemp, 0, 0));
                    Vector3D c2 = c1;
                    c2.Y *= -1;
                    Vector3D c3 = new Vector3D(1, 0);
                    Circle3D c  = new Circle3D(c1, c2, c3);

                    radius = c.Radius;
                    center = c.Center;
                }
                else if (Finite(p) && Infinite(q) && FiniteOrInfinite(r))
                {
                    radius = p2.Abs();                                                                              // infinite r
                    radius = DonHatch.asinh(Math.Sinh(DonHatch.e2hNorm(p2.Abs())) / Math.Cos(Util.PiOverNSafe(r))); // hyperbolic trig

                    // 4j3
                    //m_jOffset = radius * 0.02;
                    //radius += m_jOffset ;

                    radius    = DonHatch.h2eNorm(radius);
                    center    = new Vector3D();
                    rotation *= -1;
                }
                else if (/*Finite( p ) &&*/ Finite(q))
                {
                    // Infinite r
                    //double mag = Geometry2D.GetTrianglePSide( q, p );

                    // Finite or Infinite r
                    double halfSide = Geometry2D.GetTrianglePSide(q, p);
                    double mag      = DonHatch.asinh(Math.Sinh(halfSide) / Math.Cos(Util.PiOverNSafe(r)));                              // hyperbolic trig
                    H3Models.Ball.DupinCyclideSphere(p1, DonHatch.h2eNorm(mag), out center, out radius);
                }
                else
                {
                    throw new System.NotImplementedException();
                }
            }
            Sphere cellBoundary = new Sphere()
            {
                Center = center,
                Radius = radius
            };

            Sphere[] interior = InteriorMirrors(p, q);
            Sphere[] surfaces = new Sphere[] { cellBoundary, interior[0], interior[1], interior[2] };

            // Apply rotations.
            bool applyRotations = true;

            if (applyRotations)
            {
                foreach (Sphere s in surfaces)
                {
                    RotateSphere(s, rotation);
                }
                p1.RotateXY(rotation);
            }

            // Apply scaling
            bool applyScaling = scaling != -1;

            if (applyScaling)
            {
                //double scale = 1.0/0.34390660467269524;
                //scale = 0.58643550768408892;
                foreach (Sphere s in surfaces)
                {
                    Sphere.ScaleSphere(s, scaling);
                }
            }

            bool facetCentered = false;

            if (facetCentered)
            {
                PrepForFacetCentering(p, q, surfaces, ref cellCenter);
            }

            // Move to ball if needed.
            if (moveToBall)
            {
                surfaces = MoveToBall(surfaces, ref cellCenter);
            }

            return(surfaces);
        }
示例#14
0
        public static Vector3D VertexSpherical(int p, int q, int r)
        {
            double circumRadius = Spherical2D.s2eNorm(Honeycomb.CircumRadius(p, q, r));

            return(new Vector3D(0, 0, -circumRadius));
        }