/// <summary> /// Creates a new mesh where no vertices are shared. /// </summary> /// <param name="input"> /// The input mesh. /// </param> /// <returns> /// A new mesh. /// </returns> public static MeshGeometry3D NoSharedVertices(this MeshGeometry3D input) { var p = new Point3DCollection(); var ti = new Int32Collection(); Vector3DCollection n = null; if (input.Normals != null) { n = new Vector3DCollection(); } PointCollection tc = null; if (input.TextureCoordinates != null) { tc = new PointCollection(); } for (int i = 0; i < input.TriangleIndices.Count; i += 3) { int i0 = i; int i1 = i + 1; int i2 = i + 2; int index0 = input.TriangleIndices[i0]; int index1 = input.TriangleIndices[i1]; int index2 = input.TriangleIndices[i2]; var p0 = input.Positions[index0]; var p1 = input.Positions[index1]; var p2 = input.Positions[index2]; p.Add(p0); p.Add(p1); p.Add(p2); ti.Add(i0); ti.Add(i1); ti.Add(i2); if (n != null) { n.Add(input.Normals[index0]); n.Add(input.Normals[index1]); n.Add(input.Normals[index2]); } if (tc != null) { tc.Add(input.TextureCoordinates[index0]); tc.Add(input.TextureCoordinates[index1]); tc.Add(input.TextureCoordinates[index2]); } } #if SHARPDX return(new MeshGeometry3D { Positions = p, TriangleIndices = new SharpDX.Core.IntCollection(ti), Normals = n, TextureCoordinates = tc }); #else return(new MeshGeometry3D { Positions = p, TriangleIndices = ti, Normals = n, TextureCoordinates = tc }); #endif }
/// <summary> /// Finds all edges in the mesh (each edge is only included once). /// </summary> /// <param name="mesh"> /// A mesh geometry. /// </param> /// <returns> /// The edge indices (minimum index first). /// </returns> public static Int32Collection FindEdges(this MeshGeometry3D mesh) { var edges = new Int32Collection(); var dict = new HashSet <ulong>(); for (int i = 0; i < mesh.TriangleIndices.Count / 3; i++) { int i0 = i * 3; for (int j = 0; j < 3; j++) { int index0 = mesh.TriangleIndices[i0 + j]; int index1 = mesh.TriangleIndices[i0 + ((j + 1) % 3)]; int minIndex = Math.Min(index0, index1); int maxIndex = Math.Max(index1, index0); ulong key = CreateKey((uint)minIndex, (uint)maxIndex); if (!dict.Contains(key)) { edges.Add(minIndex); edges.Add(maxIndex); dict.Add(key); } } } return(edges); }
/// <summary> /// /// </summary> /// <returns></returns> public MeshGeometry3D GetMesh() { var pos = new Point3DCollection(vertices.Select(x => new Point3D(x.p.X, x.p.Y, x.p.Z))); var tris = new Int32Collection(triangles.Count * 3); foreach (var tri in triangles) { tris.Add(tri.v[0]); tris.Add(tri.v[1]); tris.Add(tri.v[2]); } return(new MeshGeometry3D() { Positions = pos, TriangleIndices = tris }); }
/// <summary> /// Finds all edges where the angle between adjacent triangle normal vectors. /// is larger than minimumAngle /// </summary> /// <param name="mesh"> /// A mesh geometry. /// </param> /// <param name="minimumAngle"> /// The minimum angle between the normal vectors of two adjacent triangles (degrees). /// </param> /// <returns> /// The edge indices. /// </returns> public static Int32Collection FindSharpEdges(this MeshGeometry3D mesh, double minimumAngle) { var edgeIndices = new Int32Collection(); // the keys of the dictionary are created from the triangle indices of the edge var edgeNormals = new Dictionary <ulong, Vector3D>(); for (int i = 0; i < mesh.TriangleIndices.Count / 3; i++) { int i0 = i * 3; var p0 = mesh.Positions[mesh.TriangleIndices[i0]]; var p1 = mesh.Positions[mesh.TriangleIndices[i0 + 1]]; var p2 = mesh.Positions[mesh.TriangleIndices[i0 + 2]]; var p10 = p1 - p0; var p20 = p2 - p0; var n = SharedFunctions.CrossProduct(ref p10, ref p20); n.Normalize(); for (int j = 0; j < 3; j++) { int index0 = mesh.TriangleIndices[i0 + j]; int index1 = mesh.TriangleIndices[i0 + ((j + 1) % 3)]; int minIndex = Math.Min(index0, index1); int maxIndex = Math.Max(index0, index1); ulong key = CreateKey((uint)minIndex, (uint)maxIndex); Vector3D value; if (edgeNormals.TryGetValue(key, out value)) { var n2 = value; n2.Normalize(); var angle = 180 / (DoubleOrSingle)Math.PI * (DoubleOrSingle)Math.Acos(SharedFunctions.DotProduct(ref n, ref n2)); if (angle > minimumAngle) { edgeIndices.Add(minIndex); edgeIndices.Add(maxIndex); } } else { edgeNormals.Add(key, n); } } } return(edgeIndices); }
/// <summary> /// Simplifies the specified mesh. /// </summary> /// <param name="mesh"> /// The mesh. /// </param> /// <param name="eps"> /// The tolerance. /// </param> /// <returns> /// A simplified mesh. /// </returns> public static MeshGeometry3D Simplify(this MeshGeometry3D mesh, DoubleOrSingle eps) { // Find common positions var dict = new Dictionary <int, int>(); // map position index to first occurence of same position for (int i = 0; i < mesh.Positions.Count; i++) { for (int j = i + 1; j < mesh.Positions.Count; j++) { if (dict.ContainsKey(j)) { continue; } var v = mesh.Positions[i] - mesh.Positions[j]; var l2 = SharedFunctions.LengthSquared(ref v); if (l2 < eps) { dict.Add(j, i); } } } var p = new Point3DCollection(); var ti = new Int32Collection(); // create new positions array var newIndex = new Dictionary <int, int>(); // map old index to new index for (int i = 0; i < mesh.Positions.Count; i++) { if (!dict.ContainsKey(i)) { newIndex.Add(i, p.Count); p.Add(mesh.Positions[i]); } } // Update triangle indices foreach (int index in mesh.TriangleIndices) { int j; ti.Add(dict.TryGetValue(index, out j) ? newIndex[j] : newIndex[index]); } #if SHARPDX var result = new MeshGeometry3D { Positions = p, TriangleIndices = new SharpDX.Core.IntCollection(ti), }; #else var result = new MeshGeometry3D { Positions = p, TriangleIndices = ti }; #endif return(result); }
/// <summary> /// Finds edges that are only connected to one triangle. /// </summary> /// <param name="mesh"> /// A mesh geometry. /// </param> /// <returns> /// The edge indices for the edges that are only used by one triangle. /// </returns> public static Int32Collection FindBorderEdges(this MeshGeometry3D mesh) { var dict = new Dictionary <ulong, int>(); for (int i = 0; i < mesh.TriangleIndices.Count / 3; i++) { int i0 = i * 3; for (int j = 0; j < 3; j++) { int index0 = mesh.TriangleIndices[i0 + j]; int index1 = mesh.TriangleIndices[i0 + ((j + 1) % 3)]; int minIndex = Math.Min(index0, index1); int maxIndex = Math.Max(index1, index0); ulong key = CreateKey((uint)minIndex, (uint)maxIndex); if (dict.ContainsKey(key)) { dict[key] = dict[key] + 1; } else { dict.Add(key, 1); } } } var edges = new Int32Collection(); foreach (var kvp in dict) { // find edges only used by 1 triangle if (kvp.Value == 1) { uint i0, i1; ReverseKey(kvp.Key, out i0, out i1); edges.Add((int)i0); edges.Add((int)i1); } } return(edges); }