Exemplo n.º 1
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);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Attempts to calculate approx 1.3M edges when the threshold is a distance from origin in the ball model.
        /// This works for honeycombs with finite cells.
        /// </summary>
        public static Edge[] CalcEdgesSmart(Sphere[] simplex, Edge[] edges, int desiredCount)
        {
            Settings s = new Settings();

            s.ThreshType = EdgeThreshType.Radial;

            // The number of cells increase exponentially with hyperbolic distance,
            // so linear on a log scale.
            // We'll do to test runs to get the line, then run at the extrapolated value.
            double hDist = 5;

            s.Threshold = DonHatch.h2eNorm(hDist);
            Edge[] result = CalcEdges(simplex, edges, s);
            int    count1 = result.Length;

            hDist       = 5.5;
            s.Threshold = DonHatch.h2eNorm(hDist);
            result      = CalcEdges(simplex, edges, s);
            int count2 = result.Length;

            double slope           = (Math.Log(count2) - Math.Log(count1)) / 0.5;
            double logDesiredCount = Math.Log(desiredCount);

            hDist = 5.5 + (logDesiredCount - Math.Log(count2)) / slope;

            s.Threshold = DonHatch.h2eNorm(hDist);
            return(CalcEdges(simplex, edges, s));
        }
Exemplo n.º 3
0
        private Tile TemplateTile()
        {
            double inRadiusHyp       = InRadius;
            double inRadiusEuclidean = DonHatch.h2eNorm(inRadiusHyp);
            double faceRadius        = FaceRadius(inRadiusEuclidean);

            // Calc the midpoint, and project to plane.
            Vector3D midPoint = MidPoint(inRadiusEuclidean, faceRadius);

            midPoint.Z *= -1;
            midPoint    = Sterographic.SphereToPlane(midPoint);
            //double midPointSpherical = MidPoint( inRadiusEuclidean, faceRadius );
            //double midPoint = Spherical2D.s2eNorm( midPointSpherical );

            // Create and scale based on our midpoint.
            Polygon poly = new Polygon();

            poly.CreateRegular(Q, R);
            double standardMidpointAbs = poly.Segments[0].Midpoint.Abs();

            m_shrink = midPoint.Abs() / standardMidpointAbs;
            poly.Scale(m_shrink);

            Matrix4D m = Matrix4D.MatrixToRotateinCoordinatePlane(-Math.PI / Q, 0, 1);

            poly.Rotate(m);

            return(new Tile(poly, poly.Clone(), Geometry.Hyperbolic));
        }
Exemplo n.º 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();
        }
Exemplo n.º 5
0
        /// <summary>
        /// Get the length of the side of a triangle opposite alpha, given the three angles of the triangle.
        /// NOTE: This does not work in Euclidean geometry!
        /// </summary>
        public static double GetTriangleSide(Geometry g, double alpha, double beta, double gamma)
        {
            switch (g)
            {
            case Geometry.Spherical:
            {
                // Spherical law of cosines
                return(Math.Acos((Math.Cos(alpha) + Math.Cos(beta) * Math.Cos(gamma)) / (Math.Sin(beta) * Math.Sin(gamma))));
            }

            case Geometry.Euclidean:
            {
                // Not determined in this geometry.
                Debug.Assert(false);
                return(0.0);
            }

            case Geometry.Hyperbolic:
            {
                // Hyperbolic law of cosines
                // http://en.wikipedia.org/wiki/Hyperbolic_law_of_cosines
                return(DonHatch.acosh((Math.Cos(alpha) + Math.Cos(beta) * Math.Cos(gamma)) / (Math.Sin(beta) * Math.Sin(gamma))));
            }
            }

            // Not determined in this geometry.
            Debug.Assert(false);
            return(0.0);
        }
Exemplo n.º 6
0
        private static Sphere[] GetSpheres(Sphere[] facets, Vector3D[] verts, Vector3D interiorPoint, double inSphereHRad)
        {
            // Get relevant points (near) inSphere.
            Vector3D[] transformed = verts.Select(v =>
            {
                v = H3Models.Transform_PointToOrigin(v, interiorPoint);
                v.Normalize();
                v *= DonHatch.h2eNorm(inSphereHRad * .5);
                v  = H3Models.Transform_PointToOrigin(v, -interiorPoint);
                return(v);
            }).ToArray();

            List <Sphere> result = new List <R3.Geometry.Sphere>();

            result.Add(ConstructSphere(facets, transformed[0], new int[] { 1, 2, 3 }));
            result.Add(ConstructSphere(facets, transformed[1], new int[] { 0, 2, 3 }));
            result.Add(ConstructSphere(facets, transformed[2], new int[] { 0, 1, 3 }));
            result.Add(ConstructSphere(facets, transformed[3], new int[] { 0, 1, 2 }));
            return(result.ToArray());

            /*Vector3D[] verts = SimplexCalcs.VertsBall( p, q, r );
             * for( int i = 0; i < 4; i++ )
             * {
             *      double hDist = H3Models.Ball.HDist( cen, verts[i] ) - .05;
             *      System.Diagnostics.Trace.WriteLine( hDist + " " + DonHatch.h2eNorm( hDist ) );
             * }*/
        }
