Isometry() public method

This will calculate the Mobius transform that represents an isometry in the given geometry. The isometry will rotate CCW by angle A about the origin, then translate the origin to P (and -P to the origin).
public Isometry ( Geometry g, double angle, System.Numerics.Complex P ) : void
g Geometry
angle double
P System.Numerics.Complex
return void
示例#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;
        }
示例#2
0
        /// <summary>
        /// Allow a hyperbolic transformation using an absolute offset.
        /// offset is specified in the respective geometry.
        /// </summary>
        public void Hyperbolic2(Geometry g, Complex fixedPlus, Complex point, double offset)
        {
            // To the origin.
            Mobius m = new Mobius();

            m.Isometry(g, 0, fixedPlus * -1);
            double eRadius = m.Apply(point).Magnitude;

            double scale = 1;

            switch (g)
            {
            case Geometry.Spherical:
                double sRadius = Spherical2D.e2sNorm(eRadius);
                sRadius += offset;
                scale    = Spherical2D.s2eNorm(sRadius) / eRadius;
                break;

            case Geometry.Euclidean:
                scale = (eRadius + offset) / eRadius;
                break;

            case Geometry.Hyperbolic:
                double hRadius = DonHatch.e2hNorm(eRadius);
                hRadius += offset;
                scale    = DonHatch.h2eNorm(hRadius) / eRadius;
                break;
            }

            Hyperbolic(g, fixedPlus, scale);
        }
示例#3
0
        public static Mobius CreateFromIsometry(Geometry g, double angle, Complex P)
        {
            Mobius m = new Mobius();

            m.Isometry(g, angle, P);
            return(m);
        }
示例#4
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;
        }
示例#5
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;
        }
示例#6
0
        public void Hyperbolic(Geometry g, Complex fixedPlus, double scale)
        {
            // To the origin.
            Mobius m1 = new Mobius();

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

            // Scale.
            Mobius m2 = new Mobius();

            m2.A = scale;
            m2.B = m2.C = 0;
            m2.D = 1;

            // Back.
            //Mobius m3 = m1.Inverse();	// Doesn't work well if fixedPlus is on disk boundary.
            Mobius m3 = new Mobius();

            m3.Isometry(g, 0, fixedPlus);

            // Compose them (multiply in reverse order).
            this = m3 * m2 * m1;
        }
示例#7
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;
        }
示例#8
0
 /// <summary>
 /// A Mobius that will put our simplex into a face centered orientation.
 /// Meant to be used with H3Models.TransformInBall2 or H3Models.TransformHelper
 /// </summary>
 private static Mobius FCOrientMobius( Sphere cellSphereInBall )
 {
     Mobius m = new Mobius();
     double d = cellSphereInBall.Center.Abs() - cellSphereInBall.Radius;
     m.Isometry( Geometry.Hyperbolic, 0, new Vector3D( 0, d ) );
     return m;
 }
示例#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();
        }
示例#10
0
        private static void HyperidealSquares()
        {
            Mobius rot = new Mobius();
            rot.Isometry( Geometry.Spherical, Math.PI / 4, new Vector3D() );

            List<Segment> segs = new List<Segment>();
            int[] qs = new int[] { 5, -1 };
            foreach( int q in qs )
            {
                TilingConfig config = new TilingConfig( 4, q, 1 );
                Tile t = Tiling.CreateBaseTile( config );
                List<Segment> polySegs = t.Boundary.Segments;
                polySegs = polySegs.Select( s => { s.Transform( rot ); return s; } ).ToList();
                segs.AddRange( polySegs );
            }

            Vector3D v1 = new Vector3D(1,0);
            v1.RotateXY( Math.PI/6 );
            Vector3D v2 = v1;
            v2.Y *= -1;
            Vector3D cen;
            double rad;
            H3Models.Ball.OrthogonalCircle( v1, v2, out cen, out rad );
            Segment seg = Segment.Arc( v1, v2, cen, false );
            rot.Isometry( Geometry.Spherical, Math.PI / 2, new Vector3D() );
            for( int i = 0; i < 4; i++ )
            {
                seg.Transform( rot );
                segs.Add( seg.Clone() );
            }

            SVG.WriteSegments( "output1.svg", segs );

            System.Func<Segment, Segment> PoincareToKlein = s =>
            {
                return Segment.Line(
                    HyperbolicModels.PoincareToKlein( s.P1 ),
                    HyperbolicModels.PoincareToKlein( s.P2 ) );
            };
            segs = segs.Select( s => PoincareToKlein( s ) ).ToList();

            Vector3D v0 = new Vector3D( v1.X, v1.X );
            Vector3D v3 = v0;
            v3.Y *= -1;
            Segment seg1 = Segment.Line( v0, v1 ), seg2 = Segment.Line( v2, v3 );
            Segment seg3 = Segment.Line( new Vector3D( 1, 1 ), new Vector3D( 1, -1 ) );
            for( int i = 0; i < 4; i++ )
            {
                seg1.Transform( rot );
                seg2.Transform( rot );
                seg3.Transform( rot );
                segs.Add( seg1.Clone() );
                segs.Add( seg2.Clone() );
                segs.Add( seg3.Clone() );
            }

            SVG.WriteSegments( "output2.svg", segs );
        }
