Exemple #1
0
 /// <summary>
 /// A correct implementation of shrink tile.
 /// hmmmm, is "scaling" even well defined in non-E geometries? Am I really looking for an equidistant curve?
 /// Sadly, even if I figure out what is best, I fear changing out usage of the incorrect one below in MagicTile,
 /// because of the possibility of breaking existing puzzles.
 /// </summary>
 internal static void ShrinkTileCorrect( ref Tile tile, double shrinkFactor )
 {
     System.Func<Vector3D,double,Vector3D> scaleFunc = null;
     switch( tile.Geometry )
     {
         case Geometry.Euclidean:
         {
             scaleFunc = ( v, s ) => v * s;
             break;
         }
         case Geometry.Spherical:
         {
             scaleFunc = ( v, s ) =>
                 {
                     // Move to spherical norm, scale, then move back to euclidean.
                     double scale = Spherical2D.s2eNorm( ( Spherical2D.e2sNorm( v.Abs() ) * s ) );
                     v.Normalize();
                     return v * scale;
                 };
             break;
         }
         case Geometry.Hyperbolic:
         {
             throw new System.NotImplementedException();
         }
     }
 }
Exemple #2
0
 public Tile Clone()
 {
     Tile newTile = new Tile();
     newTile.Boundary = Boundary.Clone();
     newTile.Drawn = Drawn.Clone();
     newTile.VertexCircle = VertexCircle.Clone();
     newTile.Geometry = Geometry;
     return newTile;
 }
Exemple #3
0
        /// <summary>
        /// This will trim back the tile using an equidistant curve.
        /// It assumes the tile is at the origin.
        /// </summary>
        internal static void ShrinkTile( ref Tile tile, double shrinkFactor )
        {
            // This code is not correct in non-Euclidean cases!
            // But it works reasonable well for small shrink factors.
            // For example, you can easily use this function to grow a hyperbolic tile beyond the disk.
            Mobius m = new Mobius();
            m.Hyperbolic( tile.Geometry, new Vector3D(), shrinkFactor );
            tile.Drawn.Transform( m );
            return;

            /*
            // ZZZ
            // Wow, all the work I did below was subsumed by 4 code lines above!
            // I can't bring myself to delete it yet.

            switch( tile.Geometry )
            {
                case Geometry.Spherical:
                {
                    List<Tile> clipped = new List<Tile>();
                    clipped.Add( tile );

                    Polygon original = tile.Drawn.Clone();
                    foreach( Segment seg in original.Segments )
                    {
                        Debug.Assert( seg.Type == SegmentType.Arc );

                        if( true )
                        {
                            // Unproject to sphere.
                            Vector3D p1 = Spherical2D.PlaneToSphere( seg.P1 );
                            Vector3D p2 = Spherical2D.PlaneToSphere( seg.P2 );

                            // Get the poles of the GC, and project them to the plane.
                            Vector3D pole1, pole2;
                            Spherical2D.GreatCirclePole( p1, p2, out pole1, out pole2 );
                            pole1 = Spherical2D.SphereToPlane( pole1 );
                            pole2 = Spherical2D.SphereToPlane( pole2 );

                            // Go hyperbolic, dude.
                            double scale = 1.065;	// ZZZ - needs to be configurable.
                            Complex fixedPlus = pole1;
                            Mobius hyperbolic = new Mobius();
                            hyperbolic.Hyperbolic( tile.Geometry, fixedPlus, scale );
                            Vector3D newP1 = hyperbolic.Apply( seg.P1 );
                            Vector3D newMid = hyperbolic.Apply( seg.Midpoint );
                            Vector3D newP2 = hyperbolic.Apply( seg.P2 );

                            Circle trimmingCircle = new Circle();
                            trimmingCircle.From3Points( newP1, newMid, newP2 );

                            Slicer.Clip( ref clipped, trimmingCircle, true );
                        }
                        else
                        {
                            // I think this block has logic flaws, but strangely it seems to work,
                            // so I'm leaving it in commented out for posterity.

                            Vector3D p1 = seg.P1;
                            Vector3D mid = seg.Midpoint;
                            Vector3D p2 = seg.P2;

                            //double offset = .1;
                            double factor = .9;
                            double f1 = Spherical2D.s2eNorm( (Spherical2D.e2sNorm( p1.Abs() ) * factor) );
                            double f2 = Spherical2D.s2eNorm( (Spherical2D.e2sNorm( mid.Abs() ) * factor) );
                            double f3 = Spherical2D.s2eNorm( (Spherical2D.e2sNorm( p2.Abs() ) * factor) );
                            p1.Normalize();
                            mid.Normalize();
                            p2.Normalize();
                            p1 *= f1;
                            mid *= f2;
                            p2 *= f3;

                            Circle trimmingCircle = new Circle();
                            trimmingCircle.From3Points( p1, mid, p2 );

                            Slicer.Clip( ref clipped, trimmingCircle, true );
                        }
                    }

                    Debug.Assert( clipped.Count == 1 );
                    tile = clipped[0];
                    return;
                }
                case Geometry.Euclidean:
                {
                    double scale = .95;

                    Mobius hyperbolic = new Mobius();
                    hyperbolic.Hyperbolic( tile.Geometry, new Vector3D(), scale );

                    tile.Drawn.Transform( hyperbolic );

                    return;
                }
                case Geometry.Hyperbolic:
                {
                    List<Tile> clipped = new List<Tile>();
                    clipped.Add( tile );

                    Circle infinity = new Circle();
                    infinity.Radius = 1.0;

                    Polygon original = tile.Drawn.Clone();
                    foreach( Segment seg in original.Segments )
                    {
                        Debug.Assert( seg.Type == SegmentType.Arc );
                        Circle segCircle = seg.GetCircle();

                        // Get the intersection points with the disk at infinity.
                        Vector3D p1, p2;
                        int count = Euclidean2D.IntersectionCircleCircle( infinity, segCircle, out p1, out p2 );
                        Debug.Assert( count == 2 );

                        Vector3D mid = seg.Midpoint;
                        //mid *= 0.75;	// ZZZ - needs to be configurable.

                        double offset = .03;
                        double f1 = DonHatch.h2eNorm( DonHatch.e2hNorm( mid.Abs() ) - offset );
                        mid.Normalize();
                        mid *= f1;

                        Circle trimmingCircle = new Circle();
                        trimmingCircle.From3Points( p1, mid, p2 );

                        Slicer.Clip( ref clipped, trimmingCircle, false );
                    }

                    Debug.Assert( clipped.Count == 1 );
                    tile = clipped[0];
                    return;
                }
            }
            */
        }
