Example #1
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));
        }
Example #2
0
        public static void EdgesToStl(H3.Cell.Edge[] edges)
        {
            Shapeways mesh = new Shapeways();

            int divisions = 25;

            foreach (H3.Cell.Edge edge in edges)
            {
                Segment seg = Segment.Line(
                    Sterographic.R3toS3(edge.Start),
                    Sterographic.R3toS3(edge.End));
                Vector3D[] points = seg.Subdivide(divisions);

                ProjectAndAddS3Points(mesh, points);
            }

            for (int i = 0; i < mesh.Mesh.Triangles.Count; i++)
            {
                mesh.Mesh.Triangles[i] = new Mesh.Triangle(
                    SphericalModels.StereoToEqualVolume(mesh.Mesh.Triangles[i].a),
                    SphericalModels.StereoToEqualVolume(mesh.Mesh.Triangles[i].b),
                    SphericalModels.StereoToEqualVolume(mesh.Mesh.Triangles[i].c));
            }

            STL.SaveMeshToSTL(mesh.Mesh, @"output.stl");
        }
Example #3
0
        public static Vector3D SinusoidalToStereo(Vector3D v)
        {
            double   lat       = Math.PI / 2 * (1 - v.Y);
            Vector3D spherical = new Vector3D(1, lat, Math.PI * v.X / Math.Cos(lat - Math.PI / 2));
            Vector3D onBall    = SphericalCoords.SphericalToCartesian(spherical);

            return(Sterographic.SphereToPlane(onBall));
        }
Example #4
0
        /// <summary>
        /// 2-dimensional function.
        /// http://archive.bridgesmathart.org/2013/bridges2013-217.pdf
        /// </summary>
        public static Vector3D MercatorToStereo(Vector3D v)
        {
            v *= Math.PI;               // Input is [-1,1]
            double   lat         = 2 * Math.Atan(Math.Exp(v.Y)) - Math.PI / 2;
            double   inclination = lat + Math.PI / 2;
            Vector3D spherical   = new Vector3D(1, inclination, v.X);
            Vector3D onBall      = SphericalCoords.SphericalToCartesian(spherical);

            return(Sterographic.SphereToPlane(onBall));
        }
Example #5
0
        public static Vector3D EquirectangularToStereo(Vector3D v)
        {
            // http://mathworld.wolfram.com/EquirectangularProjection.html
            // y is the latitude
            // x is the longitude
            // Assume inputs go from -1 to 1.
            Vector3D spherical = new Vector3D(1, Math.PI / 2 * (1 - v.Y), v.X * Math.PI);
            Vector3D onBall    = SphericalCoords.SphericalToCartesian(spherical);

            return(Sterographic.SphereToPlane(onBall));
        }
Example #6
0
        /// <summary>
        /// 2-dimensional function.
        /// ZZZ - Should make this general.
        /// </summary>
        public static Vector3D OrthographicToStereo(Vector3D v)
        {
            // We can only do the projection for half of the sphere.
            double t = v.X * v.X + v.Y * v.Y;

            if (t > 1)
            {
                t = 1;
            }
            v.Z = Math.Sqrt(1 - t);
            return(Sterographic.SphereToPlane(v));
        }
Example #7
0
        private static double EquidistantToStereo(double dist)
        {
            if (dist > 1)
            {
                throw new System.ArgumentException();
            }

            Vector3D v = new Vector3D(0, -1);

            v.RotateXY(dist * Math.PI);
            v = Sterographic.SphereToPlane(new Vector3D(v.X, 0, v.Y));
            return(v.Abs());
        }
Example #8
0
        /// <summary>
        /// https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection
        /// </summary>
        private static double EqualAreaToStereo(double dist)
        {
            if (dist > 1)
            {
                throw new System.ArgumentException();
            }

            // We have dist normalized between 0 and 1, so this formula is slightly
            // different than on Wikipedia, where dist ranges up to 2.
            Vector3D v = new Vector3D(1, 2 * Math.Acos(dist), 0);

            v = Sterographic.SphereToPlane(SphericalCoords.SphericalToCartesian(v));
            return(v.Abs());
        }