Exemplo n.º 7
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));
        }
Exemplo n.º 8
0
        public static Vector3D Dini(Vector3D uv, double a, double b)
        {
            uv = DiskToUpper(uv);

            // Eq 1.86 on p36 of book Backlund and Darboux Transformations
            double eta = Math.PI / 2 - Math.PI / 20;
            //double eta = Math.PI / 2;
            double p = 1;                    // curvature
            double x = DonHatch.acosh(uv.Y); // Used info on mathworld for tractrix to figure this out.
            //double x = DonHatch.acosh( Math.Exp( DonHatch.acosh( ( uv.Y * uv.Y + 1 ) / ( 2 * uv.Y ) ) ) );
            //double x = Math.Log( uv.Y );
            double y = uv.X;

            double pSinEta = p * Math.Sin(eta);
            double chi     = (x - y * Math.Cos(eta)) / pSinEta;

            if (x <= -4 || x > 4 ||
                y < -3 * Math.PI || y > 3 * Math.PI)
            {
                return(Infinity.InfinityVector);
            }

            Vector3D result = new Vector3D(
                pSinEta * Sech(chi) * Math.Cos(y / p),
                pSinEta * Sech(chi) * Math.Sin(y / p),
                x - pSinEta * Math.Tanh(chi));

            return(result);

            /*
             * System.Func<double, Complex> tractrix = new System.Func<double, Complex>(
             * ( t ) =>
             * {
             *      //return new Complex( t - Math.Tanh( t ), 1.0 / Math.Cosh( t ) );
             *      return new Complex( - Math.Sqrt( 1 - 1 / (t*t) ) + DonHatch.acosh( t ), 1.0 / t );
             * } );
             *
             * double logy = Math.Log( uv.Y );
             * //Complex tract = tractrix( logy );
             * Complex tract = tractrix( uv.Y );
             * return new Vector3D(
             *      a * Math.Cos( uv.X ) * tract.Imaginary,
             *      a * Math.Sin( uv.X ) * tract.Imaginary,
             *      a * tract.Real + b * uv.X );
             */

            /*
             * return new Vector3D(
             *      a * Math.Cos( uv.X ) / Math.Cosh( uv.Y ),
             *      a * Math.Sin( uv.X ) / Math.Cosh( uv.Y ),
             *      a * (uv.Y - Math.Tanh( uv.Y )) + b * uv.X ); */

            /*return new Vector3D(
             *      a * Math.Cos( uv.X ) * Math.Sin( uv.Y ),
             *      a * Math.Sin( uv.X ) * Math.Sin( uv.Y ),
             *      a * (Math.Cos( uv.Y ) + Math.Log( Math.Tan( 0.5 * uv.Y ) )) + b * uv.X );*/
        }
Exemplo n.º 9
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);
            }
        }
Exemplo n.º 10
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);
        }
Exemplo n.º 11
0
        public static double EdgeLength(int p, int q, int r)
        {
            double pip = PiOverNSafe(p);
            double pir = PiOverNSafe(r);

            double pi_hqr     = Pi_hpq(q, r);
            double edgeLength = 2 * DonHatch.acosh(Math.Cos(pip) * Math.Sin(pir) / Math.Sin(pi_hqr));

            return(edgeLength);
        }
Exemplo n.º 12
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);
        }
Exemplo n.º 13
0
        private static Sphere ConstructSphere(Vector3D p, double hDist)
        {
            double eDist = DonHatch.h2eNorm(hDist);

            Vector3D cen;
            double   rad;

            H3Models.Ball.DupinCyclideSphere(p, eDist, out cen, out rad);
            Sphere s = new Sphere()
            {
                Center = cen, Radius = rad
            };

            return(s);
        }
Exemplo n.º 14
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());
        }
Exemplo n.º 15
0
        static public double OffsetInModel(Tiler.Settings settings, double p = 0, double q = 0, double r = 1)
        {
            double off = OffsetInSpace(settings, p, q, r);

            switch (settings.Geometry)
            {
            case Geometry.Spherical:
                off = Spherical2D.s2eNorm(off);
                break;

            case Geometry.Hyperbolic:
                off = DonHatch.h2eNorm(off);
                break;
            }
            return(off);
        }
