private TriMesh.HalfEdge[] FindSaddleExtreme(TriMesh.Vertex v, bool maxOrMin) { List <TriMesh.HalfEdge> all = new List <HalfEdgeMesh.HalfEdge>(); TriMesh.HalfEdge n2p = this.FindN2P(v); v.HalfEdge = n2p; List <TriMesh.HalfEdge> part = new List <HalfEdgeMesh.HalfEdge>(); double mid = this.function[v.Index]; foreach (TriMesh.HalfEdge hf in v.HalfEdges) { double round = this.function[hf.ToVertex.Index]; if (this.Compare(round, mid, maxOrMin)) { part.Add(hf); } else { if (part.Count != 0) { all.Add(this.FindExtreme(part, maxOrMin)); } part.Clear(); } } if (part.Count != 0) { all.Add(this.FindExtreme(part, maxOrMin)); } return(all.ToArray()); }
public static void InverseFace(TriMesh mesh) { List <TriMesh.Vertex[]> faces = new List <HalfEdgeMesh.Vertex[]>(); foreach (TriMesh.Face face in mesh.Faces) { TriMesh.HalfEdge hf = face.HalfEdge; TriMesh.Vertex[] arr = new TriMesh.Vertex[] { hf.Next.ToVertex, hf.ToVertex, hf.FromVertex }; faces.Add(arr); } TriMesh.Vertex[] vertices = new TriMesh.Vertex[mesh.Vertices.Count]; for (int i = 0; i < mesh.Vertices.Count; i++) { vertices[i] = mesh.Vertices[i]; vertices[i].HalfEdge = null; } mesh.Clear(); foreach (var v in vertices) { mesh.AppendToVertexList(v); } foreach (var face in faces) { mesh.Faces.AddTriangles(face); } }
/// <summary> /// 两端点都在边界上 /// </summary> /// <param name="edge"></param> void CutBothBoundary(TriMesh.Edge edge) { TriMesh.HalfEdge hf = edge.HalfEdge0; TriMesh.HalfEdge[] leftArr = this.GetToBoundaryAntiClockWise(hf); TriMesh.HalfEdge[] rightArr = this.GetToBoundaryClockWise(hf.Next); for (int i = 1; i < leftArr.Length; i++) { TriMeshModify.RemoveEdge(leftArr[i].Edge); } for (int i = 0; i < rightArr.Length; i++) { TriMeshModify.RemoveEdge(rightArr[i].Edge); } Vector3D vec = this.GetMoveVector(hf.Opposite); TriMesh.Vertex left = this.Clone(hf.FromVertex, vec); TriMesh.Vertex right = this.Clone(hf.ToVertex, vec); for (int i = 2; i < leftArr.Length; i++) { this.mesh.Faces.AddTriangles(left, leftArr[i - 1].ToVertex, leftArr[i].ToVertex); } for (int i = 1; i < rightArr.Length; i++) { this.mesh.Faces.AddTriangles(right, rightArr[i].ToVertex, rightArr[i - 1].ToVertex); } this.mesh.Faces.AddTriangles(left, right, leftArr[1].ToVertex); }
private double GetAngle(Plane plane, TriMesh.HalfEdge hf) { Vector3D v = hf.ToVertex.Traits.Position - hf.FromVertex.Traits.Position; double cos = Math.Abs(plane.Normal.Dot(v.Normalize())); return(Math.Acos(cos) * 180 / Math.PI); }
public List <List <TriMesh.HalfEdge> > Append1RingBases(TriMesh mesh) { MapRow = new int[mesh.Vertices.Count]; List <List <TriMesh.HalfEdge> > cycles = new List <List <HalfEdgeMesh.HalfEdge> >(); foreach (TriMesh.Vertex vertex in mesh.Vertices) { if (vertex.OnBoundary) { MapRow[vertex.Index] = -1; continue; } List <TriMesh.HalfEdge> cycle = new List <HalfEdgeMesh.HalfEdge>(); TriMesh.HalfEdge currentHf = vertex.HalfEdge; do { cycle.Add(currentHf); currentHf = currentHf.Opposite.Next; } while (currentHf != vertex.HalfEdge); MapRow[vertex.Index] = cycles.Count; cycles.Add(cycle); } return(cycles); }
public void PlaneCut(TriMesh.HalfEdge above, Vector3D normal, double maxAngle) { Plane plane = new Plane(above.Next.ToVertex.Traits.Position, normal); Nullable <Vector3D> point = this.Intersect(plane, above.Edge); double angle = this.GetAngle(plane, above); while (point != null && angle > maxAngle) { TriMesh.Vertex left = above.FromVertex; TriMesh.Vertex right = above.ToVertex; TriMesh.Vertex buttom = above.Opposite.Next.ToVertex; this.Cut(above, point.Value); if (above.Opposite.OnBoundary) { break; } TriMesh.HalfEdge[] below = new[] { left.FindHalfedgeTo(buttom), buttom.FindHalfedgeTo(right) }; foreach (var hf in below) { point = this.Intersect(plane, hf.Edge); if (point != null) { angle = this.GetAngle(plane, hf); above = hf; break; } } } }
public static bool EdgeSwap(TriMesh.Edge edge) { if (edge.OnBoundary) { return(false); } //逆时针90度,左右变为下上 TriMesh.HalfEdge hf1 = edge.HalfEdge0; TriMesh.HalfEdge hf2 = edge.HalfEdge1; TriMesh.Vertex top = hf1.ToVertex; TriMesh.Vertex buttom = hf2.ToVertex; TriMesh.HalfEdge topLeft = hf1.Next; TriMesh.HalfEdge buttomLeft = hf1.Previous; TriMesh.HalfEdge topRight = hf2.Previous; TriMesh.HalfEdge buttomRight = hf2.Next; top.HalfEdge = topLeft; buttom.HalfEdge = buttomRight; hf1.ToVertex = topLeft.ToVertex; hf2.ToVertex = buttomRight.ToVertex; hf1.Face.HalfEdge = hf1; hf2.Face.HalfEdge = hf2; topLeft.Face = hf2.Face; buttomRight.Face = hf1.Face; ConnectHalfEdge(topLeft, hf2, topRight); ConnectHalfEdge(buttomRight, hf1, buttomLeft); return(true); }
public void RemoveCapWithSplit() { int count = 0; do { count = 0; for (int i = 0; i < this.mesh.HalfEdges.Count; i++) { TriMesh.HalfEdge hf = this.mesh.HalfEdges[i]; double angle = TriMeshUtil.ComputeAngle(hf) / Math.PI * 180; if (angle > this.capAngle) { Plane plane = this.GetPlane(hf); Nullable <Vector3D> point = this.Intersect(plane, hf.Edge); this.ShowIntersect(plane); if (point != null) { this.Cut(hf, point.Value); count++; } else { hf.Edge.Traits.SelectedFlag = 1; } } } } while (count != 0); }
TriMesh.Edge CreateNewEdge(TriMesh.Vertex from, TriMesh.Vertex to) { TriMesh mesh = (TriMesh)from.Mesh; // Create new edge TriMesh.Edge edge = new TriMesh.Edge(); mesh.AppendToEdgeList(edge); // Create new halfedges TriMesh.HalfEdge hf0 = new TriMesh.HalfEdge(); mesh.AppendToHalfedgeList(hf0); hf0.Opposite = new TriMesh.HalfEdge(); mesh.AppendToHalfedgeList(hf0.Opposite); // Connect opposite halfedge to inner halfedge hf0.Opposite.Opposite = hf0; // Connect edge to halfedges edge.HalfEdge0 = hf0; // Connect halfedges to edge hf0.Edge = edge; hf0.Opposite.Edge = edge; // Connect halfedges to vertices hf0.ToVertex = to; hf0.Opposite.ToVertex = from; // Connect vertex to outgoing halfedge if it doesn't have one yet if (from.HalfEdge == null) { from.HalfEdge = hf0; } return(edge); }
void OuterHalfedgeBothOld(TriMesh.HalfEdge cur, TriMesh.HalfEdge next) { // Relink faces before adding new edges if they are in the way of a new face if (cur.Next != next) { TriMesh.HalfEdge closeHalfedge = cur.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 != next && closeHalfedge != cur.Opposite); if (closeHalfedge == next || closeHalfedge == cur.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 = cur.Next; cur.Next.Previous = openHalfedge; // Insert group of faces into target opening next.Previous.Next = closeHalfedge; closeHalfedge.Previous = next.Previous; } }
void OuterHalfedgeBothNew(TriMesh.HalfEdge cur, TriMesh.HalfEdge next, bool vertexIsUsed) { if (vertexIsUsed) // Both edges are new and vertex has faces connected already { TriMesh.Vertex vertex = cur.ToVertex; TriMesh.HalfEdge closeHalfedge = null; // Find the closing halfedge of the first available opening foreach (TriMesh.HalfEdge h in vertex.HalfEdges) { if (h.Face == null) { closeHalfedge = h; break; } } TriMesh.HalfEdge openHalfedge = closeHalfedge.Previous; // Link new outer halfedges into this opening cur.Opposite.Previous = openHalfedge; openHalfedge.Next = cur.Opposite; next.Opposite.Next = closeHalfedge; closeHalfedge.Previous = next.Opposite; } else { cur.Opposite.Previous = next.Opposite; next.Opposite.Next = cur.Opposite; } }
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 void SelectAngle(TriMesh.HalfEdge hf) { hf.Edge.Traits.SelectedFlag = 1; hf.Previous.Edge.Traits.SelectedFlag = 1; hf.Next.Edge.Traits.SelectedFlag = 1; hf.Next.ToVertex.Traits.SelectedFlag = 1; }
public bool Backward() { if (this.index == 0) { return(false); } else { index--; EdgeContext ctx = this.method.Logs[this.index]; SplitVertex.Split(this.Mesh, ctx); TriMesh.Vertex left = null; TriMesh.Vertex right = null; foreach (var v in this.Mesh.Vertices) { if (v.Index == ctx.Left) { left = v; } else if (v.Index == ctx.Right) { right = v; } } TriMesh.HalfEdge hf = left.FindHalfedgeTo(right); hf.Face.Traits.Normal = TriMeshUtil.ComputeNormalFace(hf.Face); hf.Opposite.Face.Traits.Normal = TriMeshUtil.ComputeNormalFace(hf.Opposite.Face); left.Traits.Normal = TriMeshUtil.ComputeNormalAreaWeight(left); right.Traits.Normal = TriMeshUtil.ComputeNormalAreaWeight(right); return(true); } }
private static void InsertEdge(TriMesh mesh, TriMesh.HalfEdge inner, TriMesh.HalfEdge outer) { //TriMesh.Edge left = new TriMesh.Edge(); //left.HalfEdge0 = outer; //outer.Edge = left; //inner.Next.Edge = left; //TriMesh.Edge right = outer.Edge; //right.HalfEdge0 = inner; //inner.Edge = right; //outer.Opposite.Edge = right; //inner.Opposite = outer.Opposite; //inner.Next.Opposite = outer; //outer.Opposite.Opposite = inner; //outer.Opposite = inner.Next; inner.Opposite = outer.Opposite; inner.Next.Opposite = outer; outer.Opposite.Opposite = inner; outer.Opposite = inner.Next; outer.Edge.HalfEdge0 = outer; TriMesh.Edge edge = new TriMesh.Edge(); edge.HalfEdge0 = inner; inner.Edge = edge; inner.Opposite.Edge = edge; inner.Next.Edge = outer.Edge; mesh.AppendToEdgeList(edge); }
public static TriMesh.HalfEdge[] RetrieveBoundaryHalfEdgeByPatch(TriMesh mesh, bool[] selectedFlags) { List <TriMesh.HalfEdge> boundaryHFs = new List <TriMesh.HalfEdge>(); TriMesh.HalfEdge start = GetStart(mesh, selectedFlags); if (start == null) { return(boundaryHFs.ToArray()); } TriMesh.HalfEdge cur = start; do { do { cur = cur.Next.Opposite; } while (!(selectedFlags[cur.Next.FromVertex.Index] && selectedFlags[cur.Next.ToVertex.Index])); do { cur = cur.Next; boundaryHFs.Add(cur); } while (cur.OnBoundary && selectedFlags[cur.Next.ToVertex.Index] && selectedFlags[cur.Next.FromVertex.Index]); } while (cur != start); return(boundaryHFs.ToArray()); }
public static TriMesh.HalfEdge Split(TriMesh.HalfEdge hf, Vector3D v1Pos, Vector3D v2Pos) { TriMesh mesh = (TriMesh)hf.Mesh; List <TriMesh.HalfEdge> list = new List <HalfEdgeMesh.HalfEdge>(); TriMesh.HalfEdge cur = hf; list.Add(cur); do { cur = cur.Opposite.Next; list.Add(cur); } while (cur.Opposite.Face != null && cur != hf); for (int i = 1; i < list.Count; i++) { TriMeshModify.RemoveEdge(list[i].Edge); } hf.FromVertex.Traits.Position = v1Pos; TriMesh.Vertex v2 = new HalfEdgeMesh.Vertex(new VertexTraits(v2Pos)); mesh.AppendToVertexList(v2); for (int i = 1; i < list.Count; i++) { mesh.Faces.AddTriangles(list[i - 1].ToVertex, v2, list[i].ToVertex); } mesh.Faces.AddTriangles(list[0].ToVertex, hf.FromVertex, v2); return(hf.FromVertex.FindHalfedgeTo(v2)); }
public static List <TriMesh.HalfEdge> RetrieveOneRingEdgeOfEdge(TriMesh.Edge edge) { TriMesh mesh = (TriMesh)edge.Mesh; List <TriMesh.HalfEdge> list = new List <TriMesh.HalfEdge>(); TriMesh.HalfEdge hf0 = edge.HalfEdge0; TriMesh.HalfEdge currentHalfedge = hf0.Next.Opposite; while (currentHalfedge.Next.Opposite != hf0) { if (!currentHalfedge.OnBoundary) { list.Add(currentHalfedge.Previous); } currentHalfedge = currentHalfedge.Next.Opposite; } ; TriMesh.HalfEdge hf1 = edge.HalfEdge1; currentHalfedge = hf1.Next.Opposite; while (currentHalfedge.Next.Opposite != hf1) { if (!currentHalfedge.OnBoundary) { list.Add(currentHalfedge.Previous); } currentHalfedge = currentHalfedge.Next.Opposite; } ; return(list); }
/// <summary> /// 逆时针一圈 /// </summary> /// <param name="mesh"></param> /// <param name="faceFlags"></param> /// <returns></returns> public static TriMesh.HalfEdge[] RetrieveRegionBoundaryHalfEdge(TriMesh mesh, bool[] faceFlags) { TriMesh.HalfEdge start = null; foreach (var hf in mesh.HalfEdges) { if (IsBoundary(hf, faceFlags)) { start = hf; break; } } List <TriMesh.HalfEdge> list = new List <HalfEdgeMesh.HalfEdge>(); TriMesh.HalfEdge cur = start; do { list.Add(cur); foreach (var hf in cur.ToVertex.HalfEdges) { if (IsBoundary(hf, faceFlags)) { cur = hf; break; } } } while (cur != start); return(list.ToArray()); }
public static TriMesh.Vertex MergeEdge(TriMesh.Edge edge, Vector3D position) { TriMesh mesh = (TriMesh)edge.Mesh; TriMesh.Vertex v0 = edge.Vertex0; TriMesh.Vertex v1 = edge.Vertex1; TriMesh.HalfEdge hf0 = edge.HalfEdge0; TriMesh.HalfEdge hf1 = edge.HalfEdge1; v0.Traits.Position = position; foreach (var item in v1.HalfEdges) { //if (item.ToVertex != v0) { item.Opposite.ToVertex = v0; } } MergeOneSide(hf0); MergeOneSide(hf1); mesh.RemoveVertex(v1); mesh.RemoveEdge(edge); v1.HalfEdge = null; edge.HalfEdge0 = null; return(v0); }
public static void Split(TriMesh mesh, EdgeContext ctx) { TriMesh.Vertex left = null; TriMesh.Vertex top = null; TriMesh.Vertex bottom = null; foreach (var v in mesh.Vertices) { if (v.Index == ctx.Left) { left = v; } else if (v.Index == ctx.Top) { top = v; } else if (v.Index == ctx.Bottom) { bottom = v; } } TriMesh.Vertex right = TriMeshModify.VertexSplit(left, top, bottom, ctx.LeftPos, ctx.RightPos); TriMesh.HalfEdge hf = left.FindHalfedgeTo(right); right.Index = ctx.Right; hf.Next.ToVertex.Index = ctx.Top; hf.Opposite.Next.ToVertex.Index = ctx.Bottom; }
void ConnectHalfedge(TriMesh.HalfEdge cur, TriMesh.HalfEdge next, bool vertexIsUsed) { TriMesh mesh = (TriMesh)cur.Mesh; bool curIsNew = cur.Next == null; bool nextIsNew = next.Previous == null; // Outer halfedges if (curIsNew && nextIsNew) { this.OuterHalfedgeBothNew(cur, next, vertexIsUsed); } else if (curIsNew && !nextIsNew) // This is new, next is old { cur.Opposite.Previous = next.Previous; next.Previous.Next = cur.Opposite; } else if (!curIsNew && nextIsNew) // This is old, next is new { cur.Next.Previous = next.Opposite; next.Opposite.Next = cur.Next; } else { this.OuterHalfedgeBothOld(cur, next); } // Inner halfedges cur.Next = next; next.Previous = cur; }
Vector3D GetMoveVector(TriMesh.HalfEdge hf) { Vector3D normal = TriMeshUtil.ComputeNormalFace(hf.Face); Vector3D vec = hf.ToVertex.Traits.Position - hf.FromVertex.Traits.Position; Vector3D dir = normal.Cross(vec).Normalize(); return(dir * this.move); }
private Plane GetProjectivePlane(TriMesh.HalfEdge hf) { Vector3D p = hf.Next.ToVertex.Traits.Position; Vector3D p1 = hf.FromVertex.Traits.Position; Vector3D p2 = hf.ToVertex.Traits.Position; return(new Plane(p, p2 - p1)); }
private void Cut(TriMesh.HalfEdge above, Vector3D pos) { TriMesh.Vertex v1 = above.FromVertex; TriMesh.Vertex top = above.Next.ToVertex; TriMesh.Vertex buttom = above.Opposite.Next.ToVertex; TriMesh.Vertex v2 = TriMeshModify.VertexSplit(v1, top, buttom, v1.Traits.Position, pos); v2.Traits.SelectedFlag = 1; }
private static void MergeOneSide(TriMesh.HalfEdge hf) { TriMesh mesh = (TriMesh)hf.Mesh; if (hf.OnBoundary) { hf.ToVertex.HalfEdge = hf.Next; hf.Previous.Next = hf.Next; hf.Next.Previous = hf.Previous; } else { TriMesh.Edge remain = hf.Next.Edge; TriMesh.Edge remove = hf.Previous.Edge; TriMesh.HalfEdge outerLeft = hf.Previous.Opposite; TriMesh.HalfEdge outerRight = hf.Next.Opposite; if (outerLeft.Next == outerRight || outerLeft.Previous == outerRight) { outerLeft.Edge.Traits.SelectedFlag = 1; hf.FromVertex.Traits.SelectedFlag = 1; outerLeft.ToVertex.Traits.SelectedFlag = 1; //throw new Exception(); } remain.HalfEdge0 = outerRight; outerLeft.Edge = remain; outerLeft.Opposite = outerRight; outerRight.Opposite = outerLeft; hf.ToVertex.HalfEdge = outerRight.Next; //hf.ToVertex.HalfEdge = outerLeft; TriMesh.Vertex top = hf.Next.ToVertex; top.HalfEdge = outerRight; mesh.RemoveFace(hf.Face); mesh.RemoveHalfedge(hf.Previous); mesh.RemoveHalfedge(hf.Next); mesh.RemoveEdge(remove); hf.Previous.Previous = null; hf.Previous.Next = null; hf.Previous.Opposite = null; hf.Next.Previous = null; hf.Next.Next = null; hf.Next.Opposite = null; remove.HalfEdge0 = null; } mesh.RemoveHalfedge(hf); hf.ToVertex = null; hf.Next = null; hf.Previous = null; hf.Opposite = null; hf.Face = null; }
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) }); }
private Plane GetBisectorPlane(TriMesh.HalfEdge hf) { Vector3D a = hf.Next.ToVertex.Traits.Position; Vector3D b = hf.FromVertex.Traits.Position; Vector3D c = hf.ToVertex.Traits.Position; Vector3D v1 = a + (b + c - a * 2); Vector3D v2 = a + new Plane(a, b, c).Normal; return(new Plane(a, v1, v2)); }
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 double ComputeAngle(TriMesh.HalfEdge op) { double a = (op.FromVertex.Traits.Position - op.ToVertex.Traits.Position).Length(); double b = (op.ToVertex.Traits.Position - op.Next.ToVertex.Traits.Position).Length(); double c = (op.Next.ToVertex.Traits.Position - op.FromVertex.Traits.Position).Length(); double angle = Math.Acos((b * b + c * c - a * a) / (2 * b * c)); return(angle); }
private TriMesh.HalfEdge[] AddInnerTriangle(TriMesh mesh, TriMesh.Face face, params TriMesh.Vertex[] verteces) { mesh.Add(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]; this.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; }
/// <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 MakeTheTopologyB(PolygonMesh dualMesh) { List<TriMesh.Vertex> boundaryVertices = new List<TriMesh.Vertex>(); boundaryVertices = TriMeshUtil.RetrieveAllBoundaryVertex(mesh); foreach (TriMesh.Face face in mesh.Faces) { int index = face.Index; int baryVertexIndex = mesh.Edges.Count; int edgeVertexIndex; int faceIndex = index; TriMesh.Edge boundaryEdge = new TriMesh.Edge(); TriMesh.HalfEdge tempHalfedge = new TriMesh.HalfEdge(); TriMesh.Vertex vertex0 = mesh.Faces[index].GetVertex(0); TriMesh.Vertex vertex1 = mesh.Faces[index].GetVertex(1); TriMesh.Vertex vertex2 = mesh.Faces[index].GetVertex(2); TriMesh.HalfEdge halfedge0 = vertex0.FindHalfedgeTo(vertex1); TriMesh.HalfEdge halfedge1 = vertex1.FindHalfedgeTo(vertex2); TriMesh.HalfEdge halfedge2 = vertex2.FindHalfedgeTo(vertex0); TriMesh.HalfEdge boundaryHalfedge = new TriMesh.HalfEdge(); tempHalfedge = halfedge0; edgeVertexIndex = halfedge0.Edge.Index; TriMesh.Vertex firstVertex = dualMesh.Vertices[baryVertexIndex + faceIndex]; TriMesh.Vertex secondVertex = dualMesh.Vertices[edgeVertexIndex]; if (firstVertex.FindHalfedgeTo(secondVertex) == null) { List<TriMesh.Vertex> ringVertices = new List<TriMesh.Vertex>(); do { ringVertices.Add(dualMesh.Vertices[baryVertexIndex + faceIndex]); ringVertices.Add(dualMesh.Vertices[edgeVertexIndex]); if (tempHalfedge.Opposite.Next.Face != null) { tempHalfedge = tempHalfedge.Opposite.Next; faceIndex = tempHalfedge.Face.Index; edgeVertexIndex = tempHalfedge.Edge.Index; } else { tempHalfedge = tempHalfedge.Opposite.Next; edgeVertexIndex = tempHalfedge.Edge.Index; faceIndex = tempHalfedge.Opposite.Next.Face.Index; } } while (tempHalfedge != halfedge0); TriMesh.Vertex[] newFaceVertices = new TriMesh.Vertex[ringVertices.Count]; for (int i = 0; i < ringVertices.Count; i++) { newFaceVertices[i] = ringVertices[i]; } dualMesh.Faces.Add(newFaceVertices); } tempHalfedge = halfedge1; edgeVertexIndex = halfedge1.Edge.Index; firstVertex = dualMesh.Vertices[baryVertexIndex + faceIndex]; secondVertex = dualMesh.Vertices[edgeVertexIndex]; if (firstVertex.FindHalfedgeTo(secondVertex) == null) { List<TriMesh.Vertex> ringVertices = new List<TriMesh.Vertex>(); do { ringVertices.Add(dualMesh.Vertices[baryVertexIndex + faceIndex]); ringVertices.Add(dualMesh.Vertices[edgeVertexIndex]); if (tempHalfedge.Opposite.Next != null) { tempHalfedge = tempHalfedge.Opposite.Next; faceIndex = tempHalfedge.Face.Index; edgeVertexIndex = tempHalfedge.Edge.Index; } else { continue; } } while (tempHalfedge != halfedge1); TriMesh.Vertex[] newFaceVertices = new TriMesh.Vertex[ringVertices.Count]; for (int i = 0; i < ringVertices.Count; i++) { newFaceVertices[i] = ringVertices[i]; } dualMesh.Faces.Add(newFaceVertices); } tempHalfedge = halfedge2; edgeVertexIndex = halfedge2.Edge.Index; firstVertex = dualMesh.Vertices[baryVertexIndex + faceIndex]; secondVertex = dualMesh.Vertices[edgeVertexIndex]; if (firstVertex.FindHalfedgeTo(secondVertex) == null) { List<TriMesh.Vertex> ringVertices = new List<TriMesh.Vertex>(); do { ringVertices.Add(dualMesh.Vertices[baryVertexIndex + faceIndex]); ringVertices.Add(dualMesh.Vertices[edgeVertexIndex]); if (tempHalfedge.Opposite.Next != null) { tempHalfedge = tempHalfedge.Opposite.Next; faceIndex = tempHalfedge.Face.Index; edgeVertexIndex = tempHalfedge.Edge.Index; } else { continue; } } while (tempHalfedge != halfedge2); TriMesh.Vertex[] newFaceVertices = new TriMesh.Vertex[ringVertices.Count]; for (int i = 0; i < ringVertices.Count; i++) { newFaceVertices[i] = ringVertices[i]; } dualMesh.Faces.Add(newFaceVertices); } } }
TriMesh.Edge CreateNewEdge(TriMesh.Vertex from, TriMesh.Vertex to) { TriMesh mesh = (TriMesh)from.Mesh; // Create new edge TriMesh.Edge edge = new TriMesh.Edge(); mesh.AppendToEdgeList(edge); // Create new halfedges TriMesh.HalfEdge hf0 = new TriMesh.HalfEdge(); mesh.AppendToHalfedgeList(hf0); hf0.Opposite = new TriMesh.HalfEdge(); mesh.AppendToHalfedgeList(hf0.Opposite); // Connect opposite halfedge to inner halfedge hf0.Opposite.Opposite = hf0; // Connect edge to halfedges edge.HalfEdge0 = hf0; // Connect halfedges to edge hf0.Edge = edge; hf0.Opposite.Edge = edge; // Connect halfedges to vertices hf0.ToVertex = to; hf0.Opposite.ToVertex = from; // Connect vertex to outgoing halfedge if it doesn't have one yet if (from.HalfEdge == null) { from.HalfEdge = hf0; } return edge; }
/// <summary> /// Computes principle curvatures on the vertices. /// </summary> /// <param name="cornerArea">A halfedge dynamic trait with face vertex angular areas.</param> /// <param name="pointArea">A vertex dynamic trait with vertex angular areas.</param> /// <remarks> /// Portions of this method are based on code from the C++ trimesh2 library /// (from TriMesh_curvature.cc). /// </remarks> public void ComputePrincipleCurvatures(TriMesh mesh,TriMesh.HalfedgeDynamicTrait<float> cornerArea, TriMesh.VertexDynamicTrait<float> pointArea) { // Add dynamic trait for principle curvature computation TriMesh.VertexDynamicTrait<float> curv = new TriMesh.VertexDynamicTrait<float>(mesh); // Initialize principle curvatures to zero foreach (TriMesh.Vertex v in mesh.Vertices) { v.Traits.MaxCurvature = 0.0f; v.Traits.MinCurvature = 0.0f; } // Initialize a coordinate system for each vertex foreach (TriMesh.Vertex v in mesh.Vertices) { if (Math.Sqrt(v.Traits.Normal.Length()) > 0.0f) // Ignore isolated points { // Vector that points from this vertex to an adjacent one v.Traits.MaxCurvatureDirection = v.HalfEdge.ToVertex.Traits.Position - v.Traits.Position; v.Traits.MaxCurvatureDirection.Normalize(); // Get a vector orthogonal to this vector and the vertex normal v.Traits.MinCurvatureDirection = v.Traits.Normal.Cross(v.Traits.MaxCurvatureDirection); } } TriMesh.HalfEdge[] fh = new TriMesh.HalfEdge[3]; TriMesh.Vertex[] fv = new TriMesh.Vertex[3]; Vector3D[] e = new Vector3D[3]; Vector3D t, b, dn, faceNormal; // Compute curvature for each face foreach (TriMesh.Face f in mesh.Faces) { // Get halfedges for this face fh[0] = f.HalfEdge; fh[1] = fh[0].Next; fh[2] = fh[1].Next; // Get vertices for this face fv[0] = fh[0].ToVertex; fv[1] = fh[1].ToVertex; fv[2] = fh[2].ToVertex; // Edge vectors e[0] = fv[2].Traits.Position - fv[1].Traits.Position; e[1] = fv[0].Traits.Position - fv[2].Traits.Position; e[2] = fv[1].Traits.Position - fv[0].Traits.Position; t = e[0]; t.Normalize(); faceNormal = e[0].Cross(e[1]); faceNormal.Normalize(); b = faceNormal.Cross(t); b.Normalize(); // Estimate curvature by variation of normals along edges float[] m = new float[3]; float[,] w = new float[3, 3]; for (int i = 0; i < 3; ++i) { float u = (float)e[i].Dot(t); float v = (float)e[i].Dot(b); w[0, 0] += u * u; w[0, 1] += u * v; w[2, 2] += v * v; dn = fv[(i + 2) % 3].Traits.Normal - fv[(i + 1) % 3].Traits.Normal; float dnu = (float)dn.Dot(t); float dnv = (float)dn.Dot(b); m[0] += dnu * u; m[1] += dnu * v + dnv * u; m[2] += dnv * v; } w[1, 1] = w[0, 0] + w[2, 2]; w[1, 2] = w[0, 1]; // Least squares solution float[] diag = new float[3]; if (Curvature.LdlTransposeDecomp(w, diag)) { Curvature.LdlTransposeSolveInPlace(w, diag, m); // Adjust curvature for vertices of this face for (int i = 0; i < 3; ++i) { float c1, c12, c2; Curvature.ProjectCurvature(t, b, m[0], m[1], m[2], fv[i].Traits.MaxCurvatureDirection, fv[i].Traits.MinCurvatureDirection, out c1, out c12, out c2); float weight = cornerArea[fh[i]] / pointArea[fv[i]]; fv[i].Traits.MaxCurvature += weight * c1; curv[fv[i]] += weight * c12; fv[i].Traits.MinCurvature += weight * c2; } } } // Compute curvature for each vertex foreach (TriMesh.Vertex v in mesh.Vertices) { if (Math.Sqrt(v.Traits.Normal.Length()) > 0.0f) // Ignore isolated points { Curvature.DiagonalizeCurvature(v.Traits.MaxCurvatureDirection, v.Traits.MinCurvatureDirection, v.Traits.MaxCurvature, curv[v], v.Traits.MinCurvature, v.Traits.Normal, out v.Traits.MaxCurvatureDirection, out v.Traits.MinCurvatureDirection, out v.Traits.MaxCurvature, out v.Traits.MinCurvature); } } }
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; }
public static PrincipalCurvature[] ComputePrincipleCurvatures(TriMesh mesh, double[] CornerArea, double[] PointArea) { Vector3D[] vertexNormal = TriMeshUtil.ComputeNormalVertex(mesh); // Add dynamic trait for principle curvature computation double[] curv = new double[mesh.Vertices.Count]; PrincipalCurvature[] pc = new PrincipalCurvature[mesh.Vertices.Count]; // Initialize a coordinate system for each vertex foreach (TriMesh.Vertex v in mesh.Vertices) { pc[v.Index] = new PrincipalCurvature(); // Vector that points from this vertex to an adjacent one pc[v.Index].maxDir = (v.HalfEdge.ToVertex.Traits.Position - v.Traits.Position).Cross(vertexNormal[v.Index]).Normalize(); // Get a vector orthogonal to this vector and the vertex normal pc[v.Index].minDir = vertexNormal[v.Index].Cross(pc[v.Index].maxDir); } TriMesh.HalfEdge[] fh = new TriMesh.HalfEdge[3]; TriMesh.Vertex[] fv = new TriMesh.Vertex[3]; Vector3D[] e = new Vector3D[3]; Vector3D t, b, dn, faceNormal; // Compute curvature for each face foreach (TriMesh.Face f in mesh.Faces) { // Get halfedges for this face fh[0] = f.HalfEdge; fh[1] = fh[0].Next; fh[2] = fh[1].Next; // Get vertices for this face fv[0] = fh[0].ToVertex; fv[1] = fh[1].ToVertex; fv[2] = fh[2].ToVertex; // Edge vectors e[0] = fv[2].Traits.Position - fv[1].Traits.Position; e[1] = fv[0].Traits.Position - fv[2].Traits.Position; e[2] = fv[1].Traits.Position - fv[0].Traits.Position; t = e[0]; t.Normalize(); faceNormal = e[0].Cross(e[1]); faceNormal.Normalize(); b = faceNormal.Cross(t); b.Normalize(); // Estimate curvature by variation of normals along edges double[] m = new double[3]; double[,] w = new double[3, 3]; for (int i = 0; i < 3; ++i) { double u = e[i].Dot(t); double v = e[i].Dot(b); w[0, 0] += u * u; w[0, 1] += u * v; w[2, 2] += v * v; dn = vertexNormal[fv[(i + 2) % 3].Index] - vertexNormal[fv[(i + 1) % 3].Index]; double dnu = dn.Dot(t); double dnv = dn.Dot(b); m[0] += dnu * u; m[1] += dnu * v + dnv * u; m[2] += dnv * v; } w[1, 1] = w[0, 0] + w[2, 2]; w[1, 2] = w[0, 1]; // Least squares solution double[] diag = new double[3]; if (Transform.LdlTransposeDecomp(w, diag)) { Transform.LdlTransposeSolveInPlace(w, diag, m); // Adjust curvature for vertices of this face for (int i = 0; i < 3; ++i) { UV tb = new UV { U = t, V = b }; KUV mk = new KUV { U = m[0], UV = m[1], V = m[2] }; UV dst = new UV { U = pc[fv[i].Index].maxDir, V = pc[fv[i].Index].minDir }; KUV c = Transform.ProjectCurvature(tb, mk, dst); double weight = CornerArea[fh[i].Index] / PointArea[fv[i].Index]; pc[fv[i].Index].max += weight * c.U; curv[fv[i].Index] += weight * c.UV; pc[fv[i].Index].min += weight * c.V; } } } // Compute curvature for each vertex foreach (TriMesh.Vertex v in mesh.Vertices) { UV src = new UV { U = pc[v.Index].maxDir, V = pc[v.Index].minDir }; KUV srcK = new KUV { U = pc[v.Index].max, UV = curv[v.Index], V = pc[v.Index].min }; pc[v.Index] = Transform.DiagonalizeCurvature(src, srcK, vertexNormal[v.Index]); } return pc; }
public static Vector4D[] ComputeDCruv(TriMesh mesh, double[] CornerArea, double[] PointArea) { PrincipalCurvature[] PrincipalCurv = ComputePrincipleCurvatures(mesh, CornerArea, PointArea); Vector4D[] dcurv = new Vector4D[mesh.Vertices.Count]; TriMesh.HalfEdge[] fh = new TriMesh.HalfEdge[3]; TriMesh.Vertex[] fv = new TriMesh.Vertex[3]; Vector3D[] e = new Vector3D[3]; Vector3D t, b, faceNormal; // Compute curvature for each face foreach (TriMesh.Face f in mesh.Faces) { // Get halfedges for this face fh[0] = f.HalfEdge; fh[1] = fh[0].Next; fh[2] = fh[1].Next; // Get vertices for this face fv[0] = fh[0].ToVertex; fv[1] = fh[1].ToVertex; fv[2] = fh[2].ToVertex; // Edge vectors e[0] = fv[2].Traits.Position - fv[1].Traits.Position; e[1] = fv[0].Traits.Position - fv[2].Traits.Position; e[2] = fv[1].Traits.Position - fv[0].Traits.Position; t = e[0]; t.Normalize(); faceNormal = e[0].Cross(e[1]); b = faceNormal.Cross(t); b.Normalize(); KUV[] fcurv = new KUV[3]; for (int i = 0; i < 3; i++) { PrincipalCurvature pc = PrincipalCurv[fv[i].Index]; UV src = new UV { U = pc.maxDir, V = pc.minDir }; KUV mk = new KUV { U = pc.max, UV = 0, V = pc.min }; UV tb = new UV { U = t, V = b }; fcurv[i] = Transform.ProjectCurvature(src, mk, tb); } double[] m = new double[4]; double[,] w = new double[4, 4]; for (int i = 0; i < 3; i++) { KUV prev = fcurv[(i + 2) % 3]; KUV next = fcurv[(i + 1) % 3]; KUV dfcurv = new KUV { U = prev.U - next.U, UV = prev.UV - next.UV, V = prev.V - next.V }; double u = e[i].Dot(t); double v = e[i].Dot(b); w[0, 0] += u * u; w[0, 1] += u * v; w[3, 3] += v * v; m[0] += u * dfcurv.U; m[1] += v * dfcurv.U + 2d * u * dfcurv.UV; m[2] += 2d * v * dfcurv.UV + u * dfcurv.V; m[3] += v * dfcurv.V; } w[1, 1] = 2d * w[0, 0] + w[3, 3]; w[1, 2] = 2d * w[0, 1]; w[2, 2] = w[0, 0] + 2d * w[3, 3]; w[2, 3] = w[0, 1]; double[] diag = new double[4]; if (Transform.LdlTransposeDecomp(w, diag)) { Transform.LdlTransposeSolveInPlace(w, diag, m); Vector4D d = new Vector4D(m); // Adjust curvature for vertices of this face for (int i = 0; i < 3; ++i) { UV tb = new UV { U = t, V = b }; PrincipalCurvature pc = PrincipalCurv[fv[i].Index]; UV dst = new UV { U = pc.maxDir, V = pc.minDir }; Vector4D c = Transform.ProjectDCurvature(tb, d, dst); double weight = CornerArea[fh[i].Index] / PointArea[fv[i].Index]; dcurv[fv[i].Index] += weight * d; } } } return dcurv; }