Example #1
0
        /// <summary>
        /// Make an edge mesh of a regular tiling.
        /// </summary>
        public static Mesh MakeEdgeMesh( int p, int q )
        {
            Mesh mesh = new Mesh();

            int maxTiles = 400;

            Tiling tiling = new Tiling();
            TilingConfig config = new TilingConfig( p, q, maxTiles: maxTiles );
            config.Shrink = 0.6;
            tiling.GenerateInternal( config );

            TilingConfig boundaryConfig = new TilingConfig( 14, 7, maxTiles: 1 );
            boundaryConfig.Shrink = 1.01;
            Tile boundary = Tiling.CreateBaseTile( boundaryConfig );

            AddSymmetryTriangles( mesh, tiling, boundary.Drawn );
            //AddSymmetryTriangles( mesh, tiling, null );
            return mesh;

            HashSet<Vector3D> completed = new HashSet<Vector3D>();
            int count = 0;
            foreach( Tile tile in tiling.Tiles )
            {
                MeshEdges( mesh, tile, completed, null );
                count++;
                if( count >= maxTiles )
                    break;
            }

            return mesh;
        }
Example #2
0
        /// <summary>
        /// Transform a mesh in the Poincare model to Dini's surface.
        /// </summary>
        public static Mesh Dini( Mesh mesh )
        {
            System.Func<Vector3D,Vector3D> transform = v =>
            {
                //v = DiskToUpper( v );
                //v.Y = Math.Log( v.Y );

                //if( v.Y < 1 || v.Y > 10 )
                //	return Infinity.InfinityVector;
                //if( v.X < -Math.PI || v.X > Math.PI )
                //if( v.X < -3*Math.PI || v.X > 3*Math.PI )
                //	return Infinity.InfinityVector;

                //v.Y = Math.Log( v.Y );
                //return v;
                return Dini( v );
            };

            Mesh result = new Mesh();
            for( int i=0; i<mesh.Triangles.Count; i++ )
            {
                Vector3D a = transform( mesh.Triangles[i].a );
                Vector3D b = transform( mesh.Triangles[i].b );
                Vector3D c = transform( mesh.Triangles[i].c );
                if( Infinity.IsInfinite( a ) ||
                    Infinity.IsInfinite( b ) ||
                    Infinity.IsInfinite( c ) )
                    continue;

                result.Triangles.Add( new Mesh.Triangle( a, b, c ) );
            }

            return result;
        }
Example #3
0
 public static void DrawTriangle( Mesh.Triangle triangle, Graphics g, ImageSpace i )
 {
     using( Pen pen = new Pen( Color.Black, 1.0f ) )
     {
         g.DrawLine( pen, VecToPoint( triangle.a, i ), VecToPoint( triangle.b, i ) );
         g.DrawLine( pen, VecToPoint( triangle.b, i ), VecToPoint( triangle.c, i ) );
         g.DrawLine( pen, VecToPoint( triangle.c, i ), VecToPoint( triangle.a, i ) );
     }
 }
Example #4
0
        private static void WriteMesh( StreamWriter sw, Mesh mesh, string fileName, bool append = false )
        {
            Vector3D[] verts, normals;
            List<int[]> faces;
            mesh.BuildIndexes( out verts, out normals, out faces );

            // http://www.povray.org/documentation/view/3.6.0/68/
            // http://www.povray.org/documentation/view/3.6.1/293/
            // We are going to use mesh2 so that we can have per-vertex coloring.
            sw.WriteLine( "mesh2 {" );

            // Vertices
            sw.WriteLine( "  vertex_vectors {" );
            sw.WriteLine( "    " + verts.Length + "," );
            foreach( Vector3D v in verts )
                sw.WriteLine( "    " + FormatVec( v ) + "," );
            sw.WriteLine( "  }" );

            // Normals for smooth triangles
            sw.WriteLine( "  normal_vectors {" );
            sw.WriteLine( "    " + verts.Length + "," );
            foreach( Vector3D v in normals )
            {
                v.Normalize();
                sw.WriteLine( "    " + FormatVec( v ) + "," );
            }
            sw.WriteLine( "  }" );

            // Triangles
            sw.WriteLine( "  face_indices {" );
            sw.WriteLine( "    " + faces.Count + "," );
            foreach( int[] face in faces )
                sw.WriteLine( string.Format( "    <{0},{1},{2}>,", face[0], face[1], face[2] ) );
            sw.WriteLine( "  }" );

            sw.WriteLine( "texture {tex2}" );
            sw.WriteLine( "}" );
        }
