示例#1
0
        /// <summary>
        /// Thickens each mesh edge in the plane of the mesh surface.
        /// </summary>
        /// <param name="offset">Distance to offset edges in plane of adjacent faces</param>
        /// <param name="boundaries">If true, attempt to ribbon boundary edges</param>
        /// <returns>The ribbon mesh</returns>
        public Mesh Ribbon(float offset, Boolean boundaries, float smooth)
        {
            Mesh ribbon     = Duplicate();
            var  orig_faces = ribbon.Faces.ToArray();

            List <List <Halfedge> > incidentEdges = ribbon.Vertices.Select(v => v.Halfedges).ToList();

            // create new "vertex" faces
            List <List <Vertex> > all_new_vertices = new List <List <Vertex> >();

            for (int k = 0; k < Vertices.Count; k++)
            {
                Vertex          v            = ribbon.Vertices[k];
                List <Vertex>   new_vertices = new List <Vertex>();
                List <Halfedge> halfedges    = incidentEdges[k];
                Boolean         boundary     = halfedges[0].Next.Pair != halfedges[halfedges.Count - 1];

                // if the edge loop around this vertex is open, close it with 'temporary edges'
                if (boundaries && boundary)
                {
                    Halfedge a, b;
                    a = halfedges[0].Next;
                    b = halfedges[halfedges.Count - 1];
                    if (a.Pair == null)
                    {
                        a.Pair = new Halfedge(a.Prev.Vertex)
                        {
                            Pair = a
                        };
                    }
                    if (b.Pair == null)
                    {
                        b.Pair = new Halfedge(b.Prev.Vertex)
                        {
                            Pair = b
                        };
                    }
                    a.Pair.Next = b.Pair;
                    b.Pair.Prev = a.Pair;
                    a.Pair.Prev = a.Pair.Prev ?? a; // temporary - to allow access to a.Pair's start/end vertices
                    halfedges.Add(a.Pair);
                }

                foreach (Halfedge edge in halfedges)
                {
                    if (halfedges.Count < 2)
                    {
                        continue;
                    }

                    Vector3f normal = edge.Face != null ? edge.Face.Normal : Vertices[k].Normal;
                    Halfedge edge2  = edge.Next;

                    Vector3f o1 = Vector3f.CrossProduct(normal, edge.Vector);
                    Vector3f o2 = Vector3f.CrossProduct(normal, edge2.Vector);
                    o1.Unitize();
                    o2.Unitize();
                    o1 *= offset;
                    o2 *= offset;

                    if (edge.Face == null)
                    {
                        // boundary condition: create two new vertices in the plane defined by the vertex normal
                        Vertex v1 = new Vertex(v.Position + (edge.Vector * (1 / edge.Vector.Length) * -offset) + o1);
                        Vertex v2 = new Vertex(v.Position + (edge2.Vector * (1 / edge2.Vector.Length) * offset) + o2);
                        ribbon.Vertices.Add(v2);
                        ribbon.Vertices.Add(v1);
                        new_vertices.Add(v2);
                        new_vertices.Add(v1);
                        Halfedge c = new Halfedge(v2, edge2, edge, null);
                        edge.Next  = c;
                        edge2.Prev = c;
                    }
                    else
                    {
                        // internal condition: offset each edge in the plane of the shared face and create a new vertex where they intersect eachother
                        Line l1 = new Line(edge.Vertex.Position + o1, edge.Prev.Vertex.Position + o1);
                        Line l2 = new Line(edge2.Vertex.Position + o2, edge2.Prev.Vertex.Position + o2);

                        double a, b;
                        Rhino.Geometry.Intersect.Intersection.LineLine(l1, l2, out a, out b);
                        Point3d new_point  = l1.PointAt(a);
                        Vertex  new_vertex = new Vertex(new Point3f((float)new_point.X, (float)new_point.Y, (float)new_point.Z));
                        ribbon.Vertices.Add(new_vertex);
                        new_vertices.Add(new_vertex);
                    }
                }

                if ((!boundaries && boundary) == false) // only draw boundary node-faces in 'boundaries' mode
                {
                    ribbon.Faces.Add(new_vertices);
                }
                all_new_vertices.Add(new_vertices);
            }

            // change edges to reference new vertices
            for (int k = 0; k < Vertices.Count; k++)
            {
                Vertex v = ribbon.Vertices[k];
                if (all_new_vertices[k].Count < 1)
                {
                    continue;
                }
                int c = 0;
                foreach (Halfedge edge in incidentEdges[k])
                {
                    if (!ribbon.Halfedges.SetVertex(edge, all_new_vertices[k][c++]))
                    {
                        edge.Vertex = all_new_vertices[k][c];
                    }
                }
                //v.Halfedge = null; // unlink from halfedge as no longer in use (culled later)
                // note: new vertices don't link to any halfedges in the mesh until later
            }

            // cull old vertices
            ribbon.Vertices.RemoveRange(0, Vertices.Count);

            // use existing edges to create 'ribbon' faces
            MeshHalfedgeList temp = new MeshHalfedgeList();

            for (int i = 0; i < Halfedges.Count; i++)
            {
                temp.Add(ribbon.Halfedges[i]);
            }
            List <Halfedge> items = temp.GetUnique();

            foreach (Halfedge halfedge in items)
            {
                if (halfedge.Pair != null)
                {
                    // insert extra vertices close to the new 'vertex' vertices to preserve shape when subdividing
                    if (smooth > 0.0)
                    {
                        if (smooth > 0.5)
                        {
                            smooth = 0.5f;
                        }
                        Vertex[] new_vertices = new Vertex[] {
                            new Vertex(halfedge.Vertex.Position + (-smooth * halfedge.Vector)),
                            new Vertex(halfedge.Prev.Vertex.Position + (smooth * halfedge.Vector)),
                            new Vertex(halfedge.Pair.Vertex.Position + (-smooth * halfedge.Pair.Vector)),
                            new Vertex(halfedge.Pair.Prev.Vertex.Position + (smooth * halfedge.Pair.Vector))
                        };
                        ribbon.Vertices.AddRange(new_vertices);
                        Vertex[] new_vertices1 = new Vertex[] {
                            halfedge.Vertex,
                            new_vertices[0],
                            new_vertices[3],
                            halfedge.Pair.Prev.Vertex
                        };
                        Vertex[] new_vertices2 = new Vertex[] {
                            new_vertices[1],
                            halfedge.Prev.Vertex,
                            halfedge.Pair.Vertex,
                            new_vertices[2]
                        };
                        ribbon.Faces.Add(new_vertices);
                        ribbon.Faces.Add(new_vertices1);
                        ribbon.Faces.Add(new_vertices2);
                    }
                    else
                    {
                        Vertex[] new_vertices = new Vertex[] {
                            halfedge.Vertex,
                            halfedge.Prev.Vertex,
                            halfedge.Pair.Vertex,
                            halfedge.Pair.Prev.Vertex
                        };

                        ribbon.Faces.Add(new_vertices);
                    }
                }
            }

            // remove original faces, leaving just the ribbon
            //var orig_faces = Enumerable.Range(0, Faces.Count).Select(i => ribbon.Faces[i]);
            foreach (Face item in orig_faces)
            {
                ribbon.Faces.Remove(item);
            }

            // search and link pairs
            ribbon.Halfedges.MatchPairs();

            return(ribbon);
        }
示例#2
0
 public Mesh()
 {
     Halfedges = new MeshHalfedgeList(this);
     Vertices  = new MeshVertexList(this);
     Faces     = new MeshFaceList(this);
 }