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); } }
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 PrincipalCurvature ComputePrincipalCurvature(TriMesh.Vertex v) { Vector3D sum = Vector3D.Zero; Vector3D mid = v.Traits.Position; foreach (var hf in v.HalfEdges) { Vector3D buttom = hf.ToVertex.Traits.Position; Vector3D left = hf.Opposite.Next.ToVertex.Traits.Position; Vector3D right = hf.Next.ToVertex.Traits.Position; double cota = (mid - left).Dot(buttom - left) / (mid - left).Cross(buttom - left).Length(); double cotb = (mid - right).Dot(buttom - right) / (mid - right).Cross(buttom - right).Length(); sum += (cota + cotb) * (this.Normal[v.Index] - this.Normal[hf.ToVertex.Index]); } double mixedArea = TriMeshUtil.ComputeAreaMixed(v); Vector3D laplace = sum / mixedArea / 2d; double square = -laplace.Dot(this.Normal[v.Index]); double k = this.K[v.Index].Length(); double delta = -k * k + 2d * square; if (delta < 0d) { delta = 0d; } PrincipalCurvature pc = new PrincipalCurvature(); pc.max = (k + Math.Pow(delta, 0.5)) / 2d; pc.min = (k - Math.Pow(delta, 0.5)) / 2d; return(pc); }
public TriMesh CreateSquareSpoke(int length, int width) { TriMesh mesh = new TriMesh(); double x0 = -this.GridSizeX * length / 2d; double y0 = -this.GridSizeX * width / 2d; double z0 = 0; double d = this.GridSizeX / 2; int t = 4; TriMesh.Vertex[,] v = new TriMesh.Vertex[length + 1, width + 1]; for (int i = 0; i < length + 1; i++) { for (int j = 0; j < width + 1; j++) { double x = x0 + this.GridSizeX * i; double y = y0 + this.GridSizeX * j; int r = i % t == j % t ? i % t : 0; double z = z0 - (Math.Abs(r - t / 2) - t / 2) * d; v[i, j] = mesh.Vertices.Add(new VertexTraits(x, y, z)); } } for (int i = 0; i < length; i++) { for (int j = 0; j < width; j++) { mesh.Faces.AddTriangles(v[i, j], v[i + 1, j], v[i + 1, j + 1], v[i, j + 1]); } } TriMeshUtil.SetUpNormalVertex(mesh); return(mesh); }
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); } }
public TriMesh CreateSquare(int length, int width) { TriMesh mesh = new TriMesh(); double x0 = -this.GridSizeX * length / 2d; double y0 = -this.GridSizeX * width / 2d; double z0 = 0; double d = this.GridSizeX / 2; TriMesh.Vertex[,] v = new TriMesh.Vertex[length + 1, width + 1]; for (int i = 0; i < length + 1; i++) { for (int j = 0; j < width + 1; j++) { double x = x0 + this.GridSizeX * i; double y = y0 + this.GridSizeX * j; double z = i % 2 == 1 && j % 2 == 1 ? d : z0; v[i, j] = mesh.Vertices.Add(new VertexTraits(x, y, z)); } } for (int i = 0; i < length; i++) { for (int j = 0; j < width; j++) { mesh.Faces.AddTriangles(v[i, j], v[i + 1, j], v[i + 1, j + 1], v[i, j + 1]); } } TriMeshUtil.SetUpNormalVertex(mesh); return(mesh); }
public static void GrowByVertexArea(TriMesh mesh) { Queue <TriMesh.Vertex> queue = new Queue <HalfEdgeMesh.Vertex>(); double[] avgArea = new double[mesh.Vertices.Count]; foreach (var v in mesh.Vertices) { avgArea[v.Index] = TriMeshUtil.ComputeAreaOneRing(v); if (v.Traits.SelectedFlag != 0) { queue.Enqueue(v); } } double k = 0.896; while (queue.Count != 0) { TriMesh.Vertex center = queue.Dequeue(); foreach (var round in center.Vertices) { if (round.Traits.SelectedFlag == 0) { if (Math.Abs(avgArea[center.Index] - avgArea[round.Index]) < k * avgArea[center.Index]) { round.Traits.SelectedFlag = center.Traits.SelectedFlag; queue.Enqueue(round); } } } } }
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); }
public bool Forward() { if (this.index < this.method.Logs.Count) { EdgeContext ctx = this.method.Logs[this.index]; 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.Edge edge = left.FindEdgeTo(right); MergeEdge.Merge(edge, ctx.MidPos); index++; return(true); } else { int r = this.method.Run(this.Mesh.Faces.Count - 1); index += r; return(false); } }
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; }
/// <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); }
public TriMesh CreateSquare(int length, int width) { TriMesh mesh = new TriMesh(); double x0 = -this.GridSizeX * length / 2d; double y0 = -this.GridSizeX * width / 2d; double z0 = 0; double d = this.GridSizeX / 2; TriMesh.Vertex[,] v = new TriMesh.Vertex[length + 1, width + 1]; for (int i = 0; i < length + 1; i++) { for (int j = 0; j < width + 1; j++) { double x=x0 + this.GridSizeX * i; double y=y0 + this.GridSizeX * j; double z = i % 2 == 1 && j % 2 == 1 ? d : z0; v[i, j] = mesh.Vertices.Add(new VertexTraits(x, y, z)); } } for (int i = 0; i < length; i++) { for (int j = 0; j < width; j++) { mesh.Faces.AddTriangles(v[i, j], v[i + 1, j], v[i + 1, j + 1], v[i, j + 1]); } } TriMeshUtil.SetUpNormalVertex(mesh); return mesh; }
public static void RepaireHoleTwo(List <TriMesh.Vertex> hole) { TriMesh mesh = (TriMesh)hole[0].Mesh; Vector3D center = Vector3D.Zero; for (int i = 0; i < hole.Count; i++) { center += hole[i].Traits.Position; } center /= hole.Count; TriMesh.Vertex vertex = mesh.Vertices.Add(new VertexTraits(center)); if (hole.Count >= 3) { TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; for (int i = 0; i < hole.Count; i++) { faceVertices[0] = vertex; faceVertices[1] = hole[i]; faceVertices[2] = hole[(i + 1) % hole.Count]; mesh.Faces.AddTriangles(faceVertices); } } TriMeshUtil.FixIndex(mesh); }
public double Distance(TriMesh.Vertex c, TriMesh.Vertex d) //利用距离公式计算点到中心集的点的距离 { double average; average = Math.Sqrt(Math.Pow((c.Traits.Position.x - d.Traits.Position.x), 2) + Math.Pow((c.Traits.Position.y - d.Traits.Position.y), 2) + Math.Pow((c.Traits.Position.z - d.Traits.Position.z), 2)); return(average); }
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; } }
public static TriMesh Clone(TriMesh mesh) { TriMesh newMesh = new TriMesh(); for (int i = 0; i < mesh.Vertices.Count; i++) { VertexTraits traits = new VertexTraits(mesh.Vertices[i].Traits.Position.x, mesh.Vertices[i].Traits.Position.y, mesh.Vertices[i].Traits.Position.z); newMesh.Vertices.Add(traits); } TriMesh.Vertex[] faceVetices = new TriMesh.Vertex[3]; for (int i = 0; i < mesh.Faces.Count; i++) { int faceVertexIndex1 = mesh.Faces[i].GetVertex(0).Index; int faceVertexIndex2 = mesh.Faces[i].GetVertex(1).Index; int faceVertexIndex3 = mesh.Faces[i].GetVertex(2).Index; faceVetices[0] = newMesh.Vertices[faceVertexIndex1]; faceVetices[1] = newMesh.Vertices[faceVertexIndex2]; faceVetices[2] = newMesh.Vertices[faceVertexIndex3]; newMesh.Faces.AddTriangles(faceVetices); } newMesh.TrimExcess(); return newMesh; }
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 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 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); } }
protected override void BeforeMerge(TriMesh.Edge edge) { base.BeforeMerge(edge); TriMesh.Vertex v1 = edge.Vertex0; TriMesh.Vertex v2 = edge.Vertex1; vertexMatrix[v1] += vertexMatrix[v2]; }
private static double[] SimplifyComputePlane(TriMesh.Vertex vertexA, TriMesh.Vertex vertexB, TriMesh.Vertex vertexC) { double x1 = vertexA.Traits.Position.x; double x2 = vertexB.Traits.Position.x; double x3 = vertexC.Traits.Position.x; double y1 = vertexA.Traits.Position.y; double y2 = vertexB.Traits.Position.y; double y3 = vertexC.Traits.Position.y; double z1 = vertexA.Traits.Position.z; double z2 = vertexB.Traits.Position.z; double z3 = vertexC.Traits.Position.z; double[] plane = new double[4]; double a = (y2 - y1) * (z3 - z1) - (z2 - z1) * (y3 - y1); double b = (z2 - z1) * (x3 - x1) - (x2 - x1) * (z3 - z1); double c = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1); double M = Math.Sqrt(a * a + b * b + c * c); a = a / M; b = b / M; c = c / M; double d = -1 * (a * x1 + b * y1 + c * z1); plane[0] = a; plane[1] = b; plane[2] = c; plane[3] = d; return(plane); }
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 static TriMesh Clone(TriMesh mesh) { TriMesh newMesh = new TriMesh(); for (int i = 0; i < mesh.Vertices.Count; i++) { VertexTraits traits = new VertexTraits(mesh.Vertices[i].Traits.Position.x, mesh.Vertices[i].Traits.Position.y, mesh.Vertices[i].Traits.Position.z); newMesh.Vertices.Add(traits); } TriMesh.Vertex[] faceVetices = new TriMesh.Vertex[3]; for (int i = 0; i < mesh.Faces.Count; i++) { int faceVertexIndex1 = mesh.Faces[i].GetVertex(0).Index; int faceVertexIndex2 = mesh.Faces[i].GetVertex(1).Index; int faceVertexIndex3 = mesh.Faces[i].GetVertex(2).Index; faceVetices[0] = newMesh.Vertices[faceVertexIndex1]; faceVetices[1] = newMesh.Vertices[faceVertexIndex2]; faceVetices[2] = newMesh.Vertices[faceVertexIndex3]; newMesh.Faces.AddTriangles(faceVetices); } newMesh.TrimExcess(); return(newMesh); }
public static void RepaireHoleTwo(List<TriMesh.Vertex> hole) { TriMesh mesh = (TriMesh)hole[0].Mesh; Vector3D center = Vector3D.Zero; for (int i = 0; i < hole.Count; i++) { center += hole[i].Traits.Position; } center /= hole.Count; TriMesh.Vertex vertex = mesh.Vertices.Add(new VertexTraits(center)); if (hole.Count >= 3) { TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; for (int i = 0; i < hole.Count; i++) { faceVertices[0] = vertex; faceVertices[1] = hole[i]; faceVertices[2] = hole[(i + 1) % hole.Count]; mesh.Faces.AddTriangles(faceVertices); } } TriMeshUtil.FixIndex(mesh); }
public static void RemoveVertex(TriMesh.Vertex vertex) { TriMesh mesh = (TriMesh)vertex.Mesh; foreach (TriMesh.HalfEdge halfEdge in vertex.HalfEdges) { if (halfEdge.Next != null) { halfEdge.Next.Face = null; halfEdge.Opposite.Previous.Next = halfEdge.Next; halfEdge.Next.Previous = halfEdge.Opposite.Previous; } if (halfEdge.ToVertex.HalfEdge == halfEdge.Opposite) { halfEdge.ToVertex.HalfEdge = halfEdge.Next; } mesh.RemoveHalfedge(halfEdge.Opposite); mesh.RemoveHalfedge(halfEdge); } foreach (TriMesh.Face face in vertex.Faces) { mesh.RemoveFace(face); } foreach (TriMesh.Edge edge in vertex.Edges) { mesh.RemoveEdge(edge); } mesh.RemoveVertex(vertex); }
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 static TriMesh ToTriMesh(QuadMesh mesh) { TriMesh trimesh = new TriMesh(); for (int i = 0; i < mesh.Vertices.Count; i++) { Vector3D position = mesh.Vertices[i].Traits.Position; trimesh.Vertices.Add(new VertexTraits(position.x, position.y, position.z)); } foreach (QuadMesh.Face face in mesh.Faces) { int v0 = face.GetVertex(0).Index; int v1 = face.GetVertex(1).Index; int v2 = face.GetVertex(2).Index; int v3 = face.GetVertex(3).Index; TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = trimesh.Vertices[v0]; faceVertices[1] = trimesh.Vertices[v1]; faceVertices[2] = trimesh.Vertices[v2]; trimesh.Faces.AddTriangles(faceVertices); faceVertices[0] = trimesh.Vertices[v2]; faceVertices[1] = trimesh.Vertices[v3]; faceVertices[2] = trimesh.Vertices[v0]; trimesh.Faces.AddTriangles(faceVertices); } return(trimesh); }
public static void WriteToObjFile(string filePath, TriMesh mesh) { FileStream fs = new FileStream(filePath, FileMode.Create); StreamWriter sw = new StreamWriter(fs); sw.WriteLine("#Vertices:" + mesh.Vertices.Count); sw.WriteLine("#Faces:" + mesh.Faces.Count); foreach (TriMesh.Vertex item in mesh.Vertices) { sw.WriteLine("v {0} {1} {2}", item.Traits.Position.x, item.Traits.Position.y, item.Traits.Position.z); } sw.WriteLine(); foreach (TriMesh.Face item in mesh.Faces) { TriMesh.Vertex v1 = item.GetVertex(0); TriMesh.Vertex v2 = item.GetVertex(1); TriMesh.Vertex v3 = item.GetVertex(2); sw.WriteLine("f {0} {1} {2}", v1.Index + 1, v2.Index + 1, v3.Index + 1); } sw.Close(); fs.Close(); }
public static PrincipalCurvature ComputePricipalCurvature(TriMesh.Vertex v) { double mean = ComputeMeanCurvature(v); double gauss = ComputeGaussianCurvature(v); return(ComputePricipalCurvature(mean, gauss)); }
public TriMesh CreateCylinder(int length, int width, int height) { TriMesh mesh = new TriMesh(); double x0 = -this.GridSizeX * length / 2d; double y0 = -this.GridSizeY * width / 2d; double z0 = -this.GridSizeZ * height / 2d; TriMesh.Vertex[,] top = new TriMesh.Vertex[length + 1, width + 1]; TriMesh.Vertex[,] btm = new TriMesh.Vertex[length + 1, width + 1]; for (int i = 0; i < length + 1; i++) { for (int j = 0; j < width + 1; j++) { double x = x0 + this.GridSizeX * i; double y = y0 + this.GridSizeY * j; top[i, j] = mesh.Vertices.Add(new VertexTraits(x, y, -z0)); btm[i, j] = mesh.Vertices.Add(new VertexTraits(x, y, z0)); } } for (int i = 0; i < length; i++) { for (int j = 0; j < width; j++) { mesh.Faces.AddTriangles(top[i, j], top[i + 1, j], top[i + 1, j + 1], top[i, j + 1]); mesh.Faces.AddTriangles(btm[i, j], btm[i, j + 1], btm[i + 1, j + 1], btm[i + 1, j]); } } int round = (length + width) * 2; TriMesh.Vertex[,] side = new TriMesh.Vertex[round, height + 1]; int s = 0, t = 0; for (int i = 0; i < round; i++) { int ol = i < length ? 1 : i >= round / 2d && i < round - width ? -1 : 0; int ow = i >= round - width ? -1 : i >= length && i < round / 2d ? 1 : 0; Vector3D v = btm[s, t].Traits.Position; side[i, 0] = btm[s, t]; for (int j = 1; j < height; j++) { side[i, j] = mesh.Vertices.Add(new VertexTraits(v.x, v.y, z0 + this.GridSizeZ * j)); } side[i, height] = top[s, t]; s += ol; t += ow; } for (int i = 0; i < round; i++) { for (int j = 0; j < height; j++) { mesh.Faces.AddTriangles(side[i, j], side[(i + 1) % round, j], side[(i + 1) % round, j + 1], side[i, j + 1]); } } TriMeshUtil.SetUpNormalVertex(mesh); return(mesh); }
private static void BulidSphereFace(int v1, int v2, int v3, TriMesh mesh)//添加面 { TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = mesh.Vertices[v1]; faceVertices[1] = mesh.Vertices[v2]; faceVertices[2] = mesh.Vertices[v3]; TriMesh.Face[] addedFaces = mesh.Faces.AddTriangles(faceVertices); }
private void BulidBoneFace(int v1, int v2, int v3)//为正方形添加面 { TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = this.Vertices[v1]; faceVertices[1] = this.Vertices[v2]; faceVertices[2] = this.Vertices[v3]; TriMesh.Face[] addedFaces = this.Faces.AddTriangles(faceVertices); }
public static void ShowOneRingEdgeOfVertex(TriMesh.Vertex vertex) { foreach (TriMesh.HalfEdge neighbors in vertex.HalfEdges) { neighbors.Next.Edge.Traits.SelectedFlag = 10; neighbors.Next.Edge.Traits.Color = RetrieveResult.Instance.EdgeResult; } }
public static void ShowOneRingVertexOfVertex(TriMesh.Vertex vertex) { foreach (TriMesh.Vertex neighbors in vertex.Vertices) { neighbors.Traits.SelectedFlag = 8; neighbors.Traits.Color = RetrieveResult.Instance.VertexResult; } }
public TriMesh CreateCylinder(int length, int width, int height) { TriMesh mesh = new TriMesh(); double x0 = -this.GridSizeX * length / 2d; double y0 = -this.GridSizeY * width / 2d; double z0 = -this.GridSizeZ * height / 2d; TriMesh.Vertex[,] top = new TriMesh.Vertex[length + 1, width + 1]; TriMesh.Vertex[,] btm = new TriMesh.Vertex[length + 1, width + 1]; for (int i = 0; i < length + 1; i++) { for (int j = 0; j < width + 1; j++) { double x = x0 + this.GridSizeX * i; double y = y0 + this.GridSizeY * j; top[i, j] = mesh.Vertices.Add(new VertexTraits(x, y, -z0)); btm[i, j] = mesh.Vertices.Add(new VertexTraits(x, y, z0)); } } for (int i = 0; i < length; i++) { for (int j = 0; j < width; j++) { mesh.Faces.AddTriangles(top[i, j], top[i + 1, j], top[i + 1, j + 1], top[i, j + 1]); mesh.Faces.AddTriangles(btm[i, j], btm[i, j + 1], btm[i + 1, j + 1], btm[i + 1, j]); } } int round = (length + width) * 2; TriMesh.Vertex[,] side = new TriMesh.Vertex[round, height + 1]; int s = 0, t = 0; for (int i = 0; i < round; i++) { int ol = i < length ? 1 : i >= round / 2d && i < round - width ? -1 : 0; int ow = i >= round - width ? -1 : i >= length && i < round / 2d ? 1 : 0; Vector3D v = btm[s, t].Traits.Position; side[i, 0] = btm[s, t]; for (int j = 1; j < height; j++) { side[i, j] = mesh.Vertices.Add(new VertexTraits(v.x, v.y, z0 + this.GridSizeZ * j)); } side[i, height] = top[s, t]; s += ol; t += ow; } for (int i = 0; i < round; i++) { for (int j = 0; j < height; j++) { mesh.Faces.AddTriangles(side[i, j], side[(i + 1) % round, j], side[(i + 1) % round, j + 1], side[i, j + 1]); } } TriMeshUtil.SetUpNormalVertex(mesh); return mesh; }
public void ComputeGeometryB(PolygonMesh dualMesh) { TriMesh.Vertex[] edgeVertices = new TriMesh.Vertex[mesh.Faces.Count * 3]; foreach (TriMesh.Edge e in mesh.Edges) { Vector3D midVertex0 = TriMeshUtil.GetMidPoint(e); dualMesh.Vertices.Add(new VertexTraits(midVertex0.x, midVertex0.y, midVertex0.z)); } foreach (TriMesh.Face f in mesh.Faces) { Vector3D baryCenter = TriMeshUtil.GetMidPoint(f); dualMesh.Vertices.Add(new VertexTraits(baryCenter.x, baryCenter.y, baryCenter.z)); } }
public void CutHalfEdge(TriMesh.HalfEdge hf) { Vector3D p1 = hf.FromVertex.Traits.Position; Vector3D p2 = hf.ToVertex.Traits.Position; double d1 = TriMeshUtil.GetDistance(plane, p1); double d2 = TriMeshUtil.GetDistance(plane, p2); if (d1 < 0 && d2 > 0) { d1 = Math.Abs(d1); d2 = Math.Abs(d2); Vector3D pos = p1 + (p2 - p1) * d1 / (d1 + d2); TriMesh.Vertex v1 = new TriMesh.Vertex(new VertexTraits(pos)); this.mesh.AppendToVertexList(v1); TriMesh.Vertex v2 = new TriMesh.Vertex(new VertexTraits(pos)); this.mesh.AppendToVertexList(v2); this.cutPoint[hf.Index] = new CutPoint { Left = v1, Right = v2 }; } }
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; }
DenseMatrixQuaternion BuildOmega(DenseMatrixQuaternion lamda) { DenseMatrixQuaternion Omega = new DenseMatrixQuaternion(mesh.Vertices.Count, 1); TriMesh.Vertex[] index = new TriMesh.Vertex[3]; foreach (TriMesh.Face face in mesh.Faces) { index[0] = face.GetVertex(2); index[1] = face.GetVertex(0); index[2] = face.GetVertex(1); for (int i = 0; i < 3; i++) { Quaternion f0 = new Quaternion(index[(i + 0) % 3].Traits.Position, 0); Quaternion f1 = new Quaternion(index[(i + 1) % 3].Traits.Position, 0); Quaternion f2 = new Quaternion(index[(i + 2) % 3].Traits.Position, 0); //Setting Orientation Swap it TriMesh.Vertex aI = index[(i + 1) % 3]; TriMesh.Vertex bI = index[(i + 2) % 3]; if (aI.Index > bI.Index) { aI = index[(i + 2) % 3]; bI = index[(i + 1) % 3]; } Quaternion aLamda = lamda[aI.Index, 0]; Quaternion bLamda = lamda[bI.Index, 0]; Quaternion e = new Quaternion(bI.Traits.Position, 0) - new Quaternion(aI.Traits.Position, 0); Quaternion conj = aLamda.Conjugate(); Quaternion bconj = bLamda.Conjugate(); Quaternion partA = conj * e * aLamda; Quaternion eTilde = (1f / 3f) * partA + (1f / 6f) * aLamda.Conjugate() * e * bLamda + (1f / 6f) * bLamda.Conjugate() * e * aLamda + (1f / 3f) * bLamda.Conjugate() * e * bLamda; Vector3D u1 = index[(i + 1) % 3].Traits.Position - index[(i + 0) % 3].Traits.Position; Vector3D u2 = index[(i + 2) % 3].Traits.Position - index[(i + 0) % 3].Traits.Position; double cotAlpha = u1.Dot(u2) / u1.Cross(u2).Length(); Quaternion q = cotAlpha * eTilde / 2; Omega[aI.Index, 0] -= q; Omega[bI.Index, 0] += q; } } RemoveMean(ref Omega); return Omega; }
public static TriMesh ToTriMesh(QuadMesh mesh) { TriMesh trimesh = new TriMesh(); for (int i = 0; i < mesh.Vertices.Count; i++) { Vector3D position = mesh.Vertices[i].Traits.Position; trimesh.Vertices.Add(new VertexTraits(position.x, position.y, position.z)); } foreach (QuadMesh.Face face in mesh.Faces) { int v0 = face.GetVertex(0).Index; int v1 = face.GetVertex(1).Index; int v2 = face.GetVertex(2).Index; int v3 = face.GetVertex(3).Index; TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = trimesh.Vertices[v0]; faceVertices[1] = trimesh.Vertices[v1]; faceVertices[2] = trimesh.Vertices[v2]; trimesh.Faces.AddTriangles(faceVertices); faceVertices[0] = trimesh.Vertices[v2]; faceVertices[1] = trimesh.Vertices[v3]; faceVertices[2] = trimesh.Vertices[v0]; trimesh.Faces.AddTriangles(faceVertices); } return trimesh; }
private static void ProcessPlyLine(TriMesh mesh, string line, PlyFileProcessorState state) { // Trim out comments (allow comments trailing on a line) int commentStart = line.IndexOf("ply"); if (commentStart != -1) { line = line.Substring(0, commentStart); } // Tokenize line string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); // Process line based on the keyword used if (tokens.Length > 0) { int? v; float x, y, z; TriMesh.Vertex[] faceVertices; int?[] vt, vn; if (tokens[0] == "element" && tokens[1] == "vertex") { state.Vnum = Int32.Parse(tokens[2]); } else if (tokens[0] == "element" && tokens[1] == "face") { state.Fnum = Int32.Parse(tokens[2]); } else if (tokens[0] == "end_header") { state.startv = true; } else if (state.startv == true ) { x = Single.Parse(tokens[0]); y = Single.Parse(tokens[1]); z = Single.Parse(tokens[2]); double r = Single.Parse(tokens[3]); double g = Single.Parse(tokens[4]); double b = Single.Parse(tokens[5]); double nx = Single.Parse(tokens[6]); double ny = Single.Parse(tokens[7]); double nz = Single.Parse(tokens[8]); int sel = int.Parse(tokens[9]); double tx = Single.Parse(tokens[10]); double ty = Single.Parse(tokens[11]); TriMesh.Vertex vertex= mesh.Vertices.Add(new VertexTraits(x, y, z)); vertex.Traits.Color = new Color4(r, g, b); vertex.Traits.SelectedFlag = (byte)sel; vertex.Traits.UV.x = tx; vertex.Traits.UV.y = ty; state.countv += 1; if (state.countv == state.Vnum) { state.startf = true; state.startv = false; } } else if (state.startf == true) { int vCount = int.Parse(tokens[0]); faceVertices = new TriMesh.Vertex[vCount]; // Parse vertex/texture coordinate/normal indices for (int i = 0; i < faceVertices.Length; ++i) { //string[] vertexTokens = tokens[i + 1].Split("/".ToCharArray()); v = Int32.Parse(tokens[i + 1]); faceVertices[i] = mesh.Vertices[v.Value]; } TriMesh.Face[] addedFaces = mesh.Faces.AddTriangles(faceVertices); double r = Single.Parse(tokens[vCount+1]); double g = Single.Parse(tokens[vCount + 2]); double b = Single.Parse(tokens[vCount + 3]); int sel = int.Parse(tokens[vCount + 4]); //double vx = Single.Parse(tokens[vCount + 5]); //double vy = Single.Parse(tokens[vCount + 6]); addedFaces[0].Traits.SelectedFlag = (byte)sel; addedFaces[0].Traits.Color = new Color4(r, g, b); state.countf+= 1; if (state.countf== state.Fnum) { state.starte = true; state.startf = false; } } else if (state.starte == true) { int sel = int.Parse(tokens[0]); mesh.Edges[state.counte].Traits.SelectedFlag =(byte)sel; state.counte += 1; } } }
public TriMesh CreateSquareSpoke(int length, int width) { TriMesh mesh = new TriMesh(); double x0 = -this.GridSizeX * length / 2d; double y0 = -this.GridSizeX * width / 2d; double z0 = 0; double d = this.GridSizeX / 2; int t = 4; TriMesh.Vertex[,] v = new TriMesh.Vertex[length + 1, width + 1]; for (int i = 0; i < length + 1; i++) { for (int j = 0; j < width + 1; j++) { double x = x0 + this.GridSizeX * i; double y = y0 + this.GridSizeX * j; int r = i % t == j % t ? i % t : 0; double z = z0 - (Math.Abs(r - t / 2) - t / 2) * d; v[i, j] = mesh.Vertices.Add(new VertexTraits(x, y, z)); } } for (int i = 0; i < length; i++) { for (int j = 0; j < width; j++) { mesh.Faces.AddTriangles(v[i, j], v[i + 1, j], v[i + 1, j + 1], v[i, j + 1]); } } TriMeshUtil.SetUpNormalVertex(mesh); return mesh; }
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> /// Computes vertex normals. /// </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> public void ComputeFaceVertexNormals(TriMesh mesh, TriMesh.HalfedgeDynamicTrait<float> cornerArea, TriMesh.VertexDynamicTrait<float> pointArea) { TriMesh.FaceDynamicTrait<Vector3D> normal = new TriMesh.FaceDynamicTrait<Vector3D>(mesh); TriMesh.Vertex[] fv = new TriMesh.Vertex[3]; // Compute normal for each face foreach (TriMesh.Face f in mesh.Faces) { int i = 0; foreach (TriMesh.Vertex v in f.Vertices) { fv[i] = v; ++i; } // Compute normal for this face normal[f] = (fv[2].Traits.Position - fv[1].Traits.Position).Cross(fv[0].Traits.Position - fv[2].Traits.Position); normal[f] = normal[f].Normalize(); f.Traits.Normal = normal[f]; } // Compute normal for each vertex foreach (TriMesh.HalfEdge h in mesh.HalfEdges) { if (!h.OnBoundary) // Ignore halfedges that don't have a face { float weight = cornerArea[h] / pointArea[h.ToVertex]; h.ToVertex.Traits.Normal += weight * normal[h.Face]; } } // Normalize normals foreach (TriMesh.Vertex v in mesh.Vertices) { if (Math.Sqrt(v.Traits.Normal.Length()) > 0.0f) // Ignore isolated points { v.Traits.Normal.Normalize(); } } }
private static void ProcessOffLine(TriMesh mesh, string line, OffFileProcessorState state, ref bool ignoreFirstThreeNum) { // Trim out comments (allow comments trailing on a line) int commentStart = line.IndexOf("OFF"); if (commentStart != -1) { line = line.Substring(0, commentStart); } // Tokenize line string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); // Process line based on the keyword used if (tokens.Length > 0) { int? v; float x, y, z; TriMesh.Vertex[] faceVertices; int?[] vt, vn; if (tokens.Length == 3) { if (!ignoreFirstThreeNum) { x = Single.Parse(tokens[0]); y = Single.Parse(tokens[1]); z = Single.Parse(tokens[2]); mesh.Vertices.Add(new VertexTraits(x, y, z)); } ignoreFirstThreeNum = false; } else if (tokens.Length == 4 || tokens.Length == 5) { faceVertices = new TriMesh.Vertex[tokens.Length - 1]; vt = new int?[tokens.Length - 1]; vn = new int?[tokens.Length - 1]; // Parse vertex/texture coordinate/normal indices for (int i = 0; i < faceVertices.Length; ++i) { //string[] vertexTokens = tokens[i + 1].Split("/".ToCharArray()); v = Int32.Parse(tokens[i + 1]); faceVertices[i] = mesh.Vertices[v.Value]; } TriMesh.Face[] addedFaces = mesh.Faces.AddTriangles(faceVertices); // Set texture coordinates and normals if any are given for (int i = 0; i < faceVertices.Length; ++i) { TriMesh.HalfEdge faceVertex; if (vt[i].HasValue || vn[i].HasValue) { foreach (TriMesh.Face f in addedFaces) { faceVertex = f.FindHalfedgeTo(faceVertices[i]); if (faceVertex != null) // Make sure vertex belongs to face if triangularization is on { if (vt[i].HasValue) { faceVertex.Traits.TextureCoordinate = state.VertexTextureCoords[vt[i].Value - 1]; } if (vn[i].HasValue) { faceVertex.Traits.Normal = state.VertexNormals[vn[i].Value - 1]; } } } } } } } }
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); } } }
public void ComputeGeometryC(PolygonMesh dualMesh) { //get the mid-Vertex of each edges TriMesh.Vertex[] edgeVertices = new TriMesh.Vertex[mesh.Faces.Count * 3]; foreach (TriMesh.Edge e in mesh.Edges) { Vector3D midVertex0 = TriMeshUtil.GetMidPoint(e); dualMesh.Vertices.Add(new VertexTraits(midVertex0.x, midVertex0.y, midVertex0.z)); } //get circumcentre of each faces foreach (TriMesh.Face f in mesh.Faces) { TriMesh.Vertex vertex0 = f.GetVertex(0); TriMesh.Vertex vertex1 = f.GetVertex(1); TriMesh.Vertex vertex2 = f.GetVertex(2); Triangle triangle = new Triangle(vertex0.Traits.Position, vertex1.Traits.Position, vertex2.Traits.Position); Vector3D circumCenter = triangle.ComputeCircumCenter(); dualMesh.Vertices.Add(new VertexTraits(circumCenter.x, circumCenter.y, circumCenter.z)); } }
public static TriMesh ConvertToTriMesh(NonManifoldMesh mesh) { TriMesh triMesh = new GraphicResearchHuiZhao.TriMesh(); triMesh.Traits.HasFaceVertexNormals = true; triMesh.Traits.HasTextureCoordinates = true; if (mesh.VertexNormal == null) { triMesh.Traits.HasFaceVertexNormals = false; } else { triMesh.Traits.HasFaceVertexNormals = true; } if (mesh.TextextCoordinate == null) { triMesh.Traits.HasTextureCoordinates = false; } else { triMesh.Traits.HasTextureCoordinates = true; } int vertexCount = mesh.VertexCount; int faceCount = mesh.FaceCount; for (int i = 0; i < vertexCount; i++) { VertexTraits traits = new VertexTraits((float)mesh.VertexPos[i * 3], (float)mesh.VertexPos[i * 3 + 1], (float)mesh.VertexPos[i * 3 + 2]); triMesh.Vertices.Add(traits); } TriMesh.Vertex[] vertices = new TriMesh.Vertex[3]; for (int i = 0; i < faceCount; i++) { vertices[0] = triMesh.Vertices[mesh.FaceIndex[i * 3]]; vertices[1] = triMesh.Vertices[mesh.FaceIndex[i * 3 + 1]]; vertices[2] = triMesh.Vertices[mesh.FaceIndex[i * 3 + 2]]; triMesh.Faces.AddTriangles(vertices); } if (triMesh.Traits.HasTextureCoordinates) { TriMesh.HalfEdge faceVertex; foreach (TriMesh.Face face in triMesh.Faces) { foreach (TriMesh.Vertex vertex in face.Vertices) { faceVertex = face.FindHalfedgeTo(vertex); if (faceVertex != null) // Make sure vertex belongs to face if triangularization is on { faceVertex.Traits.TextureCoordinate = new Vector2D(mesh.TextextCoordinate[vertex.Index * 2], mesh.TextextCoordinate[vertex.Index * 2 + 1]); } } } } if (triMesh.Traits.HasFaceVertexNormals) { TriMesh.HalfEdge faceVertex; foreach (TriMesh.Face face in triMesh.Faces) { foreach (TriMesh.Vertex vertex in face.Vertices) { faceVertex = face.FindHalfedgeTo(vertex); if (faceVertex != null) // Make sure vertex belongs to face if triangularization is on { faceVertex.Traits.Normal = new Vector3D(mesh.FaceNormal, vertex.Index); } } } } //if (triMesh.Traits.HasTextureCoordinates) //{ // foreach (HalfEdgeMesh.TriMesh.Vertex vertex in triMesh.Vertices ) // { // vertex.Traits.TextureCoordinate = new Vector2d(mesh.TextextCoordinate[vertex.Index * 2], mesh.TextextCoordinate[vertex.Index * 2 + 1]); // } //} //if (triMesh.Traits.HasFaceVertexNormals) //{ // foreach (HalfEdgeMesh.TriMesh.Vertex vertex in triMesh.Vertices) // { // vertex.Traits.Normal = new Vector3d(mesh.FaceNormal, vertex.Index); // } //} return triMesh; }
/// <summary> /// Processes a line from an OBJ file. /// </summary> /// <param name="line">A line from an OBJ file.</param> /// <param name="state">An object that manages state between calls.</param> private static void ProcessObjLine(TriMesh mesh, string line, ObjFileProcessorState state) { // Trim out comments (allow comments trailing on a line) int commentStart = line.IndexOf('#'); if (commentStart != -1) { line = line.Substring(0, commentStart); } // Tokenize line string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries); // Process line based on the keyword used if (tokens.Length > 0) { int? v; float x, y, z; TriMesh.Vertex[] faceVertices; int?[] vt, vn; switch (tokens[0]) { case "v": // Vertex if (tokens.Length != 4) { throw new IOException("Vertices in the OBJ file must have 3 coordinates."); } x = Single.Parse(tokens[1]); y = Single.Parse(tokens[2]); z = Single.Parse(tokens[3]); mesh.Vertices.Add(new VertexTraits(x, y, z)); break; case "vt": // Vertex texture if (tokens.Length != 3 && tokens.Length != 4) { throw new IOException("Texture coordinates in the OBJ file must have 2 or 3 coordinates."); } x = Single.Parse(tokens[1]); y = Single.Parse(tokens[2]); state.VertexTextureCoords.Add(new Vector2D(x, y)); break; case "vn": // Vertex normal if (tokens.Length != 4) { throw new IOException("Vertex normals in the OBJ file must have 3 coordinates."); } x = Single.Parse(tokens[1]); y = Single.Parse(tokens[2]); z = Single.Parse(tokens[3]); state.VertexNormals.Add(new Vector3D(x, y, z)); break; case "f": // Face faceVertices = new TriMesh.Vertex[tokens.Length - 1]; vt = new int?[tokens.Length - 1]; vn = new int?[tokens.Length - 1]; // Parse vertex/texture coordinate/normal indices for (int i = 0; i < faceVertices.Length; ++i) { string[] vertexTokens = tokens[i + 1].Split("/".ToCharArray()); v = Int32.Parse(vertexTokens[0]); if (vertexTokens.Length > 1 && vertexTokens[1].Length > 0) { vt[i] = Int32.Parse(vertexTokens[1]); } else { mesh.Traits.HasTextureCoordinates = false; } if (vertexTokens.Length > 2 && vertexTokens[2].Length > 0) { vn[i] = Int32.Parse(vertexTokens[2]); } else { mesh.Traits.HasFaceVertexNormals = false; } faceVertices[i] = mesh.Vertices[v.Value - 1]; } try { TriMesh.Face[] addedFaces = mesh.Faces.AddTriangles(faceVertices); // Set texture coordinates and normals if any are given for (int i = 0; i < faceVertices.Length; ++i) { TriMesh.HalfEdge faceVertex; if (vt[i].HasValue || vn[i].HasValue) { foreach (TriMesh.Face f in addedFaces) { faceVertex = f.FindHalfedgeTo(faceVertices[i]); if (faceVertex != null) // Make sure vertex belongs to face if triangularization is on { if (vt[i].HasValue) { faceVertex.Traits.TextureCoordinate = state.VertexTextureCoords[vt[i].Value - 1]; } if (vn[i].HasValue) { faceVertex.Traits.Normal = state.VertexNormals[vn[i].Value - 1]; } } } } } } catch { } break; } } }
public static void RepairHole(TriMesh mesh) { List<TriMesh.Vertex> hole = new List<TriMesh.Vertex>(); hole = TriMeshUtil.RetrieveBoundarySingle(mesh); TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; for (int i = 0; i < hole.Count - 2; i++) { faceVertices[0] = mesh.Vertices[hole[0].Index]; faceVertices[1] = mesh.Vertices[hole[i + 1].Index]; faceVertices[2] = mesh.Vertices[hole[i + 2].Index]; mesh.Faces.AddTriangles(faceVertices); } TriMeshUtil.FixIndex(mesh); }
public static void RepairComplexHole(TriMesh mesh) { List<TriMesh.Vertex> hole = new List<TriMesh.Vertex>(); TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; while (true)//此循环只限单洞修补 { //计算边界边的平均值 #region 计算边界边的平均值 hole = TriMeshUtil.RetrieveBoundarySingle(mesh); double aver_l = 0; double[] edgeLength = new double[hole.Count]; for (int i = 0; i < hole.Count; i++) { if (i == hole.Count - 1) { edgeLength[i] = Math.Sqrt(Math.Pow(hole[i].Traits.Position.x - hole[0].Traits.Position.x, 2) + Math.Pow(hole[i].Traits.Position.y - hole[0].Traits.Position.y, 2) + Math.Pow(hole[i].Traits.Position.z - hole[0].Traits.Position.z, 2)); break; } edgeLength[i] = Math.Sqrt(Math.Pow(hole[i].Traits.Position.x - hole[i + 1].Traits.Position.x, 2) + Math.Pow(hole[i].Traits.Position.y - hole[i + 1].Traits.Position.y, 2) + Math.Pow(hole[i].Traits.Position.z - hole[i + 1].Traits.Position.z, 2)); } for (int i = 0; i < hole.Count; i++) { aver_l += edgeLength[i]; } aver_l = aver_l / hole.Count; #endregion hole = TriMeshUtil.RetrieveBoundarySingle(mesh); //计算角度值 #region 计算角度值 double[] angle = new double[hole.Count]; double a = 0, b = 0, c = 0; for (int i = 0; i < hole.Count; i++) { if (i == 0) { a = Math.Sqrt(Math.Pow(hole[hole.Count - 1].Traits.Position.x - hole[i + 1].Traits.Position.x, 2) + Math.Pow(hole[hole.Count - 1].Traits.Position.y - hole[i + 1].Traits.Position.y, 2) + Math.Pow(hole[hole.Count - 1].Traits.Position.z - hole[i + 1].Traits.Position.z, 2)); b = Math.Sqrt(Math.Pow(hole[i].Traits.Position.x - hole[i + 1].Traits.Position.x, 2) + Math.Pow(hole[i].Traits.Position.y - hole[i + 1].Traits.Position.y, 2) + Math.Pow(hole[i].Traits.Position.z - hole[i + 1].Traits.Position.z, 2)); c = Math.Sqrt(Math.Pow(hole[hole.Count - 1].Traits.Position.x - hole[i].Traits.Position.x, 2) + Math.Pow(hole[hole.Count - 1].Traits.Position.y - hole[i].Traits.Position.y, 2) + Math.Pow(hole[hole.Count - 1].Traits.Position.z - hole[i].Traits.Position.z, 2)); angle[i] = Math.Acos((b * b + c * c - a * a) / (2 * b * c)); } else if (i == hole.Count - 1) { a = Math.Sqrt(Math.Pow(hole[i - 1].Traits.Position.x - hole[0].Traits.Position.x, 2) + Math.Pow(hole[i - 1].Traits.Position.y - hole[0].Traits.Position.y, 2) + Math.Pow(hole[i - 1].Traits.Position.z - hole[0].Traits.Position.z, 2)); b = Math.Sqrt(Math.Pow(hole[i].Traits.Position.x - hole[0].Traits.Position.x, 2) + Math.Pow(hole[i].Traits.Position.y - hole[0].Traits.Position.y, 2) + Math.Pow(hole[i].Traits.Position.z - hole[0].Traits.Position.z, 2)); c = Math.Sqrt(Math.Pow(hole[i - 1].Traits.Position.x - hole[i].Traits.Position.x, 2) + Math.Pow(hole[i - 1].Traits.Position.y - hole[i].Traits.Position.y, 2) + Math.Pow(hole[i - 1].Traits.Position.z - hole[i].Traits.Position.z, 2)); angle[i] = Math.Acos((b * b + c * c - a * a) / (2 * b * c)); } else { a = Math.Sqrt(Math.Pow(hole[i - 1].Traits.Position.x - hole[i + 1].Traits.Position.x, 2) + Math.Pow(hole[i - 1].Traits.Position.y - hole[i + 1].Traits.Position.y, 2) + Math.Pow(hole[i - 1].Traits.Position.z - hole[i + 1].Traits.Position.z, 2)); b = Math.Sqrt(Math.Pow(hole[i].Traits.Position.x - hole[i + 1].Traits.Position.x, 2) + Math.Pow(hole[i].Traits.Position.y - hole[i + 1].Traits.Position.y, 2) + Math.Pow(hole[i].Traits.Position.z - hole[i + 1].Traits.Position.z, 2)); c = Math.Sqrt(Math.Pow(hole[i - 1].Traits.Position.x - hole[i].Traits.Position.x, 2) + Math.Pow(hole[i - 1].Traits.Position.y - hole[i].Traits.Position.y, 2) + Math.Pow(hole[i - 1].Traits.Position.z - hole[i].Traits.Position.z, 2)); angle[i] = Math.Acos((b * b + c * c - a * a) / (2 * b * c)); } } #endregion //取得最小的角度 #region 取得最小的角度 int min = 0; for (int i = 0; i < hole.Count - 1; i++) { if (angle[i] < angle[i + 1]) min = i; else min = i + 1; } #endregion //求最小角度对应的边长 #region 求最小角度对应的边长 double temp = 0; if (min == hole.Count - 1) { temp = Math.Sqrt(Math.Pow(hole[min - 1].Traits.Position.x - hole[0].Traits.Position.x, 2) + Math.Pow(hole[min - 1].Traits.Position.y - hole[0].Traits.Position.y, 2) + Math.Pow(hole[min - 1].Traits.Position.z - hole[0].Traits.Position.z, 2)); } else if (min == 0) { temp = Math.Sqrt(Math.Pow(hole[hole.Count - 1].Traits.Position.x - hole[min + 1].Traits.Position.x, 2) + Math.Pow(hole[hole.Count - 1].Traits.Position.y - hole[min + 1].Traits.Position.y, 2) + Math.Pow(hole[hole.Count - 1].Traits.Position.z - hole[min + 1].Traits.Position.z, 2)); } else { temp = Math.Sqrt(Math.Pow(hole[min - 1].Traits.Position.x - hole[min + 1].Traits.Position.x, 2) + Math.Pow(hole[min - 1].Traits.Position.y - hole[min + 1].Traits.Position.y, 2) + Math.Pow(hole[min - 1].Traits.Position.z - hole[min + 1].Traits.Position.z, 2)); } #endregion //判断最小角对应的边与平均边界边长,并进行修补 #region 判断最小角对应的边与平均边界边长,并进行修补 if (temp > aver_l) { if (min == hole.Count - 1) { faceVertices[0] = mesh.Vertices[hole[min].Index]; faceVertices[1] = mesh.Vertices[hole[0].Index]; faceVertices[2] = mesh.Vertices[hole[min - 1].Index]; mesh.Faces.AddTriangles(faceVertices); } else if (min == 0) { faceVertices[0] = mesh.Vertices[hole[min].Index]; faceVertices[1] = mesh.Vertices[hole[min + 1].Index]; faceVertices[2] = mesh.Vertices[hole[hole.Count - 1].Index]; mesh.Faces.AddTriangles(faceVertices); } else { faceVertices[0] = mesh.Vertices[hole[min].Index]; faceVertices[1] = mesh.Vertices[hole[min + 1].Index]; faceVertices[2] = mesh.Vertices[hole[min - 1].Index]; mesh.Faces.AddTriangles(faceVertices); } } else { if (min == hole.Count - 1) { Vector3D midPosition; midPosition = (hole[min - 1].Traits.Position + hole[0].Traits.Position) / 2; mesh.Vertices.Add(new VertexTraits(midPosition.x, midPosition.y, midPosition.z)); faceVertices[0] = mesh.Vertices[hole[min].Index]; faceVertices[1] = mesh.Vertices[mesh.Vertices.Count - 1]; faceVertices[2] = mesh.Vertices[hole[min - 1].Index]; mesh.Faces.AddTriangles(faceVertices); faceVertices[0] = mesh.Vertices[hole[min].Index]; faceVertices[1] = mesh.Vertices[hole[0].Index]; faceVertices[2] = mesh.Vertices[mesh.Vertices.Count - 1]; mesh.Faces.AddTriangles(faceVertices); } else if (min == 0) { Vector3D midPosition; midPosition = (hole[hole.Count - 1].Traits.Position + hole[min + 1].Traits.Position) / 2; mesh.Vertices.Add(new VertexTraits(midPosition.x, midPosition.y, midPosition.z)); faceVertices[0] = mesh.Vertices[hole[min].Index]; faceVertices[1] = mesh.Vertices[mesh.Vertices.Count - 1]; faceVertices[2] = mesh.Vertices[hole[hole.Count - 1].Index]; mesh.Faces.AddTriangles(faceVertices); faceVertices[0] = mesh.Vertices[hole[min].Index]; faceVertices[1] = mesh.Vertices[hole[min + 1].Index]; faceVertices[2] = mesh.Vertices[mesh.Vertices.Count - 1]; mesh.Faces.AddTriangles(faceVertices); } else { Vector3D midPosition; midPosition = (hole[min - 1].Traits.Position + hole[min + 1].Traits.Position) / 2; mesh.Vertices.Add(new VertexTraits(midPosition.x, midPosition.y, midPosition.z)); faceVertices[0] = mesh.Vertices[hole[min].Index]; faceVertices[1] = mesh.Vertices[mesh.Vertices.Count - 1]; faceVertices[2] = mesh.Vertices[hole[min - 1].Index]; mesh.Faces.AddTriangles(faceVertices); faceVertices[0] = mesh.Vertices[hole[min].Index]; faceVertices[1] = mesh.Vertices[hole[min + 1].Index]; faceVertices[2] = mesh.Vertices[mesh.Vertices.Count - 1]; mesh.Faces.AddTriangles(faceVertices); } } #endregion //更新边界点,并判断空洞是否完整 #region 更新边界点,并判断空洞是否完整 TriMeshUtil.FixIndex(mesh); hole = TriMeshUtil.RetrieveBoundarySingle(mesh); if (hole.Count < 3) break; #endregion } }
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; }
public TriMesh CreateMesh() { TriMesh mesh = new TriMesh(); mesh.Vertices.Add(new VertexTraits(this.A)); mesh.Vertices.Add(new VertexTraits(this.B)); mesh.Vertices.Add(new VertexTraits(this.C)); TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = mesh.Vertices[0]; faceVertices[1] = mesh.Vertices[1]; faceVertices[2] = mesh.Vertices[2]; mesh.Faces.AddTriangles(faceVertices); return mesh; }
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 TriMesh.Vertex VertexSplit(TriMesh.Vertex v1, TriMesh.Vertex share1, TriMesh.Vertex share2, Vector3D v1Position, Vector3D v2Position, int fixedIndex) { TriMesh.HalfEdge[] hfs = FindGroup(v1, share1, share2); TriMesh mesh = (TriMesh)v1.Mesh; v1.Traits.Position = v1Position; v1.HalfEdge = hfs[0]; TriMesh.Vertex v2 = new TriMesh.Vertex(); v2.Traits = new VertexTraits(v2Position); v2.Traits.FixedIndex = fixedIndex; v2.HalfEdge = hfs[1]; mesh.AppendToVertexList(v2); for (int i = 0; i < hfs.Length - 1; i++) { hfs[i].Opposite.ToVertex = v2; } TriMesh.HalfEdge[] triangle1 = AddInnerTriangle(mesh, v1, v2, share1); InsertEdge(mesh, triangle1[1], hfs[0]); TriMesh.HalfEdge[] triangle2 = AddInnerTriangle(mesh, v2, v1, share2); InsertEdge(mesh, triangle2[1], hfs[hfs.Length - 1]); TriMesh.Edge edge = new TriMesh.Edge(); edge.HalfEdge0 = triangle1[0]; triangle1[0].Edge = edge; triangle2[0].Edge = edge; triangle1[0].Opposite = triangle2[0]; triangle2[0].Opposite = triangle1[0]; mesh.AppendToEdgeList(edge); return v2; }
private static void BulidSphereFace(int v1, int v2, int v3,TriMesh mesh)//添加面 { TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = mesh.Vertices[v1]; faceVertices[1] = mesh.Vertices[v2]; faceVertices[2] = mesh.Vertices[v3]; TriMesh.Face[] addedFaces = mesh.Faces.AddTriangles(faceVertices); }
/// <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 static TriMesh CreateSquare() { double length = 0.5; double width = 0.3; TriMesh Shape = new TriMesh(); Shape.Vertices.Add(new VertexTraits(-width, -length, 0)); Shape.Vertices.Add(new VertexTraits(width, -length, 0)); Shape.Vertices.Add(new VertexTraits(-width, length, 0)); Shape.Vertices.Add(new VertexTraits(width, length, 0)); TriMesh.Vertex[] faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = Shape.Vertices[0]; faceVertices[1] = Shape.Vertices[1]; faceVertices[2] = Shape.Vertices[2]; CreateFace(Shape,faceVertices); faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = Shape.Vertices[1]; faceVertices[1] = Shape.Vertices[3]; faceVertices[2] = Shape.Vertices[2]; CreateFace(Shape, faceVertices); faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = Shape.Vertices[2]; faceVertices[1] = Shape.Vertices[3]; faceVertices[2] = Shape.Vertices[0]; CreateFace(Shape, faceVertices); faceVertices = new TriMesh.Vertex[3]; faceVertices[0] = Shape.Vertices[3]; faceVertices[1] = Shape.Vertices[1]; faceVertices[2] = Shape.Vertices[0]; CreateFace(Shape, faceVertices); return Shape; }