Example #9
0
        public static void Hypercube()
        {
            List <Vector3D> vertices = new List <Vector3D>();

            vertices.Add(new Vector3D(1, 1, 1, 1));
            vertices.Add(new Vector3D(1, 1, 1, -1));
            vertices.Add(new Vector3D(1, 1, -1, 1));
            vertices.Add(new Vector3D(1, 1, -1, -1));
            vertices.Add(new Vector3D(1, -1, 1, 1));
            vertices.Add(new Vector3D(1, -1, 1, -1));
            vertices.Add(new Vector3D(1, -1, -1, 1));
            vertices.Add(new Vector3D(1, -1, -1, -1));
            vertices.Add(new Vector3D(-1, 1, 1, 1));
            vertices.Add(new Vector3D(-1, 1, 1, -1));
            vertices.Add(new Vector3D(-1, 1, -1, 1));
            vertices.Add(new Vector3D(-1, 1, -1, -1));
            vertices.Add(new Vector3D(-1, -1, 1, 1));
            vertices.Add(new Vector3D(-1, -1, 1, -1));
            vertices.Add(new Vector3D(-1, -1, -1, 1));
            vertices.Add(new Vector3D(-1, -1, -1, -1));

            HashSet <H3.Cell.Edge> edges = new HashSet <H3.Cell.Edge>(new H3.Cell.EdgeEqualityComparer());

            foreach (Vector3D v1 in vertices)
            {
                foreach (Vector3D v2 in vertices)
                {
                    if (v1.Dist(v2) == 2)
                    {
                        edges.Add(new H3.Cell.Edge(v1, v2));
                    }
                }
            }

            // Radial project to S3, then stereographic to R3.
            foreach (H3.Cell.Edge edge in edges)
            {
                edge.Start.Normalize();
                edge.Start = Sterographic.S3toR3(edge.Start);
                edge.End.Normalize();
                edge.End = Sterographic.S3toR3(edge.End);
            }

            PovRay.WriteEdges(new PovRay.Parameters()
            {
                AngularThickness = .05
            }, Geometry.Spherical, edges.ToArray(), "433.pov", append: false);
        }
Example #10
0
        public static Vector3D StereoToGnomonic(Vector3D p)
        {
            Vector3D sphere = Sterographic.PlaneToSphere(p);

            // We can't only represent the lower hemisphere.
            if (sphere.Z >= 0)
            {
                sphere.Z = 0;
                sphere.Normalize();
                sphere *= Infinity.FiniteScale;
                return(sphere);
            }

            double z = sphere.Z;

            sphere.Z = 0;
            return(-sphere * m_gScale / z);
        }
Example #11
0
        public static void GenPolyhedron()
        {
            Tiling tiling;
            int    p = 3;
            int    q = 6;

            GetAssociatedTiling(p, q, 5000, out tiling);

            double overallScale = 12.5;                 // 2.5 cm = 1 in diameter

            Shapeways mesh = new Shapeways();

            foreach (Tile tile in tiling.Tiles)
            {
                foreach (Segment seg in tile.Boundary.Segments)
                {
                    double tilingScale = 0.75;
                    seg.Scale(new Vector3D(), tilingScale);

                    Vector3D v1 = Sterographic.PlaneToSphereSafe(seg.P1);
                    Vector3D v2 = Sterographic.PlaneToSphereSafe(seg.P2);
                    //if( v1.Dist( v2 ) < 0.01 )
                    //	continue;
                    if (SphericalCoords.CartesianToSpherical(v1).Y < Math.PI / 12 &&
                        SphericalCoords.CartesianToSpherical(v2).Y < Math.PI / 12)
                    {
                        continue;
                    }

                    double dist      = v1.Dist(v2);
                    int    divisions = 2 + (int)(dist * 20);

                    Vector3D[] points = seg.Subdivide(divisions);
                    points = points.Select(v => Sterographic.PlaneToSphereSafe(v)).ToArray();
                    mesh.AddCurve(points, v => SizeFunc(v, overallScale));
                }
            }

            mesh.Mesh.Scale(overallScale);

            string outputFileName = @"d:\temp\" + p + q + ".stl";

            STL.SaveMeshToSTL(mesh.Mesh, outputFileName);
        }
