Esempio n. 1
0
        public static Vector3D EdgeToPlane(Geometry g, H3.Cell.Edge edge)
        {
            if (g != Geometry.Hyperbolic)
            {
                throw new System.NotImplementedException();
            }

            Vector3D b1, b2;

            H3Models.Ball.GeodesicIdealEndpoints(edge.Start, edge.End, out b1, out b2);
            if (((b2 + b1) / 2).IsOrigin)
            {
                Vector3D lineNormal = b2 - b1;
                lineNormal.RotateXY(Math.PI / 2);
                lineNormal.Normalize();
                return(new Vector3D(lineNormal.X, lineNormal.Y, lineNormal.Z, 0));
            }

            Vector3D center, normal;
            double   radius, angleTot;

            H3Models.Ball.Geodesic(edge.Start, edge.End, out center, out radius, out normal, out angleTot);

            Vector3D closest = H3Models.Ball.ClosestToOrigin(new Circle3D()
            {
                Center = center, Radius = radius, Normal = normal
            });
            Vector3D closestKlein = HyperbolicModels.PoincareToKlein(closest);

            center.Normalize();
            return(new Vector3D(center.X, center.Y, center.Z, closestKlein.Abs()));
        }
Esempio n. 2
0
        // So that we can leverage Euclidean barycentric coordinates, we will first convert our simplex to the Klein model.
        // We will need to take care to properly convert back to the Ball as needed.
        public static Vector3D[] KleinVerts(Geometry g, Vector3D[] conformalVerts)
        {
            return(conformalVerts.Select(v =>
            {
                switch (g)
                {
                case Geometry.Spherical:
                    return SphericalModels.StereoToGnomonic(v);

                case Geometry.Euclidean:
                    return v;

                case Geometry.Hyperbolic:
                    return HyperbolicModels.PoincareToKlein(v);
                }

                throw new System.ArgumentException();
            }).ToArray());
        }
Esempio n. 3
0
        public static void Polarity()
        {
            TilingConfig config = new TilingConfig(3, 7, 50);
            Tiling       tiling = new Tiling();

            tiling.GenerateInternal(config);

            List <Vector3D>     points = new List <Vector3D>();
            List <H3.Cell.Edge> edges  = new List <H3.Cell.Edge>();

            foreach (Polygon p in tiling.Tiles.Select(t => t.Boundary))
            {
                foreach (Segment s in p.Segments)
                {
                    foreach (Vector3D v in s.Subdivide(25))
                    {
                        Vector3D     klein = HyperbolicModels.PoincareToKlein(v);
                        H3.Cell.Edge e     = Dual(klein);
                        points.Add(klein);
                        edges.Add(e);
                    }
                }
            }

            using (StreamWriter sw = File.CreateText("polarity.pov"))
            {
                double rad = 0.01;
                foreach (Vector3D vert in points)
                {
                    sw.WriteLine(PovRay.Sphere(new Sphere()
                    {
                        Center = vert, Radius = rad
                    }));
                }
                foreach (H3.Cell.Edge edge in edges)
                {
                    sw.WriteLine(PovRay.Cylinder(edge.Start, edge.End, rad / 2));
                }
            }
        }
Esempio n. 4
0
        public static Circle3D GetCircleForBallPoint(Vector3D p)
        {
            Sphere ball = new Sphere();

            p = SphericalModels.GnomonicToStereo(p);

            if (Tolerance.GreaterThanOrEqual(p.Abs(), 1))
            {
                return(null);
            }

            Sphere t = H3Models.Ball.OrthogonalSphereInterior(p);

            //return H3Models.Ball.IdealCircle( t );

            // Get the corresponding point on the exterior (our inversion).
            p = HyperbolicModels.PoincareToKlein(p);
            p = HyperbolicModels.PoincareToKlein(p);
            p = ball.ReflectPoint(p);

            return(GetCircle(p));
        }
