public static float CalculateMinTriangleShape(BaseMesh mesh) { int faceCount = mesh.faceCount(); Vector3[] tr = new Vector3[3]; float minShape = 10.0f; for (int i = 0; i < faceCount; ++i) { Face f = mesh.faces[i]; if (f.valid) { for (int j = 0; j < 3; ++j) { tr[j] = mesh.vertices[f.v[j]].coords; } float val = KrablMesh.UnityUtils.TriangleCompactnessSqr(tr); if (val < minShape) { minShape = val; } } } return(minShape); }
bool _producesNonManifold(BaseMesh mesh, CollapseInfo ci) { // ... If v0 and v1 don't have nr of commonfaces common neighbours List <Vertex> vertices = mesh.vertices; List <Face> faces = mesh.faces; int common = commonFaces.Count; int tag = mesh.GetUniqueTag(); int count = faces0.Count; int[] faceArray = faces0.array; for (int i = 0; i < count; ++i) { int[] v = faces[faceArray[i]].v; // known to be a valid triangle vertices[v[0]].mark = tag; vertices[v[1]].mark = tag; vertices[v[2]].mark = tag; } count = faces1.Count; faceArray = faces1.array; for (int i = 0; i < count; ++i) { int[] v = faces[faceArray[i]].v; if (vertices[v[0]].mark == tag) { common--; if (common < 0) { return(true); } vertices[v[0]].mark = 0; } if (vertices[v[1]].mark == tag) { common--; if (common < 0) { return(true); } vertices[v[1]].mark = 0; } if (vertices[v[2]].mark == tag) { common--; if (common < 0) { return(true); } vertices[v[2]].mark = 0; } } return(common != 0); }
/* * NOT USED. the badtopology test is faster & better * * bool _producesInvertedFaces(BaseMesh mesh, CollapseInfo ci) { * Vector3[] tr = new Vector3[3]; * for (int k = 0; k < 2; ++k) { * int vindex = ci.vp.v[k]; * List<int> linkedFaces = (k == 0) ? faces0 : faces1; * for (int i = 0; i < linkedFaces.Count; ++i) { * Face f = mesh.faces[linkedFaces[i]]; * Vector3 oldN = mesh.CalculateFaceNormal(linkedFaces[i]); * if (f.v[0] == vindex) { tr[0] = ci.targetPosition; tr[1] = mesh.vertex(f.v[1]).coords; tr[2] = mesh.vertex(f.v[2]).coords; } * else if (f.v[1] == vindex) { tr[0] = mesh.vertex(f.v[0]).coords; tr[1] = ci.targetPosition; tr[2] = mesh.vertex(f.v[2]).coords; } * else { tr[0] = mesh.vertex(f.v[0]).coords; tr[1] = mesh.vertex(f.v[1]).coords; tr[2] = ci.targetPosition; } * Vector3 newN = Vector3.Cross(tr[1] - tr[0], tr[2] - tr[1]); * if (Vector3.Dot(oldN, newN) < 0.0f) { * return true; * } * } * } * return false; * }*/ float _determineMeshSize(BaseMesh mesh) { Vector3 min = mesh.vertices[0].coords; Vector3 max = min; int numVerts = mesh.vertCount(); for (int i = 0; i < numVerts; ++i) { Vector3 c = mesh.vertices[i].coords; if (c.x < min.x) { min.x = c.x; } else if (c.x > max.x) { max.x = c.x; } if (c.y < min.y) { min.y = c.y; } else if (c.y > max.y) { max.y = c.y; } if (c.z < min.z) { min.z = c.z; } else if (c.z > max.z) { max.z = c.z; } } max -= min; float result = max.x; if (max.y > meshSize) { meshSize = max.y; } if (max.z > meshSize) { meshSize = max.z; } return(result); }
//Vector3[] tr = new Vector3[3]; /* * // rchecks result triangles against limit * bool _producesSharpTriangles(Mesh mesh, CollapseInfo ci, float limitSqr) { * for (int k = 0; k < 2; ++k) { * int vindex = ci.vp.v[k]; * List<int> linkedFaces = (k == 0) ? faces0 : faces1; * for (int i = 0; i < linkedFaces.Count; ++i) { * Face f = mesh.faces[linkedFaces[i]]; * if (f.v[0] == vindex) { tr[0] = ci.targetPosition; tr[1] = mesh.vertex(f.v[1]).coords; tr[2] = mesh.vertex(f.v[2]).coords; } * else if (f.v[1] == vindex) { tr[0] = mesh.vertex(f.v[0]).coords; tr[1] = ci.targetPosition; tr[2] = mesh.vertex(f.v[2]).coords; } * else { tr[0] = mesh.vertex(f.v[0]).coords; tr[1] = mesh.vertex(f.v[1]).coords; tr[2] = ci.targetPosition; } * float val = UnityUtils.TriangleCompactnessSqr(tr); * if (val < limitSqr) return true; * } * } * return false; * } */ // Check topology to avoid flipping the mesh by collapsing bool _producesBadTopology(BaseMesh mesh, CollapseInfo ci, int filterTag = 0) { Vector3 p1, origPos, vOpp, faceNormal, normal; List <Vertex> vertices = mesh.vertices; List <Face> faces = mesh.faces; for (int k = 0; k < 2; ++k) { int vindex = ci.vp.v[k]; origPos = vertices[vindex].coords; IndexList linkedFacesList = (k == 0) ? faces0 : faces1; int[] linkedFaces = linkedFacesList.array; for (int i = 0; i < linkedFacesList.Count; ++i) { Face f = faces[linkedFaces[i]]; if (f.mark >= filterTag) { // Construct a plane from opposing sides (p1->p2) && the face normal -> todo make this better (faster) if (f.v[0] == vindex) { p1 = vertices[f.v[1]].coords; vOpp = vertices[f.v[2]].coords - p1; } else if (f.v[1] == vindex) { p1 = vertices[f.v[2]].coords; vOpp = vertices[f.v[0]].coords - p1; } else { p1 = vertices[f.v[0]].coords; vOpp = vertices[f.v[1]].coords - p1; } faceNormal = Vector3.Cross(vOpp, origPos - p1); // the face normal normal = Vector3.Cross(faceNormal, vOpp); // normal of constructed plane if (Vector3.Dot(ci.targetPosition - p1, normal) < 0.0f) { return(true); } } } } return(false); }
/// <summary> /// Joins vertices in a mesh that have the same geometric location based on the mesh's /// equalityTolerance parameter which is set when a mesh is create (it's usually zero.) /// </summary> /// <param name='mesh'> /// The mesh to search for duplicate vertices. /// </param> public static void RemoveDoubleVertices(BaseMesh mesh) { int numVerts = mesh.vertCount(); List <int> vertexOrder = new List <int>(numVerts); for (int i = 0; i < numVerts; ++i) { vertexOrder.Add(i); } vertexOrder.Sort(delegate(int a, int b) { return(mesh.CompareVertices(a, b, mesh.equalityTolerance)); }); int[] uniqueVertex = new int[numVerts]; int unique = vertexOrder[0]; uniqueVertex[unique] = unique; for (int i = 1; i < numVerts; ++i) { int vertexIndex = vertexOrder[i]; if (mesh.CompareVertices(unique, vertexIndex, mesh.equalityTolerance) != 0) { unique = vertexIndex; } uniqueVertex[vertexIndex] = unique; } // TODO: maybe use the center of all the almost equal vertices .. probably does not matter for (int i = 0; i < numVerts; ++i) { if (i != uniqueVertex[i]) { mesh.ReplaceVertex(i, uniqueVertex[i]); } } /* int num = */ mesh.InvalidateUnconnectedVertices(); //Debug.Log("RemoveDoubleVertices Invalidated " + num + " unconnected vertices."); /*num = */ mesh.InvalidateDegenerateFaces(); // Debug.Log("RemoveDoubleVertices Invalidated " + num + " degenerate faces."); }
public float cost; // Total cose including penalties public float Ratio(BaseMesh m) { return(KrablMesh.UnityUtils.ProjectedRatioOfPointOnVector(targetPosition, m.vertices[vp.v[0]].coords, m.vertices[vp.v[1]].coords)); }
public static void Triangulate(BaseMesh mesh) { if (mesh.topology == MeshTopology.Triangles) { return; } int faceIndex, cornerIndex; int numFaces = mesh.faceCount(); Vector3[] coords = new Vector3[4]; for (faceIndex = 0; faceIndex < numFaces; ++faceIndex) { Face f = mesh.faces[faceIndex]; if (f.valid && f.cornerCount == 4) { Face fnew = new Face(3); // copy face parameters fnew.material = f.material; for (cornerIndex = 0; cornerIndex < 4; ++cornerIndex) { coords[cornerIndex] = mesh.vertices[f.v[cornerIndex]].coords; } Vector3 diag02 = coords[0] - coords[2]; Vector3 diag13 = coords[1] - coords[3]; if (diag02.sqrMagnitude < diag13.sqrMagnitude) { // Create triangles 201 and 023 .. use diag as first edge as a hint fnew.CopyVertexInfoFromFace(f, 0, 0); fnew.CopyVertexInfoFromFace(f, 2, 1); fnew.CopyVertexInfoFromFace(f, 3, 2); } else { // Create triangles 312 and 013 .. use diag as first edge as a hint fnew.CopyVertexInfoFromFace(f, 3, 0); fnew.CopyVertexInfoFromFace(f, 1, 1); fnew.CopyVertexInfoFromFace(f, 2, 2); f.CopyVertexInfoFromFace(f, 3, 2); } mesh.AddFace(fnew); // First face needs to become a triangle f.cornerCount = 3; } } // Rebuild linkedFaces for Verts int numVerts = mesh.vertCount(); for (int vertIndex = 0; vertIndex < numVerts; ++vertIndex) { mesh.vertices[vertIndex].linkedFaces = new IndexList(18); } numFaces = mesh.faceCount(); for (faceIndex = 0; faceIndex < numFaces; ++faceIndex) { Face f = mesh.faces[faceIndex]; for (cornerIndex = 0; cornerIndex < f.cornerCount; ++cornerIndex) { mesh.vertices[f.v[cornerIndex]].linkedFaces.Add(faceIndex); } } mesh.topology = MeshTopology.Triangles; }
// Count number of surrounding faces after the collapse int _vertexDegreeAfterCollapse(BaseMesh mesh, CollapseInfo ci) { return(faces0.Count + faces1.Count); }