Exemple #4
0
 public void CalculateFromTwoPolygons( Tile home, Polygon boundaryPolygon, Geometry g )
 {
     CalculateFromTwoPolygonsInternal( home.Boundary, boundaryPolygon, home.VertexCircle, g );
 }
Exemple #5
0
        private static void MeshEdges( Mesh mesh, Tile tile, HashSet<Vector3D> completed, Polygon boundary )
        {
            for( int i=0; i<tile.Boundary.Segments.Count; i++ )
            {
                Segment boundarySeg = tile.Boundary.Segments[i];
                Segment d1 = tile.Drawn.Segments[i];
                if( completed.Contains( boundarySeg.Midpoint ) )
                    continue;

                // Find the incident segment.
                Segment seg2 = null, d2 = null;
                foreach( Tile incident in tile.EdgeIncidences )
                {
                    for( int j=0; j<incident.Boundary.Segments.Count; j++ )
                    {
                        if( boundarySeg.Midpoint == incident.Boundary.Segments[j].Midpoint )
                        {
                            seg2 = incident.Boundary.Segments[j];
                            d2 = incident.Drawn.Segments[j];
                            break;
                        }
                    }

                    if( seg2 != null )
                        break;
                }

                // Found our incident edge?
                bool foundIncident = seg2 != null;
                if( !foundIncident )
                    seg2 = d2 = boundarySeg;

                // Do the endpoints mismatch?
                if( boundarySeg.P1 != seg2.P1 )
                {
                    Segment clone = d2.Clone();
                    clone.Reverse();
                    d2 = clone;
                }

                // Add the two vertices (careful of orientation).
                if( foundIncident )
                {
                    CheckAndAdd( mesh, new Mesh.Triangle( boundarySeg.P1, d1.P1, d2.P1 ), boundary );
                    CheckAndAdd( mesh, new Mesh.Triangle( boundarySeg.P2, d2.P2, d1.P2 ), boundary );
                }

                int num = 1 + (int)(d1.Length * m_divisions);
                Vector3D[] list1 = d1.Subdivide( num );
                Vector3D[] list2 = d2.Subdivide( num );
                for( int j=0; j<num; j++ )
                {
                    CheckAndAdd( mesh, new Mesh.Triangle( list1[j], list1[j + 1], list2[j + 1] ), boundary );
                    CheckAndAdd( mesh, new Mesh.Triangle( list2[j], list1[j], list2[j + 1] ), boundary );
                }

                completed.Add( boundarySeg.Midpoint );
            }
        }