Esempio n. 5
0
        // CHEAT! (would be better to do a geometrical construction)
        // We are going to iterate to the starting point that will make all edge lengths the same.
        public static Vector3D IterateToStartingPoint(HoneycombDef?def, int[] activeMirrors, Simplex simplex)
        {
            if (activeMirrors.Length == 1)
            {
                return(simplex.Verts[activeMirrors[0]]);
            }

            // We are minimizing the output of this function,
            // because we want all edge lengths to be as close as possible.
            // Input vector should be in the Ball Model.
            Func <Vector3D, double> diffFunc = v =>
            {
                List <double> lengths = new List <double>();
                for (int i = 0; i < activeMirrors.Length; i++)
                {
                    Vector3D reflected = simplex.ReflectInFacet(v, activeMirrors[i]);
                    lengths.Add(H3Models.Ball.HDist(v, reflected));
                }

                double result  = 0;
                double average = lengths.Average();
                foreach (double length in lengths)
                {
                    result += Math.Abs(length - average);
                }
                if (Infinity.IsInfinite(result))
                {
                    result = double.PositiveInfinity;
                }
                return(result);
            };

            // So that we can leverage Euclidean barycentric coordinates, we will first convert our simplex to the Klein model.
            // We will need to take care to properly convert back to the Ball as needed.
            Vector3D[] kleinVerts = simplex.Verts.Select(v => HyperbolicModels.PoincareToKlein(v)).ToArray();
            if (def != null)
            {
                HoneycombDef d = def.Value;
                Geometry     vertexGeometry = Geometry2D.GetGeometry(d.Q, d.R);
                if (vertexGeometry == Geometry.Hyperbolic)
                {
                    kleinVerts[3] = SimplexCalcs.VertexPointKlein(d.P, d.Q, d.R);
                }
            }

            // Normalizing barycentric coords amounts to making sure the 4 coords add to 1.
            Func <Vector3D, Vector3D> baryNormalize = b =>
            {
                return(b / (b.X + b.Y + b.Z + b.W));
            };

            // Bary Coords to Euclidean
            Func <Vector3D[], Vector3D, Vector3D> baryToEuclidean = (kv, b) =>
            {
                Vector3D result =
                    kv[0] * b.X + kv[1] * b.Y + kv[2] * b.Z + kv[3] * b.W;
                return(result);
            };

            // Our starting barycentric coords (halfway between all active mirrors).
            Vector3D bary = new Vector3D();

            foreach (int a in activeMirrors)
            {
                bary[a] = 0.5;
            }
            bary = baryNormalize(bary);

            // For each iteration, we'll shrink this search offset.
            // NOTE: The starting offset and decrease factor I'm using don't guarantee convergence,
            // but it seems to be working pretty well (even when varying these parameters).
            //double searchOffset = 1.0 - bary[activeMirrors[0]];
            //double searchOffset = bary[activeMirrors[0]];
            double factor       = 1.5;          // Adjusting this helps get some to converge, e.g. 4353-1111
            double searchOffset = bary[activeMirrors[0]] / factor;

            double min        = double.MaxValue;
            int    iterations = 1000;

            for (int i = 0; i < iterations; i++)
            {
                min = diffFunc(HyperbolicModels.KleinToPoincare(baryToEuclidean(kleinVerts, bary)));
                foreach (int a in activeMirrors)
                {
                    Vector3D baryTest1 = bary, baryTest2 = bary;
                    baryTest1[a] += searchOffset;
                    baryTest2[a] -= searchOffset;
                    baryTest1     = baryNormalize(baryTest1);
                    baryTest2     = baryNormalize(baryTest2);

                    double t1 = diffFunc(HyperbolicModels.KleinToPoincare(baryToEuclidean(kleinVerts, baryTest1)));
                    double t2 = diffFunc(HyperbolicModels.KleinToPoincare(baryToEuclidean(kleinVerts, baryTest2)));
                    if (t1 < min)
                    {
                        min  = t1;
                        bary = baryTest1;
                    }
                    if (t2 < min)
                    {
                        min  = t2;
                        bary = baryTest2;
                    }
                }

                if (Tolerance.Equal(min, 0.0, 1e-14))
                {
                    System.Console.WriteLine(string.Format("Converged in {0} iterations.", i));
                    break;
                }

                searchOffset /= factor;
            }

            if (!Tolerance.Equal(min, 0.0, 1e-14))
            {
                System.Console.WriteLine("Did not converge: " + min);

                // Be a little looser before thrown an exception.
                if (!Tolerance.Equal(min, 0.0, 1e-12))
                {
                    System.Console.ReadKey(true);
                    //throw new System.Exception( "Boo. We did not converge." );
                    return(Vector3D.DneVector());
                }
            }

            Vector3D euclidean = baryToEuclidean(kleinVerts, bary);

            return(HyperbolicModels.KleinToPoincare(euclidean));
        }