Example #12
0
        // Maps unit disk to Boy's surface.

        public static Vector3D MapToBoys(Vector3D v)
        {
            // https://en.wikipedia.org/wiki/Boy%27s_surface#Parametrization_of_Boy.27s_surface
            Complex w     = v.ToComplex();
            Complex t0    = (Complex.Pow(w, 6) + Complex.Pow(w, 3) * Math.Sqrt(5) - 1);
            Complex t1    = w * (1 - Complex.Pow(w, 4)) / t0;
            Complex t2    = w * (1 + Complex.Pow(w, 4)) / t0;
            Complex t3    = (1 + Complex.Pow(w, 6)) / t0;
            double  g1    = -3 / 2 * t1.Imaginary;
            double  g2    = -3 / 2 * t2.Real;
            double  g3    = t3.Imaginary - 0.5;
            double  denom = g1 * g1 + g2 * g2 + g3 * g3;

            v  = new Vector3D(g1, g2, g3);
            v /= denom;

            // The above is actually a map to R^3, but we want a surface in S^3
            return(Sterographic.R3toS3(v));
        }
Example #13
0
        /// <summary>
        /// Inputs and Outputs are in R3 (stereographically projected).
        /// </summary>
        public static Vector3D[] GeodesicPoints(Vector3D v1, Vector3D v2)
        {
            Vector3D start = Sterographic.R3toS3(v1);
            Vector3D end   = Sterographic.R3toS3(v2);

            AvoidNorthPole(ref start, end);
            AvoidNorthPole(ref end, start);

            int div = 42;
            //int div = 56;		// 343
            //int div = 50;		// 333
            Segment seg = Segment.Line(start, end);

            Vector3D[] result = seg.Subdivide(div);
            for (int i = 0; i < result.Length; i++)
            {
                result[i].Normalize();
                result[i] = Sterographic.S3toR3(result[i]);
            }

            return(result);
        }
