Exemple #1
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();
        }
Exemple #2
0
        /// <summary>
        /// Offsets a vector by a hyperbolic distance.
        /// </summary>
        public static Vector3D Offset(Vector3D v, double hDist)
        {
            double mag = v.Abs();

            mag = DonHatch.h2eNorm(DonHatch.e2hNorm(mag) + hDist);
            v.Normalize();
            v *= mag;
            return(v);
        }
Exemple #3
0
        public void AnimationSections(Settings config)
        {
            HoneycombDef imageData = new HoneycombDef(config.P, config.Q, config.R);
            int          p = imageData.P, q = imageData.Q, r = imageData.R;

            string filename = imageData.FormatFilename();

            Sphere[] mirrors = SimplexCalcs.Mirrors(p, q, r);
            double   bounds  = 1.0;          //config.UhsBoundary.Bounds;

            bounds = 9.0;

            // Calculate the color scale.
            int size = 200;

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

            CoxeterImages imageCalculator = new CoxeterImages();

            //imageCalculator.AutoCalcScale( settings );
            if (settings.ColorScaling < 1)
            {
                settings.ColorScaling = 15;
            }
            settings.ColorScaling = 11;

            Program.Log("\nGenerating sections...");
            size              = 500;
            settings.Width    = size;
            settings.Height   = size;
            settings.FileName = filename;

            double max = Spherical2D.e2sNorm(15);
            double min = Spherical2D.e2sNorm(1.0 / 15);

            DonHatch.e2hNorm(max);
            int    numSteps = 1800;          // 1 minute
            double step     = (max - min) / numSteps;

            for (int i = 0; i < 1; i++)
            {
                Program.Log("\nSection " + i);
                imageCalculator.m_z = 1.0 / 0.5;
                Spherical2D.s2eNorm(min + step * i);
                DonHatch.h2eNorm(step * i);
                settings.FileName = string.Format("533_{0:D4}.png", i);
                imageCalculator.GenImage(settings);
            }
        }
Exemple #4
0
        private void Transform(double anim, IEnumerable <Tile> tetTiles)
        {
            //TilingConfig config = new TilingConfig( 8, 3, 4 );	// Reproduces Tolerance issues with {3,3,7}, though not actually correct to be applying hyperbolic transforms anyway (only spherical).
            TilingConfig config = new TilingConfig(3, 3, 1);
            Mobius       m      = new Mobius();

            m = Mobius.Identity();

            // Invert
            Complex c1 = new Complex(0, 1);
            Complex c2 = new Complex(1, 0);
            Complex c3 = new Complex(0, -0.999999999999);               // - 1 doesn't work
            //m.MapPoints( c1, c2, c3, c3, c2, c1 );

            //Mobius m = config.DualMobius();
            //m.Isometry( Geometry.Spherical, 0, new Complex( 1.2345, -0.4321 ) );	// nice one
            //m.Isometry( Geometry.Spherical, 0, new Complex( 0, 0.148125 ) );		 // half plane

            // Animation.
            double p2       = DonHatch.e2hNorm(0.6);
            double p2Interp = DonHatch.h2eNorm(p2 * anim);

            //m.Isometry( Geometry.Spherical, 0, -p2Interp );
            m.Isometry(Geometry.Hyperbolic, 0, new Complex(-p2Interp, 0));

            Mobius m2 = new Mobius();

            m2.Isometry(Geometry.Hyperbolic, 0, new Complex(-0.6, 0));
            m2 = m_fixedCircleToStandardDisk.Inverse() * m2 * m_fixedCircleToStandardDisk;

            bool firstAnim = false;

            if (firstAnim)
            {
                m            = m_fixedCircleToStandardDisk.Inverse() * m * m_fixedCircleToStandardDisk;
                m_animMobius = m;
            }
            else
            {
                m            = m_neighborToStandardDisk.Inverse() * m * m_neighborToStandardDisk;
                m_animMobius = m2 * m;
            }
            m_animMobius.Normalize();

            foreach (Tile t in tetTiles)
            {
                t.Transform(m_animMobius);
            }
            foreach (Tile t in m_tiles)
            {
                t.Transform(m_animMobius);
            }
            m_equator.Transform(m_animMobius);
            m_neighborCircle.Transform(m_animMobius);
        }
