예제 #1
0
        /// <summary>
        /// Returns the mid-radius, in the induced geometry.
        /// </summary>
        public static double MidRadius(int p, int q, int r)
        {
            double pir = PiOverNSafe(r);

            double inRadius  = InRadius(p, q, r);
            double midRadius = DonHatch.sinh(inRadius) / Math.Sin(pir);

            switch (GetGeometry(p, q, r))
            {
            case Geometry.Hyperbolic:
                return(DonHatch.asinh(midRadius));

            case Geometry.Spherical:
                return(Math.Asin(midRadius));
            }

            throw new System.NotImplementedException();
        }
예제 #2
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);
        }
예제 #3
0
        private static double EqualAreaToPoincare(double dist)
        {
            double h = 2 * DonHatch.asinh(dist);

            return(DonHatch.h2eNorm(h));
        }
예제 #4
0
        // In hyperboloid model
        public static double GeodesicPlaneHSDF(Vector3D samplePoint, Vector3D dualPoint, double offset = 0)
        {
            double dot = -DotInGeometry(Geometry.Hyperbolic, samplePoint, dualPoint);

            return(DonHatch.asinh(dot) - offset);
        }