Пример #1
0
        /// <summary>
        /// Same as above, but works with all geometries.
        /// </summary>
        public static Circle EquidistantOffset(Geometry g, Segment seg, double offset)
        {
            Mobius   m = new Mobius();
            Vector3D direction;

            if (seg.Type == SegmentType.Line)
            {
                direction = seg.P2 - seg.P1;
                direction.RotateXY(Math.PI / 2);
            }
            else
            {
                direction = seg.Circle.Center;
            }

            direction.Normalize();
            m.Isometry(g, 0, direction * offset);

            // Transform 3 points on segment.
            Vector3D p1 = m.Apply(seg.P1);
            Vector3D p2 = m.Apply(seg.Midpoint);
            Vector3D p3 = m.Apply(seg.P2);

            return(new Circle(p1, p2, p3));
        }
Пример #2
0
        private static Vector3D DiskToUpper(Vector3D input)
        {
            Mobius m = new Mobius();

            m.UpperHalfPlane();
            return(m.Apply(input));
        }
Пример #3
0
        /// <summary>
        /// Subdivides a segment from p1->p2 with the two endpoints not on the origin, in the respective geometry.
        /// </summary>
        public static Vector3D[] SubdivideSegmentInGeometry(Vector3D p1, Vector3D p2, int divisions, Geometry g)
        {
            // Handle this specially, so we can keep things 3D if needed.
            if (g == Geometry.Euclidean)
            {
                Segment seg = Segment.Line(p1, p2);
                return(seg.Subdivide(divisions));
            }

            Mobius p1ToOrigin = new Mobius();

            p1ToOrigin.Isometry(g, 0, -p1);
            Mobius inverse = p1ToOrigin.Inverse();

            Vector3D newP2  = p1ToOrigin.Apply(p2);
            Segment  radial = Segment.Line(new Vector3D(), newP2);

            Vector3D[] temp = SubdivideRadialInGeometry(radial, divisions, g);

            List <Vector3D> result = new List <Vector3D>();

            foreach (Vector3D v in temp)
            {
                result.Add(inverse.Apply(v));
            }

            return(result.ToArray());
        }
Пример #4
0
        public int Closest(Vector3D p)
        {
            // Needs to be non-euclidean calc,
            // Moving the hex to the center will make that be the case.
            Mobius  m    = MobiusToCenter;
            Polygon poly = Hexagon.Clone();

            poly.Transform(m);
            p = m.Apply(p);

            double d1  = poly.Segments[1].Midpoint.Dist(p);
            double d2  = poly.Segments[3].Midpoint.Dist(p);
            double d3  = poly.Segments[5].Midpoint.Dist(p);
            double min = Math.Min(d1, Math.Min(d2, d3));

            if (min == d1)
            {
                return(4);
            }
            if (min == d2)
            {
                return(0);
            }
            if (min == d3)
            {
                return(2);
            }
            return(-1);
        }
Пример #5
0
        public static Vector3D LoxodromicToIsometric(Vector3D v, int p, int m, int n)
        {
            Mobius mob = Mobius.CreateFromIsometry(Geometry.Spherical, 0, new System.Numerics.Complex(1, 0));

            v = mob.Apply(v);
            return(SpiralToIsometric(v, p, m, n));
        }
Пример #6
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();
        }
Пример #7
0
 /// <summary>
 /// Apply a Mobius transform to us.
 /// </summary>
 public void Transform(Mobius m)
 {
     foreach (Segment s in this.Segments)
     {
         s.Transform(m);
     }
     Center = m.Apply(Center);
 }
Пример #8
0
        public static void Test()
        {
            S3.HopfOrbit();

            Mobius m = new Mobius();

            m.UpperHalfPlane();

            Vector3D test = m.Apply(new Vector3D());

            test *= 1;
        }
Пример #9
0
        public Vector3D TinyOffset(int awayFromSeg)
        {
            // Center;
            Mobius   m    = MobiusToCenter;
            Vector3D p    = Hexagon.Center;
            Polygon  poly = Hexagon.Clone();

            poly.Transform(m);
            p = m.Apply(p);

            // Do the offset.
            p -= poly.Segments[awayFromSeg].Midpoint / 10;

            // Go back.
            p = m.Inverse().Apply(p);
            return(p);
        }
Пример #10
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();
        }
Пример #11
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);
        }