Esempio n. 6
0
        public static H3.Cell.Edge[] OneHoneycombOrthoscheme(HoneycombDef def, int[] active, int baseHue, Settings settings = null)
        {
            // Setup parameters.
            int numEdges = 250000;

            if (settings != null)
            {
                active   = settings.PovRay.Active;
                def      = new HoneycombDef(settings.P, settings.Q, settings.R);
                numEdges = settings.PovRay.NumEdges;
            }

            CalcThickness(active);
            if (settings != null)
            {
                H3.m_settings.AngularThickness = settings.PovRay.EdgeWidth;                     // ZZZ - should really stop using that settings class.
            }
            string baseName      = BaseName(def);
            string mirrorsString = ActiveMirrorsString(active);
            string suffix        = "-" + mirrorsString;
            string fileName      = baseName + suffix;

            if (ViewPath != null)
            {
                fileName += string.Format("_{0:D4}", ViewPath.Step);
            }

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

            Program.Log(string.Format("Building {0}", fileName));

            // The wiki mirrors are labeled in the reverse of ours.
            Func <int, int> mapMirror = i => 3 - i;

            active = active.Select(i => mapMirror(i)).OrderBy(i => i).ToArray();

            Simplex simplex = new Simplex();

            simplex.Facets = SimplexCalcs.Mirrors(def.P, def.Q, def.R);
            simplex.Verts  = SimplexCalcs.VertsBall(def.P, def.Q, def.R);

            Vector3D startingPoint = IterateToStartingPoint(def, active, simplex);

            if (startingPoint.DNE)
            {
                return(null);
            }
            List <H3.Cell.Edge> startingEdges = new List <H3.Cell.Edge>();

            foreach (int a in active)
            {
                Vector3D reflected = simplex.ReflectInFacet(startingPoint, a);
                startingEdges.Add(new H3.Cell.Edge(startingPoint, reflected));
                //startingEdges.Add( new H3.Cell.Edge( simplex.Verts[0], simplex.Verts[3] ) );	// Used for Borromean Rings complement image.
            }

            if (false)
            {
                Vector3D[] kv = simplex.Verts.Select(v => HyperbolicModels.PoincareToKlein(v)).ToArray();
                kv[3] = SimplexCalcs.VertexPointKlein(def.P, def.Q, def.R);
                Vector3D t       = (kv[3] - kv[0]) * 0.5;
                Sphere   gSphere = H3Models.Ball.OrthogonalSphereInterior(HyperbolicModels.KleinToPoincare(t));
                gSphere = H3Models.BallToKlein(gSphere);
                Vector3D t2 = Euclidean3D.IntersectionPlaneLine(gSphere.Normal, gSphere.Offset, kv[3] - kv[2], kv[2]);
                //t2 = kv[2] + ( kv[3] - kv[2]) * 0.5;

                t  = HyperbolicModels.KleinToPoincare(t);
                t2 = HyperbolicModels.KleinToPoincare(t2);
                startingEdges.Add(new H3.Cell.Edge(t, t2));
                startingEdges.Add(new H3.Cell.Edge(t, simplex.ReflectInFacet(t, 3)));
            }

            // If we are doing a view path, transform our geometry.
            if (ViewPath != null)
            {
                //Vector3D p = new Vector3D( 0, 0, .5 );
                Vector3D p = new Vector3D(0.08, 0.12, 0.07);
                simplex.Facets = simplex.Facets.Select(f => H3Models.Transform_PointToOrigin(f, p)).ToArray();
                simplex.Verts  = simplex.Verts.Select(v => H3Models.Transform_PointToOrigin(v, p)).ToArray();
                startingEdges  = startingEdges.Select(e => new H3.Cell.Edge(
                                                          H3Models.Transform_PointToOrigin(e.Start, p),
                                                          H3Models.Transform_PointToOrigin(e.End, p))).ToList();
            }

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

            H3.Cell.Edge[] edges = Recurse.CalcEdgesSmart2(simplex.Facets, startingEdges.ToArray(), numEdges);
            //H3.Cell.Edge[] edges = Recurse.CalcEdges( simplex.Facets, startingEdges.ToArray(),
            //	new Recurse.Settings() { ThreshType = Recurse.EdgeThreshType.Radial, Threshold = H3Models.Ball.FindLocationForDesiredRadius( settings.PovRay.EdgeWidth, 0.8/100 ) } );
            //edges = edges.Where( e => e.Depths[0] % 2 == 1 ).ToArray();	// Used for Borromean Rings complement image.

            // Shapeways truncated 436.
            if (false)
            {
                if (true)
                {
                    Mobius m = Mobius.Scale(1.0 / H3Models.UHS.ToE(Honeycomb.InRadius(def.P, def.Q, def.R)));
                    double a = -Math.PI / 2 + Math.Asin(1 / Math.Sqrt(3));
                    edges = edges.Select(e =>
                    {
                        Vector3D v1 = e.Start;
                        Vector3D v2 = e.End;
                        v1.RotateAboutAxis(new Vector3D(1, 0, 0), a);
                        v2.RotateAboutAxis(new Vector3D(1, 0, 0), a);
                        v1 = H3Models.Ball.ApplyMobius(m, v1);
                        v2 = H3Models.Ball.ApplyMobius(m, v2);
                        return(new H3.Cell.Edge(v1, v2));
                    }).ToArray();

                    double   thresh  = -.01;
                    Vector3D looking = new Vector3D(0, 0, -1);
                    edges = edges.Where(e => e.Start.Dot(looking) > thresh && e.End.Dot(looking) > thresh).ToArray();

                    Dictionary <H3.Cell.Edge, int> edgeDict = edges.ToDictionary(e => e, e => 1);
                    H3.RemoveDanglingEdgesRecursive(edgeDict);
                    edges = edgeDict.Keys.ToArray();
                }
                else
                {
                    Mobius m = Mobius.Scale(2);
                    edges = edges.Select(e =>
                    {
                        Vector3D v1 = e.Start;
                        Vector3D v2 = e.End;
                        v1          = H3Models.Ball.ApplyMobius(m, v1);
                        v2          = H3Models.Ball.ApplyMobius(m, v2);
                        return(new H3.Cell.Edge(v1, v2));
                    }).ToArray();

                    Dictionary <H3.Cell.Edge, int> edgeDict = edges.ToDictionary(e => e, e => 1);
                    H3.RemoveDanglingEdgesRecursive(edgeDict);
                    edges = edgeDict.Keys.ToArray();
                }
            }

            //H3.m_settings.Output = H3.Output.STL;
            //H3.m_settings.Scale = 50;
            H3.SaveToFile(fileName, edges, finite: true, append: true);

            bool doCells = false;

            H3.Cell[] cellsToHighlight = null;
            if (doCells)
            {
                int[] polyMirrors = new int[] { 1, 2, 3 };
                active = active.Select(i => mapMirror(i)).OrderBy(i => i).ToArray();

                H3.Cell startingCell = PolyhedronToHighlight(Geometry.Hyperbolic, polyMirrors, simplex, startingPoint);
                cellsToHighlight = Recurse.CalcCells(simplex.Facets, new H3.Cell[] { startingCell });
                H3.AppendFacets(fileName, cellsToHighlight);
            }

            return(edges);
        }