Exemplo n.º 16
0
        internal static void CalcSelfSimilarityScale()
        {
            double   inRadius   = DonHatch.h2eNorm(Honeycomb.InRadius(4, 3, 7));
            Vector3D facePoint  = new Vector3D(0, 0, -inRadius);
            Sphere   s          = H3Models.Ball.OrthogonalSphereInterior(facePoint);
            Vector3D facePoint2 = new Vector3D(0, 0, inRadius);

            facePoint2 = s.ReflectPoint(facePoint2);

            facePoint  = H3Models.BallToUHS(facePoint);
            facePoint2 = H3Models.BallToUHS(facePoint2);

            double scale = facePoint.Z / facePoint2.Z;

            scale += 0;
        }
Exemplo n.º 17
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();
        }
Exemplo n.º 18
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);
        }
Exemplo n.º 19
0
        /// <summary>
        /// Returns the in-radius, in the induced geometry.
        /// </summary>
        public static double InRadius(int p, int q, int r)
        {
            double pip = PiOverNSafe(p);
            double pir = PiOverNSafe(r);

            double pi_hpq   = Pi_hpq(p, q);
            double inRadius = Math.Sin(pip) * Math.Cos(pir) / Math.Sin(pi_hpq);

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

            case Geometry.Spherical:
                return(Math.Acos(inRadius));
            }

            throw new System.NotImplementedException();
        }
Exemplo n.º 20
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());
        }
Exemplo n.º 21
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);
        }
Exemplo n.º 22
0
 public static double SphereToCyl(double x)
 {
     return(DonHatch.atanh(Math.Sin(x)));
 }
Exemplo n.º 23
0
        private static double EqualAreaToPoincare(double dist)
        {
            double h = 2 * DonHatch.asinh(dist);

            return(DonHatch.h2eNorm(h));
        }
Exemplo n.º 24
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);
        }