Пример #12
0
        private static void AddSymmetryTriangles(Mesh mesh, Tiling tiling, Polygon boundary)
        {
            // Assume template centered at the origin.
            Polygon         template     = tiling.Tiles.First().Boundary;
            List <Triangle> templateTris = new List <Triangle>();

            foreach (Segment seg in template.Segments)
            {
                int num = 1 + (int)(seg.Length * m_divisions);

                Vector3D a        = new Vector3D();
                Vector3D b        = seg.P1;
                Vector3D c        = seg.Midpoint;
                Vector3D centroid = (a + b + c) / 3;

                Polygon poly = new Polygon();
                Segment segA = Segment.Line(new Vector3D(), seg.P1);
                Segment segB = seg.Clone();
                segB.P2 = seg.Midpoint;
                Segment segC = Segment.Line(seg.Midpoint, new Vector3D());
                poly.Segments.Add(segA);
                poly.Segments.Add(segB);
                poly.Segments.Add(segC);

                Vector3D[] coords   = TextureHelper.TextureCoords(poly, Geometry.Hyperbolic);
                int[]      elements = TextureHelper.TextureElements(3, LOD: 3);
                for (int i = 0; i < elements.Length / 3; i++)
                {
                    int      idx1 = i * 3;
                    int      idx2 = i * 3 + 1;
                    int      idx3 = i * 3 + 2;
                    Vector3D v1   = coords[elements[idx1]];
                    Vector3D v2   = coords[elements[idx2]];
                    Vector3D v3   = coords[elements[idx3]];
                    templateTris.Add(new Triangle(v1, v2, v3));
                }

                /*
                 *
                 * // Need to shrink a little, so we won't
                 * // get intersections among neighboring faces.
                 * a = Shrink( a, centroid );
                 * b = Shrink( b, centroid );
                 * c = Shrink( c, centroid );
                 *
                 * Vector3D[] list = seg.Subdivide( num * 2 );
                 * list[0] = b;
                 * list[list.Length / 2] = c;
                 * for( int i = 0; i < list.Length / 2; i++ )
                 *      templateTris.Add( new Triangle( centroid, list[i], list[i + 1] ) );
                 *
                 * for( int i = num - 1; i >= 0; i-- )
                 *      templateTris.Add( new Triangle( centroid, a + (c - a) * (i + 1) / num, a + (c - a) * i / num ) );
                 *
                 * for( int i = 0; i < num; i++ )
                 *      templateTris.Add( new Triangle( centroid, a + (b - a) * i / num, a + (b - a) * (i + 1) / num ) );
                 */
            }

            foreach (Tile tile in tiling.Tiles)
            {
                Vector3D a = tile.Boundary.Segments[0].P1;
                Vector3D b = tile.Boundary.Segments[1].P1;
                Vector3D c = tile.Boundary.Segments[2].P1;

                Mobius m = new Mobius();
                if (tile.Isometry.Reflected)
                {
                    m.MapPoints(template.Segments[0].P1, template.Segments[1].P1, template.Segments[2].P1, c, b, a);
                }
                else
                {
                    m.MapPoints(template.Segments[0].P1, template.Segments[1].P1, template.Segments[2].P1, a, b, c);
                }

                foreach (Triangle tri in templateTris)
                {
                    Triangle transformed = new Triangle(
                        m.Apply(tri.a),
                        m.Apply(tri.b),
                        m.Apply(tri.c));
                    CheckAndAdd(mesh, transformed, boundary);
                }
            }
        }
Пример #13
0
        public void SetupHexagonForKQ()
        {
            Polygon centralTile = new Polygon();

            centralTile.CreateRegular(7, 3);
            Vector3D vertex0 = centralTile.Segments[0].P1;

            CircleNE[] otherThreeSides = OtherThreeSides();
            CircleNE[] systoles        = SystolesForKQ();

            // Calc verts.
            List <Vector3D> verts = new List <Vector3D>();
            Vector3D        t1, t2;

            Euclidean2D.IntersectionCircleCircle(otherThreeSides[0], systoles[0], out t1, out t2);
            Vector3D intersection = t1.Abs() < 1 ? t1 : t2;

            verts.Add(intersection);
            intersection.Y *= -1;
            verts.Add(intersection);
            Mobius m = RotMobius(vertex0);

            verts.Add(m.Apply(verts[0]));
            verts.Add(m.Apply(verts[1]));
            verts.Add(m.Apply(verts[2]));
            verts.Add(m.Apply(verts[3]));

            // Setup all the segments.
            bool clockwise = true;

            Hexagon.Segments.AddRange(new Segment[]
            {
                Segment.Arc(verts[0], verts[1], otherThreeSides[0].Center, clockwise),
                Segment.Arc(verts[1], verts[2], systoles[1].Center, clockwise),
                Segment.Arc(verts[2], verts[3], otherThreeSides[1].Center, clockwise),
                Segment.Arc(verts[3], verts[4], systoles[2].Center, clockwise),
                Segment.Arc(verts[4], verts[5], otherThreeSides[2].Center, clockwise),
                Segment.Arc(verts[5], verts[0], systoles[0].Center, clockwise),
            });
            Hexagon.Center = vertex0;

            // Setup the test circle.
            m.Isometry(Geometry.Hyperbolic, 0, -vertex0);
            Polygon clone = Hexagon.Clone();

            clone.Transform(m);

            Circle temp = new Circle(
                clone.Segments[0].Midpoint,
                clone.Segments[2].Midpoint,
                clone.Segments[4].Midpoint);
            CircleNE tempNE = new CircleNE(temp, new Vector3D());

            tempNE.Transform(m.Inverse());
            TestCircle = tempNE;

            temp = new Circle(
                clone.Segments[0].P1,
                clone.Segments[1].P1,
                clone.Segments[2].P1);
            tempNE = new CircleNE(temp, new Vector3D());
            tempNE.Transform(m.Inverse());
            CircumCircle = tempNE;
        }