Example #5
0
 public static void WriteMesh( Mesh mesh, string fileName, bool append = false )
 {
     if( append )
     {
         using( StreamWriter sw = File.AppendText( fileName ) )
             WriteMesh( sw, mesh, fileName, append );
     }
     else
     {
         using( StreamWriter sw = File.CreateText( fileName ) )
             WriteMesh( sw, mesh, fileName, append );
     }
 }
Example #6
0
        private static H3.Cell[] GenTruss( Sphere[] simplex, Mesh mesh, Vector3D cen, bool ball )
        {
            // We don't want to include the first mirror (which reflects across cells).
            Sphere[] mirrors = simplex.Skip( 1 ).ToArray();
            Sphere[] allMirrors = simplex.ToArray();

            // Simplices will be the "cells" in Recurse.CalcCells.
            H3.Cell.Facet[] simplexFacets = simplex.Select( m => new H3.Cell.Facet( m ) ).ToArray();

            H3.Cell startingCell = new H3.Cell( simplexFacets );
            startingCell.Center = cen;

            //FCOrient( startingCell );
            //return null;

            startingCell = startingCell.Clone();	// So our mirrors don't get munged after we reflect around later.
            H3.Cell[] simplices = Recurse.CalcCells( mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball } );
            //H3.Cell[] simplices = new H3.Cell[] { startingCell };

            // Subsets
            //return simplices.Where( s => s.Depths[0] == 1 ).ToArray();
            //return simplices.ToArray();

            List<H3.Cell> final = new List<H3.Cell>();
            final.AddRange( simplices );

            // Add in other truss cells.
            Recurse.Settings settings = new Recurse.Settings();
            foreach( int[] reflections in TrussReflections() )
            foreach( H3.Cell c in simplices )
            {
                H3.Cell clone = c.Clone();
                foreach( int r in reflections )
                    clone.Reflect( allMirrors[r] );
                if( Recurse.CellOk( clone, settings ) )
                    final.Add( clone );
            }

            return final.ToArray();
        }
Example #7
0
 public Shapeways()
 {
     Mesh = new Mesh();
     Div = 24;
 }
Example #8
0
 private static void CheckAndAdd( Mesh mesh, Triangle tri, Polygon boundary )
 {
     if( Check( tri, boundary ) )
         mesh.Triangles.Add( tri );
 }
Example #9
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 );
            }
        }
Example #10
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 );
                }
            }
        }
Example #11
0
 public Mesh Clone()
 {
     Mesh clone = new Mesh();
     clone.Triangles = Triangles.Select( t => t ).ToList();
     return clone;
 }