Esempio n. 7
0
        private static void HyperidealSquares()
        {
            Mobius rot = new Mobius();

            rot.Isometry(Geometry.Spherical, Math.PI / 4, new Vector3D());

            List <Segment> segs = new List <Segment>();

            int[] qs = new int[] { 5, -1 };
            foreach (int q in qs)
            {
                TilingConfig   config   = new TilingConfig(4, q, 1);
                Tile           t        = Tiling.CreateBaseTile(config);
                List <Segment> polySegs = t.Boundary.Segments;
                polySegs = polySegs.Select(s => { s.Transform(rot); return(s); }).ToList();
                segs.AddRange(polySegs);
            }

            Vector3D v1 = new Vector3D(1, 0);

            v1.RotateXY(Math.PI / 6);
            Vector3D v2 = v1;

            v2.Y *= -1;
            Vector3D cen;
            double   rad;

            H3Models.Ball.OrthogonalCircle(v1, v2, out cen, out rad);
            Segment seg = Segment.Arc(v1, v2, cen, false);

            rot.Isometry(Geometry.Spherical, Math.PI / 2, new Vector3D());
            for (int i = 0; i < 4; i++)
            {
                seg.Transform(rot);
                segs.Add(seg.Clone());
            }

            SVG.WriteSegments("output1.svg", segs);

            System.Func <Segment, Segment> PoincareToKlein = s =>
            {
                return(Segment.Line(
                           HyperbolicModels.PoincareToKlein(s.P1),
                           HyperbolicModels.PoincareToKlein(s.P2)));
            };
            segs = segs.Select(s => PoincareToKlein(s)).ToList();

            Vector3D v0 = new Vector3D(v1.X, v1.X);
            Vector3D v3 = v0;

            v3.Y *= -1;
            Segment seg1 = Segment.Line(v0, v1), seg2 = Segment.Line(v2, v3);
            Segment seg3 = Segment.Line(new Vector3D(1, 1), new Vector3D(1, -1));

            for (int i = 0; i < 4; i++)
            {
                seg1.Transform(rot);
                seg2.Transform(rot);
                seg3.Transform(rot);
                segs.Add(seg1.Clone());
                segs.Add(seg2.Clone());
                segs.Add(seg3.Clone());
            }

            SVG.WriteSegments("output2.svg", segs);
        }