Inverse() public method

Returns a new Mobius transformation that is the inverse of us.
public Inverse ( ) : Mobius
return Mobius
Esempio n. 1
0
        /// <summary>
        /// Move from a point p1 -> p2 along a geodesic.
        /// Also somewhat from Don.
        /// factor can be used to only go some fraction of the distance from p1 to p2.
        /// </summary>
        public void Geodesic(Geometry g, Complex p1, Complex p2, double factor = 1.0)
        {
            Mobius t = new Mobius();

            t.Isometry(g, 0, p1 * -1);
            Complex p2t = t.Apply(p2);

            // Only implemented for hyperbolic so far.
            if (factor != 1.0 && g == Geometry.Hyperbolic)
            {
                double   newMag = DonHatch.h2eNorm(DonHatch.e2hNorm(p2t.Magnitude) * factor);
                Vector3D temp   = Vector3D.FromComplex(p2t);
                temp.Normalize();
                temp *= newMag;
                p2t   = temp.ToComplex();
            }

            Mobius m1 = new Mobius(), m2 = new Mobius();

            m1.Isometry(g, 0, p1 * -1);
            m2.Isometry(g, 0, p2t);
            Mobius m3 = m1.Inverse();

            this = m3 * m2 * m1;
        }
Esempio n. 2
0
        /// <summary>
        /// This transform will map the z points to the respective w points.
        /// </summary>
        public void MapPoints(Complex z1, Complex z2, Complex z3, Complex w1, Complex w2, Complex w3)
        {
            Mobius m1 = new Mobius(), m2 = new Mobius();

            m1.MapPoints(z1, z2, z3);
            m2.MapPoints(w1, w2, w3);
            this = m2.Inverse() * m1;
        }
Esempio n. 3
0
        /// <summary>
        /// Does a circle inversion in an arbitrary, generalized circle.
        /// IOW, the three points may be collinear, in which case we are talking about a reflection.
        /// </summary>
        private void CacheCircleInversion(Complex c1, Complex c2, Complex c3)
        {
            Mobius toUnitCircle = new Mobius();

            toUnitCircle.MapPoints(
                c1, c2, c3,
                new Complex(1, 0),
                new Complex(-1, 0),
                new Complex(0, 1));

            m_cache1 = toUnitCircle;
            m_cache2 = m_cache1.Inverse();
        }
Esempio n. 4
0
        public void Elliptic(Geometry g, Complex fixedPlus, double angle)
        {
            // To the origin.
            Mobius origin = new Mobius();

            origin.Isometry(g, 0, fixedPlus * -1);

            // Rotate.
            Mobius rotate = new Mobius();

            rotate.Isometry(g, angle, new Complex());

            // Conjugate.
            this = origin.Inverse() * rotate * origin;
        }
Esempio n. 5
0
        /// <summary>
        /// Move from a point p1 -> p2 along a geodesic.
        /// Also somewhat from Don.
        /// </summary>
        public void Geodesic(Geometry g, Complex p1, Complex p2)
        {
            Mobius t = new Mobius();

            t.Isometry(g, 0, p1 * -1);
            Complex p2t = t.Apply(p2);

            Mobius m1 = new Mobius(), m2 = new Mobius();

            m1.Isometry(g, 0, p1 * -1);
            m2.Isometry(g, 0, p2t);
            Mobius m3 = m1.Inverse();

            this = m3 * m2 * m1;
        }
Esempio n. 6
0
 /// <summary>
 /// This transform will map the z points to the respective w points.
 /// </summary>
 public void MapPoints( Complex z1, Complex z2, Complex z3, Complex w1, Complex w2, Complex w3 )
 {
     Mobius m1 = new Mobius(), m2 = new Mobius();
     m1.MapPoints( z1, z2, z3 );
     m2.MapPoints( w1, w2, w3 );
     this =  m2.Inverse() * m1;
 }
Esempio n. 7
0
        /// <summary>
        /// Move from a point p1 -> p2 along a geodesic.
        /// Also somewhat from Don.
        /// </summary>
        public void Geodesic( Geometry g, Complex p1, Complex p2 )
        {
            Mobius t = new Mobius();
            t.Isometry( g, 0, p1 * -1 );
            Complex p2t = t.Apply( p2 );

            Mobius m1 = new Mobius(), m2 = new Mobius();
            m1.Isometry( g, 0, p1 * -1 );
            m2.Isometry( g, 0, p2t );
            Mobius m3 = m1.Inverse();
            this = m3 * m2 * m1;
        }
Esempio n. 8
0
        public void Elliptic( Geometry g, Complex fixedPlus, double angle )
        {
            // To the origin.
            Mobius origin = new Mobius();
            origin.Isometry( g, 0, fixedPlus * -1 );

            // Rotate.
            Mobius rotate = new Mobius();
            rotate.Isometry( g, angle, new Complex() );

            // Conjugate.
            this = origin.Inverse() * rotate * origin;
        }
Esempio n. 9
0
        /// <summary>
        /// Subdivides a segment from p1->p2 with the two endpoints not on the origin, in the respective geometry.
        /// </summary>
        private 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();
        }
