//face area public static double ComputeAreaFaceTwo(TriMesh.Face face) { Vector3D v1 = new Vector3D(face.GetVertex(0).Traits.Position.x, face.GetVertex(0).Traits.Position.y, face.GetVertex(0).Traits.Position.z); Vector3D v2 = new Vector3D(face.GetVertex(1).Traits.Position.x, face.GetVertex(1).Traits.Position.y, face.GetVertex(1).Traits.Position.z); Vector3D v3 = new Vector3D(face.GetVertex(2).Traits.Position.x, face.GetVertex(2).Traits.Position.y, face.GetVertex(2).Traits.Position.z); double a = Math.Sqrt((v1.x - v2.x) * (v1.x - v2.x) + (v1.y - v2.y) * (v1.y - v2.y) + (v1.z - v2.z) * (v1.z - v2.z)); double b = Math.Sqrt((v3.x - v2.x) * (v3.x - v2.x) + (v3.y - v2.y) * (v3.y - v2.y) + (v3.z - v2.z) * (v3.z - v2.z)); double c = Math.Sqrt((v1.x - v3.x) * (v1.x - v3.x) + (v1.y - v3.y) * (v1.y - v3.y) + (v1.z - v3.z) * (v1.z - v3.z)); double p = (a + b + c) / 2; double area = Math.Sqrt(p * (p - a) * (p - b) * (p - c)); return(area); }
public static void KMean(TriMesh mesh) { Dictionary <int, Cluster> dict = new Dictionary <int, Cluster>(); Queue <TriMesh.Face> queue = new Queue <HalfEdgeMesh.Face>(); foreach (var face in mesh.Faces) { if (face.Traits.SelectedFlag != 0) { dict[face.Traits.SelectedFlag] = new Cluster(); dict[face.Traits.SelectedFlag].Add(TriMeshUtil.GetMidPoint(face)); queue.Enqueue(face); } } while (queue.Count != 0) { TriMesh.Face center = queue.Dequeue(); foreach (var round in center.Faces) { if (round.Traits.SelectedFlag == 0) { int index = GetNearest(round, dict); dict[index].Add(TriMeshUtil.GetMidPoint(round)); round.Traits.SelectedFlag = (byte)index; queue.Enqueue(round); } } } }
protected Vector3D Transport(Vector3D wI, TriMesh.Face faceI, TriMesh.Face faceJ, double angle) { /* * triangles i and j according to the following labels: * * b * /|\ * / | \ * / | \ * / | \ * c i | j d \ | / \ | / \ | / \|/ \ a \ */ //Find Shared edge IJ TriMesh.HalfEdge sharedEdgeI = null; TriMesh.HalfEdge sharedEdgeJ = null; TriMesh.Edge sharedEdge = null; foreach (TriMesh.HalfEdge edgeI in faceI.Halfedges) { foreach (TriMesh.HalfEdge edgeJ in faceJ.Halfedges) { if (edgeI.Opposite == edgeJ) { sharedEdge = edgeI.Edge; sharedEdgeI = edgeI; sharedEdgeJ = edgeJ; break; } } } if (sharedEdge == null) { throw new Exception("Error"); } //Find vertex correspondent to figure above Vector3D av = sharedEdgeI.FromVertex.Traits.Position; Vector3D bv = sharedEdgeJ.FromVertex.Traits.Position; Vector3D cv = sharedEdgeI.Next.ToVertex.Traits.Position; Vector3D dv = sharedEdgeJ.Next.ToVertex.Traits.Position; //Compute the basis Matrix3D Ei = Orthogonalize(bv - av, cv - av); Matrix3D Ej = Orthogonalize(bv - av, bv - dv); //Build Rotate Matrix between two Faces Matrix3D rotateMatrix = Matrix3D.Rotate(angle); Vector3D wj = (Ej * rotateMatrix * Ei.Inverse() * wI); return(wj); }
public static TriMesh Combine(List <TriMesh> meshes) { TriMesh combine = new TriMesh(); foreach (TriMesh mesh in meshes) { if (mesh != null) { TriMesh.Vertex[] arr = new TriMesh.Vertex[mesh.Vertices.Count]; foreach (TriMesh.Vertex v in mesh.Vertices) { arr[v.Index] = combine.Vertices.Add(new VertexTraits(v.Traits.Position)); arr[v.Index].Traits = v.Traits; } foreach (TriMesh.Face face in mesh.Faces) { TriMesh.Face faceNew = combine.Faces.Add(arr[face.GetVertex(0).Index], arr[face.GetVertex(1).Index], arr[face.GetVertex(2).Index]); faceNew.Traits = face.Traits; } } } return(combine); }
public TriMesh AddSelectionFace(TriMesh mesh, int index) { TriMesh result = new TriMesh(); List <TriMesh.Vertex> arr = new List <HalfEdgeMesh.Vertex>(); int vIndex = 0; List <TriMesh> sel = new List <TriMesh>(); for (int i = 0; i < mesh.Faces.Count; i++) { if (mesh.Faces[i].Traits.SelectedFlag == index) { foreach (TriMesh.Vertex v in mesh.Faces[i].Vertices) { arr.Add(result.Vertices.Add(new VertexTraits(v.Traits.Position))); arr[arr.Count - 1].Traits = v.Traits; } TriMesh.Face faceNew = result.Faces.Add(arr[vIndex * 3 + 0], arr[vIndex * 3 + 1], arr[vIndex * 3 + 2]); faceNew.Traits = mesh.Faces[i].Traits; vIndex++; } } result.FileName = Path.GetFileNameWithoutExtension(mesh.FileName) + "-F-" + index.ToString(); TriMeshUtil.SetUpVertexNormal(result, EnumNormal.AreaWeight); return(result); }
public static List <TriMesh> SeperateComponent(TriMesh mesh) { List <TriMesh> meshes = new List <TriMesh>(); Dictionary <int, TriMesh.Vertex> map = new Dictionary <int, HalfEdgeMesh.Vertex>(); bool[] visited = new bool[mesh.Faces.Count]; Queue <TriMesh.Face> queue = new Queue <HalfEdgeMesh.Face>(); TriMesh newMesh = new TriMesh(); queue.Enqueue(mesh.Faces[0]); visited[0] = true; while (queue.Count != 0) { TriMesh.Face face = queue.Dequeue(); foreach (var hf in face.Halfedges) { if (!map.ContainsKey(hf.ToVertex.Index)) { TriMesh.Vertex v = new HalfEdgeMesh.Vertex(new VertexTraits(hf.ToVertex.Traits.Position)); newMesh.AppendToVertexList(v); map[hf.ToVertex.Index] = v; } if (hf.Opposite.Face != null && !visited[hf.Opposite.Face.Index]) { queue.Enqueue(hf.Opposite.Face); visited[hf.Opposite.Face.Index] = true; } } newMesh.Faces.AddTriangles( map[face.HalfEdge.FromVertex.Index], map[face.HalfEdge.ToVertex.Index], map[face.HalfEdge.Next.ToVertex.Index]); if (queue.Count == 0) { meshes.Add(newMesh); for (int i = 0; i < visited.Length; i++) { if (!visited[i]) { newMesh = new TriMesh(); queue.Enqueue(mesh.Faces[i]); visited[i] = true; break; } } } } foreach (TriMesh child in meshes) { TriMeshUtil.SetUpNormalVertex(child); } return(meshes); }
public void DrawTrivialConnection(TriMesh mesh, Vector3D[] faceVectors, int N) { double eps = 1e-3; double perAngle = 2 * Math.PI / N; for (int i = 0; i < mesh.Faces.Count; i++) { Vector3D vector = Vector3D.Normalize(faceVectors[i]); TriMesh.Face face = mesh.Faces[i]; Vector3D center = TriMeshUtil.GetMidPoint(face); Vector3D normal = TriMeshUtil.ComputeNormalFace(face); double inradius = TriMeshUtil.ComputeInradius(face); Quaternion rotate = Quaternion.RotationAxis(normal, perAngle); Quaternion v = new Quaternion(vector, 0); for (int j = 0; j < N; j++) { Vector3D a = center + inradius * v.ImagePart; //Vector3D b = center - inradius * v.ImagePart; v = rotate * v * rotate.Conjugate(); GL.Begin(BeginMode.Lines); GL.Vertex3(a.x, a.y, a.z); GL.Vertex3(center.x, center.y, center.z); GL.End(); } } }
void UpdateAreaAndNormal(TriMesh.Face face) { Vector3D cross = this.Cross(face); this.FaceArea[face.Index] = cross.Length() / 2d; this.FaceNormal[face.Index] = cross.Normalize(); }
public static void GrowByFaceAngle(TriMesh mesh) { Queue <TriMesh.Face> queue = new Queue <HalfEdgeMesh.Face>(); Vector3D[] normal = TriMeshUtil.ComputeNormalFace(mesh); foreach (var face in mesh.Faces) { if (face.Traits.SelectedFlag != 0) { queue.Enqueue(face); } } double k = 0.449; while (queue.Count != 0) { TriMesh.Face center = queue.Dequeue(); foreach (var round in center.Faces) { if (round.Traits.SelectedFlag == 0) { if (normal[center.Index].Dot(normal[round.Index]) > k) { round.Traits.SelectedFlag = center.Traits.SelectedFlag; queue.Enqueue(round); } } } } }
public Vector3D ComputeFaceNormals(TriMesh.Face f) { Vector3D p0 = f.GetVertex(0).Traits.Position; Vector3D p1 = f.GetVertex(1).Traits.Position; Vector3D p2 = f.GetVertex(2).Traits.Position; return((p1 - p0).Cross(p2 - p0).Normalize()); }
public static void ShowOneRingFaceOfFace(TriMesh.Face face) { foreach (var item in face.Vertices) { ShowOneRingFaceOfVertex(item); } face.Traits.Color = Color4.Black; }
public static void ShowNeighborFaceOfFace(TriMesh.Face face) { foreach (TriMesh.Face neighbors in face.Faces) { neighbors.Traits.SelectedFlag = 9; neighbors.Traits.Color = RetrieveResult.Instance.FaceResult; } face.Traits.Color = Color4.Black; }
public Vector3D[] ComputeVectorField(double initAngle) { Vector3D[] vectorFields = new Vector3D[mesh.Faces.Count]; bool[] visitedFlags = new bool[mesh.Faces.Count]; for (int i = 0; i < visitedFlags.Length; i++) { visitedFlags[i] = false; } //Find a initial root to expend TriMesh.Face rootFace = mesh.Faces[0]; var v1 = rootFace.GetVertex(0); var v3 = rootFace.GetVertex(2); var v2 = rootFace.GetVertex(1); Vector3D w0 = (rootFace.GetVertex(2).Traits.Position - rootFace.GetVertex(0).Traits.Position).Normalize(); //Init transpot Vector3D av = v1.Traits.Position; Vector3D bv = v2.Traits.Position; Vector3D cv = v3.Traits.Position; Matrix3D Ei = Orthogonalize(bv - av, cv - av); Vector3D w0i = (Ei * Matrix3D.Rotate(initAngle) * Ei.Inverse() * w0); vectorFields[rootFace.Index] = w0i; visitedFlags[rootFace.Index] = true; //Recurse all faces Queue <TriMesh.Face> queue = new Queue <HalfEdgeMesh.Face>(); queue.Enqueue(rootFace); int ii = 0; while (queue.Count > 0) { TriMesh.Face currentFace = queue.Dequeue(); Vector3D wI = vectorFields[currentFace.Index]; foreach (TriMesh.Face neighbor in currentFace.Faces) { if (visitedFlags[neighbor.Index] == false) { Vector3D wj = Transport2(wI, currentFace, neighbor); vectorFields[neighbor.Index] = wj; queue.Enqueue(neighbor); visitedFlags[neighbor.Index] = true; } } ii++; } return(vectorFields); }
public static void RemoveFace(TriMesh.Face face) { TriMesh mesh = (TriMesh)face.Mesh; foreach (TriMesh.HalfEdge halfedge in face.Halfedges) { halfedge.Face = null; } mesh.RemoveFace(face); }
Vector3D GetNormal(TriMesh.Face face) { List <Vector3D> list = new List <Vector3D>(); foreach (var item in face.Vertices) { list.Add(item.Traits.Position); } return((list[2] - list[1]).Cross(list[2] - list[0]).Normalize()); }
public static Triple <Vector3D> GetHalfEdgesVector(TriMesh.Face face) { TriMesh.HalfEdge hf = face.HalfEdge; return(new Triple <Vector3D>() { T0 = GetHalfEdgeVector(hf), T1 = GetHalfEdgeVector(hf.Next), T2 = GetHalfEdgeVector(hf.Previous) }); }
public static Triple <Vector3D> GetVerticesPosition(TriMesh.Face face) { TriMesh.HalfEdge hf = face.HalfEdge; return(new Triple <Vector3D>() { T0 = hf.ToVertex.Traits.Position, T1 = hf.Next.ToVertex.Traits.Position, T2 = hf.FromVertex.Traits.Position }); }
public static Vector3D GetMidPoint(TriMesh.Face face) { Vector3D sum = new Vector3D(); foreach (var v in face.Vertices) { sum += v.Traits.Position; } return(sum / 3); }
public static Vector3D ComputeFaceCenter(TriMesh.Face face) { Vector3D center = Vector3D.Zero; foreach (TriMesh.Vertex v in face.Vertices) { center += v.Traits.Position; } center = center / 3d; return(center); }
public static T[] GetFromVertices <T>(TriMesh.Face face, Func <T> func) { T[] arr = new T[3]; int i = 0; foreach (var hf in face.Halfedges) { arr[i++] = func(hf.FromVertex); } return(arr); }
public static List <double> ComputeAngleDegree(TriMesh.Face face) { List <double> angles = ComputeAngle(face); for (int i = 0; i < angles.Count; i++) { angles[i] = angles[i] * 180 / 3.14; } return(angles); }
public double ComputeFaceAngle(TriMesh.Face face1, TriMesh.Face face2)//计算两个面的cos角度值 { double angel = 0; double a = 0, b = 0, c = 0; c = face1.Traits.Normal.x * face2.Traits.Normal.x + face1.Traits.Normal.y * face2.Traits.Normal.y + face1.Traits.Normal.z * face2.Traits.Normal.z; a = Math.Pow(Math.Pow(face1.Traits.Normal.x, 2) + Math.Pow(face1.Traits.Normal.y, 2) + Math.Pow(face1.Traits.Normal.z, 2), 0.5); b = Math.Pow(Math.Pow(face2.Traits.Normal.x, 2) + Math.Pow(face2.Traits.Normal.y, 2) + Math.Pow(face2.Traits.Normal.z, 2), 0.5); angel = c / (a + b); //angel = Math.Acos(angel); return(angel); }
Vector3D Cross(TriMesh.Face face) { Vector3D[] arr = new Vector3D[3]; int i = 0; foreach (var v in face.Vertices) { arr[i++] = v.Traits.Position; } return((arr[1] - arr[0]).Cross(arr[2] - arr[0])); }
public static double ComputeInradius(TriMesh.Face face) { Vector3D a = face.GetVertex(0).Traits.Position; Vector3D b = face.GetVertex(1).Traits.Position; Vector3D c = face.GetVertex(2).Traits.Position; double u = (a - b).Length(); double v = (b - c).Length(); double w = (c - a).Length(); return(0.5 * Math.Sqrt(((u + v - w) * (w + u - v) * (v + w - u)) / (u + v + w))); }
public void RemoveFaces(TriMesh.Face Face) { for (int j = 0; j < BoundaryFaces.Count; j++) { if (BoundaryFaces[j].Equals(Face)) { // Console.WriteLine("BF:" + BoundaryFaces.Count); Faces.Add(BoundaryFaces[j]); BoundaryFaces.Remove(Face); //Console.WriteLine("BA:" + BoundaryFaces.Count); } } }
public static List <double> ComputeAngle(TriMesh.Face face) { List <double> angles = new List <double>(); double angle1 = ComputeAngle(face.GetVertex(0).HalfEdge); double angle2 = ComputeAngle(face.GetVertex(1).HalfEdge); double angle3 = ComputeAngle(face.GetVertex(2).HalfEdge); angles.Add(angle1); angles.Add(angle2); angles.Add(angle3); return(angles); }
public static bool IsBoundary(TriMesh.HalfEdge hf, bool[] faceFlags) { TriMesh.Face left = hf.Face; TriMesh.Face right = hf.Opposite.Face; if (left == null) { return(false); } if (right == null) { return(faceFlags[left.Index]); } return(faceFlags[left.Index] && !faceFlags[right.Index]); }
public static TriMesh.Vertex MergeTriangle(TriMesh.Face face, Vector3D pos) { TriMesh.Edge edge1 = face.HalfEdge.Edge; TriMesh.Edge edge2 = face.HalfEdge.Next.Edge; TriMesh.Vertex v = MergeEdge(edge1, pos); if (IsMergeable(edge2)) { v = MergeEdge(edge2, pos); } else { edge2.Traits.SelectedFlag = 1; } return(v); }
public static bool IsMergeable(TriMesh.Face face) { if (face.OnBoundary) { //return false; } foreach (var hf in face.Halfedges) { if (!TriMeshModify.IsMergeable(hf.Edge)) { return(false); } } return(true); }
TriMesh.Vertex GetMinCvtVertex(TriMesh.Face face) { double minCvt = double.MaxValue; TriMesh.Vertex min = null; foreach (var v in face.Vertices) { double cvt = Math.Abs(this.traits.VertexDiscreteCurvature[v.Index]); if (cvt < minCvt) { minCvt = cvt; min = v; } } return(min); }
private static TriMesh.HalfEdge[] AddInnerTriangle(TriMesh mesh, params TriMesh.Vertex[] verteces) { TriMesh.Face face = new TriMesh.Face(); mesh.AppendToFaceList(face); TriMesh.HalfEdge[] hfs = new TriMesh.HalfEdge[3]; for (int i = 0; i < hfs.Length; i++) { hfs[i] = new TriMesh.HalfEdge(); hfs[i].ToVertex = verteces[(i + 1) % hfs.Length]; hfs[i].Face = face; mesh.AppendToHalfedgeList(hfs[i]); } face.HalfEdge = hfs[0]; ConnectHalfEdge(hfs); return hfs; }
/// <summary> /// Adds a face to the mesh with the specified face traits. /// </summary> /// <param name="faceVertices">The vertices of the face in counterclockwise order.</param> /// <returns>The face created by this method.</returns> /// <exception cref="BadTopologyException"> /// Thrown when fewer than three vertices are given or the vertices cannot form a valid face. /// </exception> /// <exception cref="ArgumentNullException">Thrown when a null vertex is given.</exception> public TriMesh.Face CreateFace(params TriMesh.Vertex[] faceVertices) { int n = faceVertices.Length; // Require at least 3 vertices if (n < 3) { throw new BadTopologyException("Cannot create a polygon with fewer than three vertices."); } TriMesh mesh = (TriMesh)faceVertices[0].Mesh; TriMesh.HalfEdge[] faceHalfedges = new TriMesh.HalfEdge[n]; bool[] isUsedVertex = new bool[n]; // Make sure input is (mostly) acceptable before making any changes to the mesh for (int i = 0; i < n; ++i) { int j = (i + 1) % n; faceHalfedges[i] = this.Validate(faceVertices[i], faceVertices[j]); isUsedVertex[i] = (faceVertices[i].HalfEdge != null); } // Create face TriMesh.Face f = new TriMesh.Face(default(FaceTraits)); mesh.AppendToFaceList(f); // Create new edges for (int i = 0; i < n; ++i) { int j = (i + 1) % n; if (faceHalfedges[i] == null) { TriMesh.Edge newEdge = this.CreateNewEdge(faceVertices[i], faceVertices[j]); faceHalfedges[i] = newEdge.HalfEdge0; } faceHalfedges[i].Face = f; } // Connect next/previous halfedges for (int i = 0; i < n; ++i) { int j = (i + 1) % n; this.ConnectHalfedge(faceHalfedges[i], faceHalfedges[j], isUsedVertex[j]); } // Connect face to an inner halfedge f.HalfEdge = faceHalfedges[0]; return f; }
public TriMesh.Vertex VertexSplit1(TriMesh.Vertex v, TriMesh.Vertex vshard1, TriMesh.Vertex vshard2, Vector3D v1Position, Vector3D v2Position, int v2FixedIndex) { //1.Get two group of verties TriMesh.HalfEdge[] processGroup = FindGroup(v, vshard1, vshard2); TriMesh mesh = (TriMesh)v.Mesh; TriMesh.Vertex v1 = null; TriMesh.Vertex v2 = null; TriMesh.Vertex newVertex = null; v1 = v; v.Traits.Position = v1Position; v2 = new TriMesh.Vertex(); v2.Traits = new VertexTraits(Vector3D.Zero); newVertex = v2; newVertex.Traits.FixedIndex = v2FixedIndex; v2.Mesh = v.Mesh; v2.Traits.Position = v2Position; //2.Process the Topology TriMesh.HalfEdge hf1Origin = processGroup[0]; TriMesh.HalfEdge hf2Origin = processGroup[processGroup.Length - 1]; //Add new edge TriMesh.HalfEdge hf3 = new TriMesh.HalfEdge(); TriMesh.HalfEdge hf3Oppsite = new TriMesh.HalfEdge(); TriMesh.Edge edge = new TriMesh.Edge(); hf3.Opposite = hf3Oppsite; hf3Oppsite.Opposite = hf3; edge.HalfEdge0 = hf3; edge.HalfEdge1 = hf3Oppsite; hf3.Edge = edge; hf3Oppsite.Edge = edge; hf3.ToVertex = v2; hf3Oppsite.ToVertex = v1; //Handle hf1Origin which is outter hafledge [INNER] TriMesh.HalfEdge hf1 = new TriMesh.HalfEdge(); hf1.Opposite = hf1Origin; hf1.ToVertex = v1; TriMesh.HalfEdge hf1Other = new TriMesh.HalfEdge(); hf1Other.Opposite = hf1Origin.Opposite; hf1Other.ToVertex = hf1Origin.ToVertex; hf1.Previous = hf1Other; hf1Other.Next = hf1; hf1.Next = hf3; hf3.Previous = hf1; hf1Other.Previous = hf3; hf3.Next = hf1Other; //Handle hf2Origin which is inner hafledge [INNER] TriMesh.HalfEdge hf2 = new TriMesh.HalfEdge(); hf2.Opposite = hf2Origin; hf2.ToVertex = v2; TriMesh.HalfEdge hf2Other = new TriMesh.HalfEdge(); hf2Other.Opposite = hf2Origin.Opposite; hf2Other.ToVertex = hf2Origin.ToVertex; hf2.Previous = hf2Other; hf2Other.Next = hf2; hf2.Next = hf3Oppsite; hf3Oppsite.Previous = hf2; hf2Other.Previous = hf3Oppsite; hf3Oppsite.Next = hf2Other; TriMesh.Face face1 = new TriMesh.Face(); TriMesh.Face face2 = new TriMesh.Face(); face1.HalfEdge = hf3; hf3.Face = face1; hf1.Face = face1; hf1Other.Face = face1; face2.HalfEdge = hf3Oppsite; hf3Oppsite.Face = face2; hf2.Face = face2; hf2Other.Face = face2; //Process the outside TriMesh.Edge edge1 = new TriMesh.Edge(); TriMesh.HalfEdge hf1OriginOppsite = hf1Origin.Opposite; hf1Origin.Opposite = hf1; hf1.Edge = hf1Origin.Edge; hf1OriginOppsite.Opposite = hf1Other; hf1OriginOppsite.ToVertex = v2; hf1OriginOppsite.Edge = edge1; hf1Other.Edge = edge1; edge1.HalfEdge0 = hf1Other; edge1.HalfEdge1 = hf1OriginOppsite; TriMesh.Edge edge2 = new TriMesh.Edge(); TriMesh.HalfEdge hf2OriginOppsite = hf2Origin.Opposite; hf2Origin.Opposite = hf2; hf2.Edge = hf2Origin.Edge; hf2OriginOppsite.Opposite = hf2Other; hf2OriginOppsite.ToVertex = v1; hf2OriginOppsite.Edge = edge2; hf2Other.Edge = edge2; edge2.HalfEdge0 = hf2Other; edge2.HalfEdge1 = hf2OriginOppsite; v1.HalfEdge = hf1Origin; v2.HalfEdge = hf2Origin; mesh.AppendToEdgeList(edge); mesh.AppendToEdgeList(edge1); mesh.AppendToEdgeList(edge2); mesh.AppendToFaceList(face1); mesh.AppendToFaceList(face2); mesh.AppendToHalfedgeList(hf1); mesh.AppendToHalfedgeList(hf1Other); mesh.AppendToHalfedgeList(hf2); mesh.AppendToHalfedgeList(hf2Other); mesh.AppendToHalfedgeList(hf3); mesh.AppendToHalfedgeList(hf3Oppsite); mesh.AppendToVertexList(newVertex); for (int i = 1; i < processGroup.Length - 1; i++) { processGroup[i].Opposite.ToVertex = newVertex; } //mesh.FixIndex(); return newVertex; }
/// <summary> /// Adds a face to the mesh with the specified face traits. /// </summary> /// <param name="faceTraits">The custom traits for the face to add to the mesh.</param> /// <param name="faceVertices">The vertices of the face in counterclockwise order.</param> /// <returns>The face created by this method.</returns> /// <exception cref="BadTopologyException"> /// Thrown when fewer than three vertices are given or the vertices cannot form a valid face. /// </exception> /// <exception cref="ArgumentNullException">Thrown when a null vertex is given.</exception> private static TriMesh.Face CreateFace(TriMesh mesh, params TriMesh.Vertex[] faceVertices) { int n = faceVertices.Length; // Require at least 3 vertices if (n < 3) { throw new BadTopologyException("Cannot create a polygon with fewer than three vertices."); } TriMesh.Edge e; TriMesh.Face f; TriMesh.HalfEdge[] faceHalfedges = new TriMesh.HalfEdge[n]; bool[] isNewEdge = new bool[n], isUsedVertex = new bool[n]; for (int i = 0; i < n; i++) { int j = (i + 1) % n; faceHalfedges[i] = faceVertices[i].FindHalfedgeTo(faceVertices[j]); } // Make sure input is (mostly) acceptable before making any changes to the mesh for (int i = 0; i < n; ++i) { int j = (i + 1) % n; if (faceVertices[i] == null) { throw new ArgumentNullException("Can't add a null vertex to a face."); } if (!faceVertices[i].OnBoundary) { throw new BadTopologyException("Can't add an edge to a vertex on the interior of a mesh."); } // Find existing halfedges for this face faceHalfedges[i] = faceVertices[i].FindHalfedgeTo(faceVertices[j]); isNewEdge[i] = (faceHalfedges[i] == null); isUsedVertex[i] = (faceVertices[i].HalfEdge != null); if (!isNewEdge[i] && !faceHalfedges[i].OnBoundary) { throw new BadTopologyException("Can't add more than two faces to an edge."); } } // Create face f = new TriMesh.Face(default(FaceTraits)); mesh.AppendToFaceList(f); // Create new edges for (int i = 0; i < n; ++i) { int j = (i + 1) % n; if (isNewEdge[i]) { // Create new edge e = new TriMesh.Edge(); mesh.AppendToEdgeList(e); // Create new halfedges faceHalfedges[i] = new TriMesh.HalfEdge(); mesh.AppendToHalfedgeList(faceHalfedges[i]); faceHalfedges[i].Opposite = new TriMesh.HalfEdge(); mesh.AppendToHalfedgeList(faceHalfedges[i].Opposite); // Connect opposite halfedge to inner halfedge faceHalfedges[i].Opposite.Opposite = faceHalfedges[i]; // Connect edge to halfedges e.HalfEdge0 = faceHalfedges[i]; // Connect halfedges to edge faceHalfedges[i].Edge = e; faceHalfedges[i].Opposite.Edge = e; // Connect halfedges to vertices faceHalfedges[i].ToVertex = faceVertices[j]; faceHalfedges[i].Opposite.ToVertex = faceVertices[i]; // Connect vertex to outgoing halfedge if it doesn't have one yet if (faceVertices[i].HalfEdge == null) { faceVertices[i].HalfEdge = faceHalfedges[i]; } } if (faceHalfedges[i].Face != null) { throw new BadTopologyException("An inner halfedge already has a face assigned to it."); } // Connect inner halfedge to face faceHalfedges[i].Face = f; } // Connect next/previous halfedges for (int i = 0; i < n; ++i) { int j = (i + 1) % n; // Outer halfedges if (isNewEdge[i] && isNewEdge[j] && isUsedVertex[j]) // Both edges are new and vertex has faces connected already { TriMesh.HalfEdge closeHalfedge = null; // Find the closing halfedge of the first available opening foreach (TriMesh.HalfEdge h in faceVertices[j].HalfEdges) { if (h.Face == null) { closeHalfedge = h; break; } } TriMesh.HalfEdge openHalfedge = closeHalfedge.Previous; // Link new outer halfedges into this opening faceHalfedges[i].Opposite.Previous = openHalfedge; openHalfedge.Next = faceHalfedges[i].Opposite; faceHalfedges[j].Opposite.Next = closeHalfedge; closeHalfedge.Previous = faceHalfedges[j].Opposite; } else if (isNewEdge[i] && isNewEdge[j]) // Both edges are new { faceHalfedges[i].Opposite.Previous = faceHalfedges[j].Opposite; faceHalfedges[j].Opposite.Next = faceHalfedges[i].Opposite; } else if (isNewEdge[i] && !isNewEdge[j]) // This is new, next is old { faceHalfedges[i].Opposite.Previous = faceHalfedges[j].Previous; faceHalfedges[j].Previous.Next = faceHalfedges[i].Opposite; } else if (!isNewEdge[i] && isNewEdge[j]) // This is old, next is new { faceHalfedges[i].Next.Previous = faceHalfedges[j].Opposite; faceHalfedges[j].Opposite.Next = faceHalfedges[i].Next; } // Relink faces before adding new edges if they are in the way of a new face else if (!isNewEdge[i] && !isNewEdge[j] && faceHalfedges[i].Next != faceHalfedges[j]) { TriMesh.HalfEdge closeHalfedge = faceHalfedges[i].Opposite; // Find the closing halfedge of the opening opposite the opening halfedge i is on do { closeHalfedge = closeHalfedge.Previous.Opposite; } while (closeHalfedge.Face != null && closeHalfedge != faceHalfedges[j] && closeHalfedge != faceHalfedges[i].Opposite); if (closeHalfedge == faceHalfedges[j] || closeHalfedge == faceHalfedges[i].Opposite) { throw new BadTopologyException("Unable to find an opening to relink an existing face."); } TriMesh.HalfEdge openHalfedge = closeHalfedge.Previous; // Remove group of faces between two openings, close up gap to form one opening openHalfedge.Next = faceHalfedges[i].Next; faceHalfedges[i].Next.Previous = openHalfedge; // Insert group of faces into target opening faceHalfedges[j].Previous.Next = closeHalfedge; closeHalfedge.Previous = faceHalfedges[j].Previous; } // Inner halfedges faceHalfedges[i].Next = faceHalfedges[j]; faceHalfedges[j].Previous = faceHalfedges[i]; } // Connect face to an inner halfedge f.HalfEdge = faceHalfedges[0]; return f; }
public void SetSeedFaces(int n) { Seedface = this.mesh.Faces[n]; }