示例#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 )
                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;
        }
示例#12
0
 public static Mobius VertexCenteredMobius( int p, int q )
 {
     double angle = Math.PI / q;
     if( Utils.Even( q ) )
         angle *= 2;
     Vector3D offset = new Vector3D( -1 * Geometry2D.GetNormalizedCircumRadius( p, q ), 0, 0 );
     offset.RotateXY( angle );
     Mobius m = new Mobius();
     m.Isometry( Geometry2D.GetGeometry( p, q ), angle, offset.ToComplex() );
     return m;
 }
示例#13
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;
            }
示例#14
0
        /// <summary>
        /// Allow a hyperbolic transformation using an absolute offset.
        /// offset is specified in the respective geometry.
        /// </summary>
        public void Hyperbolic2( Geometry g, Complex fixedPlus, Complex point, double offset )
        {
            // To the origin.
            Mobius m = new Mobius();
            m.Isometry( g, 0, fixedPlus * -1 );
            double eRadius = m.Apply( point ).Magnitude;

            double scale = 1;
            switch( g )
            {
                case Geometry.Spherical:
                    double sRadius = Spherical2D.e2sNorm( eRadius );
                    sRadius += offset;
                    scale = Spherical2D.s2eNorm( sRadius ) / eRadius;
                    break;
                case Geometry.Euclidean:
                    scale = (eRadius + offset) / eRadius;
                    break;
                case Geometry.Hyperbolic:
                    double hRadius = DonHatch.e2hNorm( eRadius );
                    hRadius += offset;
                    scale = DonHatch.h2eNorm( hRadius ) / eRadius;
                    break;
            }

            Hyperbolic( g, fixedPlus, scale );
        }
示例#15
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();

            // 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;
        }
示例#16
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;
        }
示例#17
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 );
        }
示例#18
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;
        }
示例#19
0
        public Vector3D Transform( Vector3D v )
        {
            v.RotateAboutAxis( new Vector3D( 1, 0 ), Math.PI / 2 );

            Mobius m = new Mobius();
            m.Isometry( Geometry.Hyperbolic, 0, new Complex( 0, 0.6 ) );
            v = H3Models.TransformHelper( v, m );

            v.RotateAboutAxis( new Vector3D( 1, 0 ), -Math.PI / 2 );
            return v;
        }
示例#20
0
        public void Hyperbolic( Geometry g, Complex fixedPlus, double scale )
        {
            // To the origin.
            Mobius m1 = new Mobius();
            m1.Isometry( g, 0, fixedPlus * -1 );

            // Scale.
            Mobius m2 = new Mobius();
            m2.A = scale;
            m2.B = m2.C = 0;
            m2.D = 1;

            // Back.
            //Mobius m3 = m1.Inverse();	// Doesn't work well if fixedPlus is on disk boundary.
            Mobius m3 = new Mobius();
            m3.Isometry( g, 0, fixedPlus );

            // Compose them (multiply in reverse order).
            this = m3 * m2 * m1;
        }
示例#21
0
        /// <summary>
        /// This Mobius transform will center the tiling on an edge.
        /// </summary>
        public Mobius EdgeMobius()
        {
            Geometry g = Geometry2D.GetGeometry( this.P, this.Q );

            Polygon poly = new Polygon();
            poly.CreateRegular( this.P, this.Q );
            Segment seg = poly.Segments[0];
            Vector3D offset = seg.Midpoint;

            double angle = Math.PI / this.P;
            offset.RotateXY( -angle );

            Mobius m = new Mobius();
            m.Isometry( g, -angle, -offset );
            return m;
        }
示例#22
0
 public static Mobius CreateFromIsometry( Geometry g, double angle, Complex P )
 {
     Mobius m = new Mobius();
     m.Isometry( g, angle, P );
     return m;
 }
示例#23
0
        public static Mobius FCOrientMobius( int p, int q )
        {
            Vector3D p1, p2, p3;
            Segment seg = null;
            TilePoints( p, q, out p1, out p2, out p3, out seg );
            Geometry cellGeometry = Geometry2D.GetGeometry( p, q );

            p1.RotateXY( Math.PI / 2 );	// XXX - repeated from above.  Implement a better way to sequence transformations.

            Mobius m = new Mobius();
            m.Isometry( cellGeometry, 0, -p1 );
            return m;
        }