Esempio n. 10
0
        /// <summary>
        /// Does a circle inversion in an arbitrary, generalized circle.
        /// IOW, the three points may be collinear, in which case we are talking about a reflection.
        /// </summary>
        private void CacheCircleInversion( Complex c1, Complex c2, Complex c3 )
        {
            Mobius toUnitCircle = new Mobius();
            toUnitCircle.MapPoints(
                c1, c2, c3,
                new Complex( 1, 0 ),
                new Complex( -1, 0 ),
                new Complex( 0, 1 ) );

            m_cache1 = toUnitCircle;
            m_cache2 = m_cache1.Inverse();
        }
Esempio n. 11
0
        /// <summary>
        /// Add an ideal banana to our mesh.  Passed in edge should be in Ball model.
        /// </summary>
        public static void AddIdealBanana( Shapeways mesh, Vector3D e1, Vector3D e2, H3.Settings settings )
        {
            Vector3D z1 = H3Models.BallToUHS( e1 );
            Vector3D z2 = H3Models.BallToUHS( e2 );

            // Mobius taking z1,z2 to origin,inf
            Complex dummy = new Complex( Math.E, Math.PI );
            Mobius m = new Mobius( z1, dummy, z2 );

            // Make our truncated cone.  We need to deal with the two ideal endpoints specially.
            List<Vector3D> points = new List<Vector3D>();
            double logHeight = 2;	// XXX - magic number, and going to cause problems for infinity checks if too big.
            int div1, div2;
            H3Models.Ball.LOD_Ideal( e1, e2, out div1, out div2, settings );
            double increment = logHeight / div1;
            for( int i=-div1; i<=div1; i+=2 )
                points.Add( new Vector3D( 0, 0, Math.Exp( increment * i ) ) );

            Shapeways tempMesh = new Shapeways();
            tempMesh.Div = div2;
            System.Func<Vector3D, double> sizeFunc = v => H3Models.UHS.SizeFunc( v, settings.AngularThickness );
            //Mesh.OpenCylinder...  pass in two ideal endpoints?
            tempMesh.AddCurve( points.ToArray(), sizeFunc, new Vector3D(), Infinity.InfinityVector );

            // Unwind the transforms.
            TakePointsBack( tempMesh.Mesh, m.Inverse(), settings );
            mesh.Mesh.Triangles.AddRange( tempMesh.Mesh.Triangles );
        }
Esempio n. 12
0
            /// <summary>
            /// Calculate the hyperbolic midpoint of an edge.
            /// Only works for non-ideal edges at the moment.
            /// </summary>
            public static Vector3D Midpoint( H3.Cell.Edge edge )
            {
                // Special case if edge has endpoint on origin.
                // XXX - Really this should be special case anytime edge goes through origin.
                Vector3D e1 = edge.Start;
                Vector3D e2 = edge.End;
                if( e1.IsOrigin || e2.IsOrigin )
                {
                    if( e2.IsOrigin )
                        Utils.Swap<Vector3D>( ref e1, ref e2 );

                    return HalfTo( e2 );
                }

                // No doubt there is a much better way, but
                // work in H2 slice transformed to xy plane, with e1 on x-axis.

                double angle = e1.AngleTo( e2 );	// always <= 180
                e1 = new Vector3D( e1.Abs(), 0 );
                e2 = new Vector3D( e2.Abs(), 0 );
                e2.RotateXY( angle );

                // Mobius that will move e1 to origin.
                Mobius m = new Mobius();
                m.Isometry( Geometry.Hyperbolic, 0, -e1 );
                e2 = m.Apply( e2 );

                Vector3D midOnPlane = HalfTo( e2 );
                midOnPlane= m.Inverse().Apply( midOnPlane );
                double midAngle = e1.AngleTo( midOnPlane );

                Vector3D mid = edge.Start;
                mid.RotateAboutAxis( edge.Start.Cross( edge.End ), midAngle );
                mid.Normalize( midOnPlane.Abs() );
                return mid;
            }
Esempio n. 13
0
        private Vector3D ApplyTransformationToSphere( Vector3D v, double t )
        {
            v = H3Models.BallToUHS( v );

            // 437 (hyperbolic)
            //v *= Math.Pow( 4.259171776329806, t*10-5 );

            // 36i (parabolic)
            //v += new Vector3D( Math.Cos( Math.PI / 6 ), Math.Sin( Math.PI / 6 ) ) * t;

            // iii (loxodromic)
            //Complex c = v.ToComplex();
            //double x = Math.Sqrt( 2 ) - 1;
            //Mobius m = new Mobius( new Complex( x, 0 ), Complex.One, new Complex( -x, 0 ) );

            // 12,12,12 loxodromic
            //m = new Mobius( new Complex( 0, 1 ), Complex.One, new Complex( 0, -1 ) );

            /*
            c = m.Apply( c );
            c *= Complex.Exp( new Complex( 2.5, 4 * Math.PI ) * t );
            c = m.Inverse().Apply( c );
            v = Vector3D.FromComplex( c );
            */

            // Center cell head in KolorEyes.
            Mobius m = new Mobius();
            m.UpperHalfPlane();
            v = m.Inverse().Apply( v );

            return H3Models.UHSToBall( v );
        }
Esempio n. 14
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 )
                return SimplexCalcs.MirrorsSpherical( p, q, r );
            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.
            Sphere[] result = surfaces.Select( s => moveToBall ? H3Models.UHSToBall( s ) : s ).ToArray();
            cellCenter = moveToBall ? H3Models.UHSToBall( cellCenter ) : cellCenter;

            return result;
        }