Exemplo n.º 25
0
        public static void CatenoidBasedSurface()
        {
            RLD_outputs outputs;

            SurfaceInternal(out outputs);
            double scale = m_params.Scale;

            // Map a point for a given k/m from the hemihypersphere to the complex plane.
            // You can also pass in -1 for k to get a point on the equator of the hemihypersphere.
            double mInc = Math.PI * 2 / m_params.M;
            Func <RLD_outputs, int, int, Vector3D> onPlane = (o, k, m) =>
            {
                double theta = k == -1 ? 0 : outputs.x_i[k];
                theta += Math.PI / 2;
                return
                    (Sterographic.SphereToPlane(
                         SphericalCoords.SphericalToCartesian(
                             new Vector3D(1, theta, m * mInc)
                             )
                         ));
            };

            // Setup texture coords on fundamental triangle.
            // We'll use a fundamental triangle in the southern hemisphere,
            // with stereographically projected coords at (0,0), (1,0), and CCW on the unit circle depending on M.
            Polygon p = new Polygon();

            p.Segments.Add(Segment.Line(new Vector3D(), new Vector3D(1, 0)));
            p.Segments.Add(Segment.Arc(new Vector3D(1, 0), onPlane(outputs, 1, 1), onPlane(outputs, -1, 1)));
            p.Segments.Add(Segment.Line(onPlane(outputs, -1, 1), new Vector3D()));
            int levels = 9;

            TextureHelper.SetLevels(levels);
            Vector3D[] coords         = TextureHelper.TextureCoords(p, Geometry.Spherical, doGeodesicDome: true);
            int[]      elementIndices = TextureHelper.TextureElements(1, levels);

            // Setup a nearTree for the catenoid locations (on the plane).
            NearTree nearTree = new NearTree(Metric.Spherical);

            for (int k = 1; k < outputs.x_i.Length; k++)
            {
                for (int m = 0; m <= 1; m++)
                {
                    Vector3D loc = onPlane(outputs, k, m);
                    nearTree.InsertObject(new NearTreeObject()
                    {
                        ID = k, Location = loc
                    });
                }
            }

            // Given a point on the plane, find the nearest catenoid center and calculate the height of the surface based on that.
            // This also calculates the locking of the point.
            Func <Vector3D, Tuple <double, Vector3D, Vector3D> > heightAndLocking = coord =>
            {
                NearTreeObject closest;
                if (!nearTree.FindNearestNeighbor(out closest, coord, double.MaxValue))
                {
                    throw new System.Exception();
                }

                Vector3D locked = new Vector3D();
                if (p.Segments[0].IsPointOn(coord) ||
                    p.Segments[2].IsPointOn(coord))
                {
                    locked = new Vector3D(1, 1, 0, 0);
                }
                //if( p.Segments[1].IsPointOn( v ) )		// Not working right for some reason, but line below will work.
                if (Tolerance.Equal(coord.Abs(), 1))
                {
                    locked = new Vector3D(1, 1, 1, 0);
                }

                Vector3D vSphere = Sterographic.PlaneToSphere(coord);
                Vector3D cSphere = Sterographic.PlaneToSphere(closest.Location);
                double   dist    = vSphere.AngleTo(cSphere);

                int    k          = (int)closest.ID;
                double waist      = outputs.t_i[k];
                double rld_height = outputs.phi_i[k];

                double h      = waist * 3.5 * 2;                                        // height where catenoid will meet rld_height.
                double factor = scale * rld_height * 2 / h;                             // Artifical scaling so we can see things.
                dist /= factor;

                double z = double.NaN;
                if (dist >= waist)
                {
                    z = waist * DonHatch.acosh(dist / waist);
                }
                else if (dist >= 0.7 * waist)
                {
                    z = 0;

                    // Move the coord to the thinnest waist circle.
                    Mobius m = new Mobius();
                    m.Hyperbolic(Geometry.Spherical, coord.ToComplex(), waist / dist);
                    coord = m.Apply(coord);
                }

                if (dist < waist * 20)
                {
                    locked = new Vector3D(1, 1, 1, 1);
                }

                return(new Tuple <double, Vector3D, Vector3D>(z * factor, locked, coord));
            };

            // Calculate all the coordinates.
            Vector3D[] locks = new Vector3D[coords.Length];
            for (int i = 0; i < coords.Length; i++)
            {
                Vector3D coord = coords[i];
                var      hl    = heightAndLocking(coord);
                locks[i]  = hl.Item2;
                coord     = hl.Item3;
                coords[i] = Normal(Sterographic.PlaneToSphere(coord), (double)hl.Item1);
            }

            // Relax it.
            Relax(coords, elementIndices, locks);

            Mesh   mesh = new Mesh();
            Sphere s    = new Sphere();

            for (int i = 0; i < elementIndices.Length; i += 3)
            {
                Vector3D a = coords[elementIndices[i]];
                Vector3D b = coords[elementIndices[i + 1]];
                Vector3D c = coords[elementIndices[i + 2]];
                if (a.DNE || b.DNE || c.DNE)
                {
                    continue;
                }

                for (int m = 0; m <= 0; m++)
                {
                    mesh.Triangles.Add(new Mesh.Triangle(a, b, c));
                    mesh.Triangles.Add(new Mesh.Triangle(
                                           s.ReflectPoint(a),
                                           s.ReflectPoint(b),
                                           s.ReflectPoint(c)));
                    a.RotateXY(mInc);
                    b.RotateXY(mInc);
                    c.RotateXY(mInc);
                }
            }

            PovRay.WriteMesh(mesh, "RLD.pov");
        }