Пример #14
0
        /// <summary>
        /// Using this to move the view around in interesting ways.
        /// </summary>
        private Vector3D ApplyTransformation(Vector3D v, double t = 0.0)
        {
            //v.RotateXY( Math.PI / 4 + 0.01 );
            bool applyNone = true;

            if (applyNone)
            {
                return(v);
            }

            Mobius m0 = new Mobius(), m1 = new Mobius(), m2 = new Mobius(), m3 = new Mobius();
            Sphere unitSphere = new Sphere();

            v.Y -= .8;
            v   *= 7;
            m0.UpperHalfPlane();
            v = m0.Apply(v);

            return(v);

            // self-similar scale for 437
            //v*= 4.259171776329806;

            double s = 6.5;

            v *= s;
            v += new Vector3D(s / 3, -s / 3);
            v  = unitSphere.ReflectPoint(v);
            v.RotateXY(Math.PI / 6);
            //v /= 3;
            //v.RotateXY( Math.PI );
            //v.RotateXY( Math.PI/2 );
            return(v);

            //v.Y = v.Y / Math.Cos( Math.PI / 6 );	// 637 repeatable
            //return v;

            // 12,12,12
            m0.Isometry(Geometry.Hyperbolic, 0, new Complex(.0, .0));
            m1 = Mobius.Identity();
            m2 = Mobius.Identity();
            m3 = Mobius.Identity();
            v  = (m0 * m1 * m2 * m3).Apply(v);
            return(v);

            // i64
            m0.Isometry(Geometry.Hyperbolic, 0, new Complex(.5, .5));
            m1.UpperHalfPlane();
            m2 = Mobius.Scale(1.333333);
            m3.Isometry(Geometry.Euclidean, 0, new Vector3D(0, -1.1));
            v = (m1 * m2 * m3).Apply(v);
            return(v);

            // 464
            // NOTE: Also, don't apply rotations during simplex generation.
            m1.UpperHalfPlane();
            m2 = Mobius.Scale(1.3);
            m3.Isometry(Geometry.Euclidean, 0, new Vector3D(1.55, -1.1));
            v = (m1 * m2 * m3).Apply(v);
            return(v);

            // iii
            m1.Isometry(Geometry.Hyperbolic, 0, new Complex(0, Math.Sqrt(2) - 1));
            m2.Isometry(Geometry.Euclidean, -Math.PI / 4, 0);
            m3 = Mobius.Scale(5);
            //v = ( m1 * m2 * m3 ).Apply( v );

            // Vertical Line

            /*v = unitSphere.ReflectPoint( v );
             * m1.MapPoints( new Vector3D(-1,0), new Vector3D(), new Vector3D( 1, 0 ) );
             * m2 = Mobius.Scale( .5 );
             * v = (m1*m2).Apply( v ); */

            /*
             * m1 = Mobius.Scale( 0.175 );
             * v = unitSphere.ReflectPoint( v );
             * v = m1.Apply( v );
             * */

            // Inversion
            //v = unitSphere.ReflectPoint( v );
            //return v;

            /*Mobius m1 = new Mobius(), m2 = new Mobius(), m3 = new Mobius();
             * m1.Isometry( Geometry.Spherical, 0, new Complex( 0, 1 ) );
             * m2.Isometry( Geometry.Euclidean, 0, new Complex( 0, -1 ) );
             * m3 = Mobius.Scale( 0.5 );
             * v = (m1 * m3 * m2).Apply( v );*/

            //Mobius m = new Mobius();
            //m.Isometry( Geometry.Hyperbolic, 0, new Complex( -0.88, 0 ) );
            //m.Isometry( Geometry.Hyperbolic, 0, new Complex( 0, Math.Sqrt(2) - 1 ) );
            //m = Mobius.Scale( 0.17 );
            //m.Isometry( Geometry.Spherical, 0, new Complex( 0, 3.0 ) );
            //v = m.Apply( v );

            // 63i, 73i
            m1 = Mobius.Scale(6.0);                                                    // Scale {3,i} to unit disk.
            m1 = Mobius.Scale(1.0 / 0.14062592996431983);                              // 73i	(constant is abs of midpoint of {3,7} tiling, if we want to calc later for other tilings).
            m2.MapPoints(Infinity.InfinityVector, new Vector3D(1, 0), new Vector3D()); // swap interior/exterior
            m3.UpperHalfPlane();
            v *= 2.9;

            // iii

            /*m1.MapPoints( new Vector3D(), new Vector3D(1,0), new Vector3D( Math.Sqrt( 2 ) - 1, 0 ) );
             * m2.Isometry( Geometry.Euclidean, -Math.PI / 4, 0 );
             * m3 = Mobius.Scale( 0.75 );*/

            Mobius m = m3 * m2 * m1;

            v = m.Inverse().Apply(v);                   // Strange that we have to do inverse here.

            return(v);
        }
Пример #15
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");
        }
Пример #16
0
 public override void Transform(Mobius m)
 {
     base.Transform(m);
     CenterNE = m.Apply(CenterNE);
 }