Ejemplo n.º 1
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);
        }
Ejemplo n.º 2
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 );*/
        }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
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();
        }
Ejemplo n.º 5
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");
        }
Ejemplo n.º 6
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);
        }