Exemplo n.º 26
0
        /// <summary>
        /// Calculate basePoints along a circle defined by a center on the z axis, and going through the point (0,0,1).
        /// .5 is horosphere, 1 is geodesic
        /// Result is in UHS model
        /// </summary>
        private static Vector3D[] BasePointsCircle(double centerUHS)
        {
            if (centerUHS > 1)
            {
                centerUHS = 1;
            }
            if (centerUHS < 0)
            {
                centerUHS = 0;
            }

            if (centerUHS == 0)
            {
                return new Vector3D[] { new Vector3D() }
            }
            ;

            bool hyperbolicOffsets = true;

            if (hyperbolicOffsets)
            {
                // h-distance between each point.
                double d = 0.1;

                // We need to work in 2D first, then we'll switch to xz plane.
                Circle circle = new Circle(new Vector3D(0, 1), new Vector3D(0, 1 - 2 * centerUHS), new Vector3D(centerUHS, 1 - centerUHS));

                // XXX - check to make sure total distance won't wrap around the circle.

                List <Vector3D> points = new List <Vector3D>();
                int             count  = 75;
                for (int i = -count; i <= count; i++)
                {
                    double currentD = d * i;

                    // Angle t around a circle with center c and radius r to get an h-distance.
                    // https://en.wikipedia.org/wiki/Poincar%C3%A9_half-plane_model
                    // http://www.wolframalpha.com/input/?i=d+%3D+arcosh%281%2B%28%28r*sin%28t%29%29%5E2%2B%28r*cos%28t%29-r%29%5E2%29%2F%282*%28c%2Br%29*%28c%2Br*cos%28t%29%29%29%29%2C+solve+for+t
                    double c           = circle.Center.Y;
                    double r           = circle.Radius;
                    double coshd       = DonHatch.cosh(currentD);
                    double numerator   = c * c - c * (c + r) * coshd + c * r + r * r;
                    double denominator = r * ((c + r) * coshd - c);
                    double angle       = Math.Acos(numerator / denominator);
                    if (i < 0)
                    {
                        angle *= -1;
                    }
                    points.Add(new Vector3D(r * Math.Sin(angle), 0, c + r * Math.Cos(angle)));

                    /*
                     * // XXX - This was my first attempt, but this code only works for geodesics, not general arcs!
                     * // Equidistant lines in UHS will all be lines through the origin.
                     * // In the following formula, x is the angle to use to get h-spaced equidistant line a distance d away.
                     * // http://www.wolframalpha.com/input/?i=d+%3D+arccosh%28sec%28x%29%29%2C+solve+for+x
                     * double angle = Math.Acos( 1.0 / DonHatch.cosh( currentD ) );
                     * angle = Math.PI/2 - angle;
                     * if( i < 0 )
                     *      angle *= -1;
                     *
                     * Vector3D p1, p2;
                     * Euclidean2D.IntersectionLineCircle( new Vector3D(), new Vector3D( Math.Cos(angle), Math.Sin(angle) ), circle, out p1, out p2 );
                     * Vector3D highest = p1.Y > p2.Y ? p1 : p2;
                     * points.Add( new Vector3D( highest.X, 0, highest.Y ) );
                     */
                }
                return(points.ToArray());
            }
            else
            {
                // equal euclidean spacing.
                Circle3D c = new Circle3D(new Vector3D(0, 0, 1), new Vector3D(0, 0, 1 - 2 * centerUHS), new Vector3D(centerUHS, 0, 1 - centerUHS));
                return(c.Subdivide(125));
            }
        }
Exemplo n.º 27
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);
        }
Exemplo n.º 28
0
        /// <summary>
        /// Calculates a mesh for a standard euclidean catenoid.
        /// This will need to be transformed to the various locations later.
        ///
        /// Like above, but we adjust the xy components of the mesh using one of the mappings described here:
        /// https://arxiv.org/ftp/arxiv/papers/1509/1509.06344.pdf
        /// I found that paper here:
        /// https://stackoverflow.com/questions/13211595/how-can-i-convert-coordinates-on-a-circle-to-coordinates-on-a-square
        /// This is so we can connect up to the RLD mesh later.
        /// </summary>
        private static Mesh CatenoidSquared(double waist, double height)
        {
            Mesh   mesh    = new Mesh();
            int    res     = m_params.Res * 2;
            double diskRad = waist * Math.Cosh(height / 2 / waist);;

            // NOTE: A band is *not* a constant height slice,
            //		 so the input z value is the height at the edge midpoints of the square.
            Func <double, Vector3D[]> oneCircle = z =>
            {
                bool neg = z < 0;
                z = Math.Abs(z);

                // Radius on disk at a starting edge midpoint.
                double   r     = waist * Math.Cosh(z / waist);
                Vector3D start = new Vector3D(r, 0);
                Vector3D axis  = new Vector3D(0, 0, 1);

                List <Vector3D> points   = new List <Vector3D>();
                double          angleInc = 2 * Math.PI / res;
                double          angle    = 0;
                for (int i = 0; i < res; i++)
                {
                    Vector3D point = start;
                    point.RotateAboutAxis(axis, angle);
                    point = DiskToSquare(point, diskRad);

                    double zi = waist * DonHatch.acosh(point.Abs() / waist);
                    if (double.IsNaN(zi))
                    {
                        zi = 0;
                    }
                    if (neg)
                    {
                        zi *= -1;
                    }
                    Vector3D newPoint = new Vector3D(point.X, point.Y, zi);
                    if (newPoint.DNE)
                    {
                        throw new System.Exception();
                    }
                    points.Add(newPoint);

                    angle += angleInc;
                }

                return(points.ToArray());
            };

            double inc = height / (res * 2);

            for (int i = 0; i < res; i++)
            {
                double z1 = inc * i;
                double z2 = inc * (i + 1);
                mesh.AddBand(oneCircle(z1), oneCircle(z2));
                mesh.AddBand(oneCircle(-z1), oneCircle(-z2));
            }

            return(mesh);
        }
Exemplo n.º 29
0
 private static double EquidistantToPoincare(double dist)
 {
     return(DonHatch.h2eNorm(dist));
 }