Example #14
0
        public static void DrawElements(HyperbolicModel model, Vector3D[] textureCoords, Vector3D[] textureVerts, int[] elements,
                                        Isometry mouseIsometry, double textureScale)
        {
            ////////////////////// ZZZ - Use VBOs
            GL.Begin(BeginMode.Triangles);
            {
                double factor  = textureScale;
                int    skipped = 0;

                for (int i = 0; i < elements.Length; i++)
                {
                    int idx = elements[i];

                    // In Poincare model.
                    GL.TexCoord2((textureCoords[idx].X * factor + 1) / 2, (textureCoords[idx].Y * factor + 1) / 2);
                    Complex transformed = textureVerts[idx].ToComplex();
                    if (mouseIsometry != null)
                    {
                        transformed = mouseIsometry.Apply(transformed);
                    }

                    switch (model)
                    {
                    case HyperbolicModel.Poincare:
                    {
                        Vertex(transformed);
                        break;
                    }

                    case HyperbolicModel.Klein:
                    {
                        Vector3D temp = Vector3D.FromComplex(transformed);
                        Vertex(PoincareToKlein(temp));
                        break;
                    }

                    case HyperbolicModel.Pseudosphere:
                    {
                        Mobius m = new Mobius();
                        m.UpperHalfPlane();
                        Complex u   = m.Apply(transformed);
                        double  x   = u.Real;
                        double  y   = u.Imaginary;
                        double  max = 1 * System.Math.PI;
                        double  min = -1 * System.Math.PI;
                        if (0 == i % 3 && (x < min - 1 || x > max + 1 || y < 0))
                        {
                            skipped = 1;
                            continue;
                        }

                        if (skipped > 0 && skipped < 3)
                        {
                            skipped++;
                            continue;
                        }

                        skipped = 0;

                        GL.TexCoord2((textureCoords[idx].X * factor + 1) / 2, (textureCoords[idx].Y * factor + 1) / 2);

                        // Pseudosphere
                        Func <double, Complex> tractrix = new Func <double, Complex>(
                            (t) =>
                            {
                                return(new Complex(t - Math.Tanh(t), 1.0 / Math.Cosh(t)));
                            });

                        //Vector3D temp1 = Vector3D.FromComplex( u );
                        if (x < min)
                        {
                            x = min;
                        }
                        if (x > max)
                        {
                            x = max;
                        }
                        if (y < 1)
                        {
                            y = 1;
                        }
                        Vector3D temp1 = new Vector3D(x, y);

                        double   logy  = Math.Log(temp1.Y);
                        Complex  tract = tractrix(logy);
                        Vector3D temp2 = new Vector3D(
                            Math.Cos(temp1.X) * tract.Imaginary,
                            Math.Sin(temp1.X) * tract.Imaginary,
                            tract.Real);

                        GL.Vertex3(temp2.X, temp2.Y, temp2.Z);

                        //temp1 = m.Inverse().Apply( temp1 );
                        //GL.Vertex3( temp1.X, temp1.Y, temp1.Z );
                        //Vertex( temp1 );

                        break;
                    }

                    case HyperbolicModel.Hyperboloid:
                    {
                        Vector3D hyper = Sterographic.PlaneToHyperboloid(Vector3D.FromComplex(transformed));                                                    // Hyperboloid
                        GL.Vertex3(hyper.X, hyper.Y, hyper.Z);
                        break;
                    }

                    default:
                    {
                        System.Diagnostics.Debug.Assert(false);
                        break;
                    }
                    }

                    /* // PETALS
                     * int petals = 7;
                     * double newMag = transformed.Magnitude * ( 1 + 0.5 * Math.Sin( transformed.Phase * petals ) );
                     * double newPhase = transformed.Phase + ( -0.2 * newMag * Math.Pow( Math.Sin( newMag * 3 ), 1 ) * Math.Cos( transformed.Phase * petals ) );
                     * transformed = Complex.FromPolarCoordinates( newMag, newPhase );
                     *
                     * Vertex( transformed );
                     * */

                    //double mag = System.Math.Pow( transformed.Magnitude, 3 ) / transformed.Magnitude;				// nice
                    //double mag = System.Math.Pow( transformed.Magnitude - 3, 2 ) + .0;							// looks spherical

                    //double mag = transformed.Magnitude + 0.1* System.Math.Sin( transformed.Magnitude * 15 );		// Fun warping (20 is cool too)
                    //Vertex( transformed * mag );

                    /*double xmag = 1;
                     * double ymag = transformed.Imaginary + 0.1 * System.Math.Sin( transformed.Imaginary * 15 );
                     * xmag = System.Math.Abs( xmag );
                     * ymag = System.Math.Abs( ymag );
                     * Vertex( new Complex( transformed.Real * xmag, transformed.Imaginary * ymag ) );	*/

                    //Vertex( 2 / System.Math.PI * Complex.Log( ( 1 + transformed ) / ( 1 - transformed ) ) );		// Band model
                    //Vertex( Complex.Pow( transformed, 3 ) / transformed.Magnitude );								// Spikey

                    // Spiral
                    //Complex band = 2 / System.Math.PI * Complex.Log( ( 1 + transformed ) / ( 1 - transformed ) );
                    //band = new Complex( band.Real, band.Imaginary + 0.3 * System.Math.Sin( band.Real * 2 ) );
                    //band = new Complex( band.Real * .5, band.Imaginary );
                    //band += new Complex( 0, .5 );
                    //Vertex( band );

                    /*
                     * double x = band.Real;
                     * double y = band.Imaginary;
                     *
                     * double r = System.Math.Exp( x );
                     * double theta = 3*( x + y/1.75 ); */
                    //Vertex( new Complex( r * System.Math.Sin( theta ), r * System.Math.Cos( theta ) ) );			// Spiral
                }
            }
            GL.End();
        }