Exemple #6
0
        /// <summary>
        /// Will clone the tile, transform it and add it to our tiling.
        /// </summary>
        private bool TransformAndAdd( Tile tile )
        {
            // Will we want to include it?
            if( !tile.IncludeAfterMobius( this.TilingConfig.M ) )
                return false;

            Tile clone = tile.Clone();
            clone.Transform( this.TilingConfig.M );
            m_tiles.Add( clone );
            this.TilePositions[clone.Boundary.Center] = clone;
            return true;
        }
Exemple #7
0
 /// <summary>
 /// Calculates an isometry by taking a tile boundary polygon to a home.
 /// </summary>
 public void CalculateFromTwoPolygons( Tile home, Tile tile, Geometry g )
 {
     Polygon poly = tile.Boundary;
     CalculateFromTwoPolygons( home, poly, g );
 }
Exemple #8
0
 /// <summary>
 /// This will fill out all the tiles with the isometry that will take them back to a home tile.
 /// </summary>
 private static void FillOutIsometries( Tile home, List<Tile> tiles, Geometry g )
 {
     foreach( Tile tile in tiles )
         tile.Isometry.CalculateFromTwoPolygons( home, tile, g );
 }
Exemple #9
0
        /// <summary>
        /// This will return whether we'll be a new tile after reflecting through a segment.
        /// This allows us to do the check without having to do all the work of reflecting the entire tile.
        /// </summary>
        public bool NewTileAfterReflect( Tile t, Segment s, Dictionary<Vector3D, bool> completed )
        {
            /* This was too slow!
            Polygon newPolyBoundary = t.Boundary.Clone();
            newPolyBoundary.Reflect( s );
            Vector3D testCenter = this.TilingConfig.M.Apply( newPolyBoundary.Center );*/

            CircleNE newVertexCircle = t.VertexCircle.Clone();
            newVertexCircle.Reflect( s );
            Vector3D testCenter = this.TilingConfig.M.Apply( newVertexCircle.CenterNE );

            return !completed.ContainsKey( testCenter );
        }
Exemple #10
0
        public static Tile CreateBaseTile( TilingConfig config )
        {
            Polygon boundary = new Polygon(), drawn = new Polygon();
            boundary.CreateRegular( config.P, config.Q );
            drawn = boundary.Clone();

            //boundary.CreateRegular( 3, 10 );
            //drawn.CreateRegular( 3, 8 );
            //boundary.CreateRegular( 3, 7 );
            //drawn = Heart();

            //for( int i=0; i<drawn.NumSides; i++ )
            //	drawn.Segments[i].Center *= 0.1;

            // Good combos:
            // ( 5, 5 ), ( 10, 10 )
            // ( 3, 10 ), ( 3, 9 )
            // ( 6, 4 ), ( 6, 8 )
            // ( 7, 3 ), ( 7, 9 )

            Tile tile = new Tile( boundary, drawn, config.Geometry );
            Tile.ShrinkTile( ref tile, config.Shrink );
            return tile;
        }
Exemple #11
0
        private static void GetAssociatedTiling( EHoneycomb honeycomb, out Tiling tiling, out Tile baseTile )
        {
            int p, q;
            GetPQ( honeycomb, out p, out q );
            TilingConfig tilingConfig = new TilingConfig( p, q, maxTiles: m_params.MaxTiles );
            tiling = new Tiling();
            tiling.Generate( tilingConfig );

            baseTile = Tiling.CreateBaseTile( tilingConfig );
        }
Exemple #12
0
 private static double EdgeCenteredScale( Tile baseTile )
 {
     Segment seg = baseTile.Boundary.Segments[0];
     return 1.0 / ( seg.Length / 2 );
 }