Example #12
0
        internal static void TakePointsBack( Mesh mesh, Mobius m, H3.Settings settings )
        {
            for( int i=0; i<mesh.Triangles.Count; i++ )
            {
                mesh.Triangles[i] = new Mesh.Triangle(
                    m.ApplyToQuaternion( mesh.Triangles[i].a ),
                    m.ApplyToQuaternion( mesh.Triangles[i].b ),
                    m.ApplyToQuaternion( mesh.Triangles[i].c ) );

                /*if( Infinity.IsInfinite( mesh.Triangles[i].a ) ||
                    Infinity.IsInfinite( mesh.Triangles[i].b ) ||
                    Infinity.IsInfinite( mesh.Triangles[i].c ) )
                    System.Diagnostics.Debugger.Break();*/
            }

            // Take all points back to Ball, if needed.
            if( !settings.Halfspace )
            {
                for( int i=0; i<mesh.Triangles.Count; i++ )
                {
                    mesh.Triangles[i] = new Mesh.Triangle(
                        H3Models.UHSToBall( mesh.Triangles[i].a ),
                        H3Models.UHSToBall( mesh.Triangles[i].b ),
                        H3Models.UHSToBall( mesh.Triangles[i].c ) );
                }
            }
        }
Example #13
0
        /// <summary>
        /// Used to generate a regular cell as a set of simplices and save to a Pov-ray file.
        /// This will work for non-finite cells.
        /// </summary>
        private static H3.Cell[] GenCell( Sphere[] simplex, Mesh mesh, Vector3D cen, bool ball, bool dual )
        {
            // We don't want to include the first mirror (which reflects across cells).
            Sphere[] mirrors = simplex.Skip( 1 ).ToArray();
            if( dual )
                mirrors = new Sphere[] { simplex[0], simplex[1], simplex[2] };
            Sphere[] allMirrors = simplex.ToArray();
            mirrors = simplex.ToArray();

            // Simplices will be the "cells" in Recurse.CalcCells.
            H3.Cell.Facet[] simplexFacets = simplex.Select( m => new H3.Cell.Facet( m ) ).ToArray();

            H3.Cell startingCell = new H3.Cell( simplexFacets );
            startingCell.Center = cen;
            startingCell.Mesh = mesh;

            //FCOrient( startingCell );

            startingCell = startingCell.Clone();	// So our mirrors don't get munged after we reflect around later.
            H3.Cell[] simplices = Recurse.CalcCells( mirrors, new H3.Cell[] { startingCell }, new Recurse.Settings() { Ball = ball } );
            //H3.Cell[] simplices = new H3.Cell[] { startingCell };

            // Layers.
            int layer = 0;
            return simplices.Where( s => s.Depths[0] <= layer /*&& s.Depths[0] == 3 && s.Depths[1] == 3*/ ).ToArray();
            //return simplices.ToArray();
        }