Exemple #5
0
        /// <summary>
        /// Equally subdivides a segment with a startpoint at the origin, in the respective geometry.
        /// </summary>
        private static Vector3D[] SubdivideRadialInGeometry(Segment radial, int divisions, Geometry g)
        {
            List <Vector3D> result = new List <Vector3D>();

            if (radial.Type != SegmentType.Line)
            {
                Debug.Assert(false);
                return(result.ToArray());
            }

            switch (g)
            {
            case Geometry.Spherical:
            {
                double eLength   = radial.Length;
                double sLength   = Spherical2D.e2sNorm(eLength);
                double divLength = sLength / divisions;

                for (int i = 0; i <= divisions; i++)
                {
                    double temp = Spherical2D.s2eNorm(divLength * i);
                    result.Add(radial.P2 * temp / eLength);
                }

                break;
            }

            case Geometry.Euclidean:
                return(radial.Subdivide(divisions));

            case Geometry.Hyperbolic:
            {
                double eLength   = radial.Length;
                double hLength   = DonHatch.e2hNorm(eLength);
                double divLength = hLength / divisions;

                for (int i = 0; i <= divisions; i++)
                {
                    double temp = DonHatch.h2eNorm(divLength * i);
                    result.Add(radial.P2 * temp / eLength);
                }

                break;
            }
            }

            return(result.ToArray());
        }
Exemple #6
0
        public static Sphere GeodesicOffset(Sphere s, double offset, bool ball = true)
        {
            Sphere offsetSphere;

            if (ball)
            {
                // Geodesic offset (ball).

                {                       // Hyperbolic honeycomb
                    double mag = s.Center.Abs() - s.Radius;
                    mag = s.IsPlane ? DonHatch.h2eNorm(offset) :
                          DonHatch.h2eNorm(DonHatch.e2hNorm(mag) - offset);

                    Vector3D closestPointToOrigin = s.IsPlane ? s.Normal : s.Center;
                    closestPointToOrigin.Normalize();
                    closestPointToOrigin *= mag;
                    offsetSphere          = H3Models.Ball.OrthogonalSphereInterior(closestPointToOrigin);

                    // There are multiple ultraparallel spheres.
                    // This experiments with picking others.
                    Mobius m = new Mobius();
                    m.Isometry(Geometry.Hyperbolic, 0, new Vector3D(0, -0.2));
                    //H3Models.TransformInBall2( offsetSphere, m );
                }

                {                       // Spherical honeycomb
                                        //offset *= -1;
                    double mag = -s.Center.Abs() + s.Radius;
                    Spherical2D.s2eNorm(Spherical2D.e2sNorm(mag) + offset);

                    offsetSphere         = s.Clone();
                    offsetSphere.Radius += offset * 10;
                }
            }
            else
            {
                // Geodesic offset (UHS).
                // XXX - not scaled right.
                offsetSphere         = s.Clone();
                offsetSphere.Radius += offset;
            }

            return(offsetSphere);
        }
Exemple #7
0
        public H3.Cell.Edge[] Helicoid()
        {
            List <H3.Cell.Edge> fiberList = new List <H3.Cell.Edge>();

            // These two params affect each other (changing numFibers will affect rotation rate).
            double rotationRate = Math.PI / 78.5;
            int    numFibers    = 1000;

            // Note: we need to increment a constant hyperbolic distance each step.
            int    count  = 0;
            double max    = DonHatch.e2hNorm(0.998);
            double offset = max * 2 / (numFibers - 1);

            for (double z_h = -max; z_h <= max; z_h += offset)
            {
                double z = DonHatch.h2eNorm(z_h);

                Sphere   s = H3Models.Ball.OrthogonalSphereInterior(new Vector3D(0, 0, z));
                Circle3D c = H3Models.Ball.IdealCircle(s);

                // Two endpoints of our fiber.
                Vector3D v1 = new Vector3D(c.Radius, 0, c.Center.Z);
                Vector3D v2 = new Vector3D(-c.Radius, 0, c.Center.Z);

                v1.RotateXY(rotationRate * count);
                v2.RotateXY(rotationRate * count);

                v1 = Transform(v1);
                v2 = Transform(v2);

                Vector3D t      = Transform(new Vector3D(0, 0, z));
                double   cutoff = 0.995;
                if (t.Abs() > cutoff)
                {
                    continue;
                }

                fiberList.Add(new H3.Cell.Edge(v1, v2, order: false));
                count++;
            }

            return(fiberList.ToArray());
        }
Exemple #8
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);
        }