Example #14
0
        /// <summary>
        /// Create an STL file for a cell.
        /// This will be a 2D surface of triangles, which will need to be thickened using an external program.
        /// Currently only works for cells with both hyperideal vertices and cells.
        /// </summary>
        private static void CreateCellSTL( HoneycombDef imageData )
        {
            int p = imageData.P;
            int q = imageData.Q;
            int r = imageData.R;

            bool ball = false;
            Sphere[] simplex = SimplexCalcs.Mirrors( p, q, r, moveToBall: ball );
            H3.Cell.Edge[] edges;
            if( ball )
                edges = SimplexCalcs.SimplexEdgesBall( p, q, r );
            else
                edges = SimplexCalcs.SimplexEdgesUHS( p, q, r );

            // Two edges of one simplex facet.
            int div = 5;
            H3.Cell.Edge e1 = edges[2];
            H3.Cell.Edge e2 = edges[3];
            Vector3D[] points1, points2;
            if( ball )
            {
                points1 = H3Models.Ball.GeodesicPoints( e1.Start, e1.End, 2 * div );
                points2 = H3Models.Ball.GeodesicPoints( e2.Start, e2.End, 2 * div );
            }
            else
            {
                points1 = H3Models.UHS.GeodesicPoints( e1.Start, e1.End, 2 * div );
                points2 = H3Models.UHS.GeodesicPoints( e2.Start, e2.End, 2 * div );
            }

            Sphere cellSphere = simplex[0];

            // Because one vertex the facet triangle is hyperideal, it will actually look like a square.
            List<Vector3D[]> allPoints = new List<Vector3D[]>();
            for( int i = 0; i < points1.Length; i++ )
            {
                Vector3D p1 = points1[i];
                Vector3D p2 = points2[i];

                // NOTE: This arc is not generally geodesic!
                Vector3D[] arcPoints;
                if( i == points1.Length - 1 )
                {
                    arcPoints = ball ?
                        H3Models.Ball.GeodesicPoints( p1, p2, div ) :
                        H3Models.UHS.GeodesicPoints( p1, p2, div );
                }
                else
                {
                    Circle3D c = Circle3D.FromCenterAnd2Points( cellSphere.Center, p1, p2 );
                    double angleTot = (p1 - c.Center).AngleTo( p2 - c.Center );
                    arcPoints = Shapeways.CalcArcPoints( cellSphere.Center, cellSphere.Radius, p1, c.Normal, -angleTot, div );
                }
                //Vector3D[] arcPoints = new Vector3D[] { p1, p2 };
                allPoints.Add( arcPoints );
            }

            // Create the triangles for the patch.
            Mesh mesh = new Mesh();
            for( int i = 0; i < allPoints.Count - 1; i++ )
            {
                Vector3D[] arc1 = allPoints[i];
                Vector3D[] arc2 = allPoints[i + 1];

                for( int j = 0; j < arc1.Length - 1; j++ )
                {
                    // Points of (i,j) box;
                    Vector3D p1 = arc1[j];
                    Vector3D p2 = arc2[j];
                    Vector3D p3 = arc1[j + 1];
                    Vector3D p4 = arc2[j + 1];

                    mesh.Triangles.Add( new Mesh.Triangle( p1, p2, p3 ) );
                    mesh.Triangles.Add( new Mesh.Triangle( p2, p4, p3 ) );
                }
            }

            // Face centered orientation.
            // XXX - We need to do this prior to mesh generation, so the mesh isn't stretched out by these transformations.
            bool faceCentered = true;

            Vector3D cen = CellCenBall;
            if( faceCentered )
                SimplexCalcs.PrepForFacetCentering( p, q, simplex, ref cen );

            Mobius mUHS = SimplexCalcs.FCOrientMobius( p, q );
            Mobius mBall = FCOrientMobius( H3Models.UHSToBall( cellSphere ) );

            simplex = simplex.Select( s =>
            {
                s = H3Models.UHSToBall( s );
                H3Models.TransformInBall2( s, mBall );
                return s;
            } ).ToArray();

            {
                for( int i = 0; i < mesh.Triangles.Count; i++ )
                {
                    Mesh.Triangle tri = mesh.Triangles[i];

                    if( faceCentered )
                    {
                        tri.a = mUHS.ApplyToQuaternion( tri.a );
                        tri.b = mUHS.ApplyToQuaternion( tri.b );
                        tri.c = mUHS.ApplyToQuaternion( tri.c );
                    }

                    tri.a = H3Models.UHSToBall( tri.a );
                    tri.b = H3Models.UHSToBall( tri.b );
                    tri.c = H3Models.UHSToBall( tri.c );

                    if( faceCentered )
                    {
                        tri.a = H3Models.TransformHelper( tri.a, mBall );
                        tri.b = H3Models.TransformHelper( tri.b, mBall );
                        tri.c = H3Models.TransformHelper( tri.c, mBall );
                    }
                    mesh.Triangles[i] = tri;
                }

                if( faceCentered )
                    cen = H3Models.TransformHelper( cen, mBall );
            }

            // Now we need to reflect around this fundamental patch.
            bool dual = false;
            H3.Cell[] simplicesFinal = GenCell( simplex, mesh, cen, ball, dual );

            System.IO.File.Delete( "cell.stl" );
            foreach( H3.Cell cell in simplicesFinal )
                STL.AppendMeshToSTL( cell.Mesh, "cell.stl" );
            //STL.AppendMeshToSTL( simplicesFinal[0].Mesh, "cell.stl" );
        }