ICHullError ICHull::Process() { unsigned int addedPoints = 0; if (m_mesh.GetNVertices() < 3) { return ICHullErrorNotEnoughPoints; } if (m_mesh.GetNVertices() == 3) { m_isFlat = true; CircularListElement<TMMTriangle>* t1 = m_mesh.AddTriangle(); CircularListElement<TMMTriangle>* t2 = m_mesh.AddTriangle(); CircularListElement<TMMVertex>* v0 = m_mesh.m_vertices.GetHead(); CircularListElement<TMMVertex>* v1 = v0->GetNext(); CircularListElement<TMMVertex>* v2 = v1->GetNext(); // Compute the normal to the plane Vec3<double> p0 = v0->GetData().m_pos; Vec3<double> p1 = v1->GetData().m_pos; Vec3<double> p2 = v2->GetData().m_pos; m_normal = (p1 - p0) ^ (p2 - p0); m_normal.Normalize(); t1->GetData().m_vertices[0] = v0; t1->GetData().m_vertices[1] = v1; t1->GetData().m_vertices[2] = v2; t2->GetData().m_vertices[0] = v1; t2->GetData().m_vertices[1] = v2; t2->GetData().m_vertices[2] = v2; return ICHullErrorOK; } if (m_isFlat) { m_mesh.m_edges.Clear(); m_mesh.m_triangles.Clear(); m_isFlat = false; } if (m_mesh.GetNTriangles() == 0) // we have to create the first polyhedron { ICHullError res = DoubleTriangle(); if (res != ICHullErrorOK) { return res; } else { addedPoints += 3; } } CircularList<TMMVertex>& vertices = m_mesh.GetVertices(); // go to the first added and not processed vertex while (!(vertices.GetHead()->GetPrev()->GetData().m_tag)) { vertices.Prev(); } while (!vertices.GetData().m_tag) // not processed { vertices.GetData().m_tag = true; if (ProcessPoint()) { addedPoints++; CleanUp(addedPoints); vertices.Next(); if (!GetMesh().CheckConsistancy()) { size_t nV = m_mesh.GetNVertices(); CircularList<TMMVertex>& vertices = m_mesh.GetVertices(); for (size_t v = 0; v < nV; ++v) { if (vertices.GetData().m_name == sc_dummyIndex) { vertices.Delete(); break; } vertices.Next(); } return ICHullErrorInconsistent; } } } if (m_isFlat) { SArray<CircularListElement<TMMTriangle>*> trianglesToDuplicate; size_t nT = m_mesh.GetNTriangles(); for (size_t f = 0; f < nT; f++) { TMMTriangle& currentTriangle = m_mesh.m_triangles.GetHead()->GetData(); if (currentTriangle.m_vertices[0]->GetData().m_name == sc_dummyIndex || currentTriangle.m_vertices[1]->GetData().m_name == sc_dummyIndex || currentTriangle.m_vertices[2]->GetData().m_name == sc_dummyIndex) { m_trianglesToDelete.PushBack(m_mesh.m_triangles.GetHead()); for (int k = 0; k < 3; k++) { for (int h = 0; h < 2; h++) { if (currentTriangle.m_edges[k]->GetData().m_triangles[h] == m_mesh.m_triangles.GetHead()) { currentTriangle.m_edges[k]->GetData().m_triangles[h] = 0; break; } } } } else { trianglesToDuplicate.PushBack(m_mesh.m_triangles.GetHead()); } m_mesh.m_triangles.Next(); } size_t nE = m_mesh.GetNEdges(); for (size_t e = 0; e < nE; e++) { TMMEdge& currentEdge = m_mesh.m_edges.GetHead()->GetData(); if (currentEdge.m_triangles[0] == 0 && currentEdge.m_triangles[1] == 0) { m_edgesToDelete.PushBack(m_mesh.m_edges.GetHead()); } m_mesh.m_edges.Next(); } size_t nV = m_mesh.GetNVertices(); CircularList<TMMVertex>& vertices = m_mesh.GetVertices(); for (size_t v = 0; v < nV; ++v) { if (vertices.GetData().m_name == sc_dummyIndex) { vertices.Delete(); } else { vertices.GetData().m_tag = false; vertices.Next(); } } CleanEdges(); CleanTriangles(); CircularListElement<TMMTriangle>* newTriangle; for (size_t t = 0; t < trianglesToDuplicate.Size(); t++) { newTriangle = m_mesh.AddTriangle(); newTriangle->GetData().m_vertices[0] = trianglesToDuplicate[t]->GetData().m_vertices[1]; newTriangle->GetData().m_vertices[1] = trianglesToDuplicate[t]->GetData().m_vertices[0]; newTriangle->GetData().m_vertices[2] = trianglesToDuplicate[t]->GetData().m_vertices[2]; } } return ICHullErrorOK; }
double MeshDecimator::ComputeEdgeCost(long v1, long v2, Vec3<Float> & newPos) const { double Q[10]; double M[12]; Vec3<double> pos; for(int i = 0; i < 10; ++i) Q[i] = m_vertices[v1].m_Q[i] + m_vertices[v2].m_Q[i]; M[0] = Q[0]; // (0, 0) M[1] = Q[1]; // (0, 1) M[2] = Q[2]; // (0, 2) M[3] = Q[3]; // (0, 3) M[4] = Q[1]; // (1, 0) M[5] = Q[4]; // (1, 1) M[6] = Q[5]; // (1, 2) M[7] = Q[6]; // (1, 3) M[8] = Q[2]; // (2, 0) M[9] = Q[5]; // (2, 1) M[10] = Q[7]; // (2, 2); M[11] = Q[8]; // (2, 3); double det = M[0] * M[5] * M[10] + M[1] * M[6] * M[8] + M[2] * M[4] * M[9] - M[0] * M[6] * M[9] - M[1] * M[4] * M[10]- M[2] * M[5] * M[8]; if (det != 0.0) { double d = 1.0 / det; pos.X() = d * (M[1]*M[7]*M[10] + M[2]*M[5]*M[11] + M[3]*M[6]*M[9] -M[1]*M[6]*M[11] - M[2]*M[7]*M[9] - M[3]*M[5]*M[10]); pos.Y() = d * (M[0]*M[6]*M[11] + M[2]*M[7]*M[8] + M[3]*M[4]*M[10] -M[0]*M[7]*M[10] - M[2]*M[4]*M[11] - M[3]*M[6]*M[8]); pos.Z() = d * (M[0]*M[7]*M[9] + M[1]*M[4]*M[11] + M[3]*M[5]*M[8] -M[0]*M[5]*M[11] - M[1]*M[7]*M[8] - M[3]*M[4]*M[9]); newPos.X() = static_cast<Float>(pos.X()); newPos.Y() = static_cast<Float>(pos.Y()); newPos.Z() = static_cast<Float>(pos.Z()); } else { const Float w = static_cast<Float>(0.5f); newPos = w * m_points[v1] + w * m_points[v2]; pos.X() = static_cast<double>(newPos.X()); pos.Y() = static_cast<double>(newPos.Y()); pos.Z() = static_cast<double>(newPos.Z()); } double qem = pos.X() * (Q[0] * pos.X() + Q[1] * pos.Y() + Q[2] * pos.Z() + Q[3]) + pos.Y() * (Q[1] * pos.X() + Q[4] * pos.Y() + Q[5] * pos.Z() + Q[6]) + pos.Z() * (Q[2] * pos.X() + Q[5] * pos.Y() + Q[7] * pos.Z() + Q[8]) + (Q[3] * pos.X() + Q[6] * pos.Y() + Q[8] * pos.Z() + Q[9]) ; Vec3<Float> d1; Vec3<Float> d2; Vec3<Float> n1; Vec3<Float> n2; Vec3<Float> oldPosV1 = m_points[v1]; Vec3<Float> oldPosV2 = m_points[v2]; SArray<long, SARRAY_DEFAULT_MIN_SIZE> triangles = m_vertices[v1].m_triangles; long idTriangle; for(size_t itT = 0; itT < m_vertices[v2].m_triangles.Size(); ++itT) { idTriangle = m_vertices[v2].m_triangles[itT]; triangles.Insert(idTriangle); } long a[3]; for(size_t itT = 0; itT != triangles.Size(); ++itT) { idTriangle = triangles[itT]; a[0] = m_triangles[idTriangle].X(); a[1] = m_triangles[idTriangle].Y(); a[2] = m_triangles[idTriangle].Z(); d1 = m_points[a[1]] - m_points[a[0]]; d2 = m_points[a[2]] - m_points[a[0]]; n1 = d1^d2; m_points[v1] = newPos; m_points[v2] = newPos; d1 = m_points[a[1]] - m_points[a[0]]; d2 = m_points[a[2]] - m_points[a[0]]; n2 = d1^d2; m_points[v1] = oldPosV1; m_points[v2] = oldPosV2; n1.Normalize(); n2.Normalize(); if (n1*n2 < 0.0) { return std::numeric_limits<double>::max(); } } if ( m_ecolManifoldConstraint && !ManifoldConstraint(v1, v2)) { return std::numeric_limits<double>::max(); } return qem; }
bool MeshDecimator::EdgeCollapse(double & qem) { MDEdgePriorityQueue currentEdge; long v1, v2; bool done = false; do { done = false; if (m_pqueue.size() == 0) { done = true; break; } else { currentEdge = m_pqueue.top(); m_pqueue.pop(); } } while ( (!m_edges[currentEdge.m_name].m_tag) || (m_edges[currentEdge.m_name].m_qem != currentEdge.m_qem)); if (done) return false; v1 = m_edges[currentEdge.m_name].m_v1; v2 = m_edges[currentEdge.m_name].m_v2; qem = currentEdge.m_qem; EdgeCollapse(v1, v2); m_points[v1] = m_edges[currentEdge.m_name].m_pos ; for(int k = 0; k < 10; k++) m_vertices[v1].m_Q[k] += m_vertices[v2].m_Q[k]; // Update priority queue long idEdge; long a, b; SArray<long, SARRAY_DEFAULT_MIN_SIZE> incidentVertices; for(size_t itE = 0; itE < m_vertices[v1].m_edges.Size(); ++itE) { idEdge = m_vertices[v1].m_edges[itE]; a = m_edges[idEdge].m_v1; b = m_edges[idEdge].m_v2; incidentVertices.PushBack((a != v1)?a:b); MDEdgePriorityQueue pqEdge; pqEdge.m_qem = m_edges[idEdge].m_qem = ComputeEdgeCost(a, b, m_edges[idEdge].m_pos); pqEdge.m_name = idEdge; m_pqueue.push(pqEdge); } long idVertex; for(size_t itV = 0; itV< incidentVertices.Size(); ++itV) { idVertex = incidentVertices[itV]; for(size_t itE = 0; itE < m_vertices[idVertex].m_edges.Size(); ++itE) { idEdge = m_vertices[idVertex].m_edges[itE]; a = m_edges[idEdge].m_v1; b = m_edges[idEdge].m_v2; if ( a!=v1 && b!=v1) { MDEdgePriorityQueue pqEdge; pqEdge.m_qem = m_edges[idEdge].m_qem = ComputeEdgeCost(a, b, m_edges[idEdge].m_pos); pqEdge.m_name = idEdge; m_pqueue.push(pqEdge); } } } return true; }
void MeshDecimator::EdgeCollapse(long v1, long v2) { long u, w; int shift; long idTriangle; for(size_t itT = 0; itT < m_vertices[v2].m_triangles.Size(); ++itT) { idTriangle = m_vertices[v2].m_triangles[itT]; if (m_triangles[idTriangle].X() == v2) { shift = 0; u = m_triangles[idTriangle].Y(); w = m_triangles[idTriangle].Z(); } else if (m_triangles[idTriangle].Y() == v2) { shift = 1; u = m_triangles[idTriangle].X(); w = m_triangles[idTriangle].Z(); } else { shift = 2; u = m_triangles[idTriangle].X(); w = m_triangles[idTriangle].Y(); } if ((u == v1) || (w == v1)) { m_trianglesTags[idTriangle] = false; m_vertices[u].m_triangles.Erase(idTriangle); m_vertices[w].m_triangles.Erase(idTriangle); m_nTriangles--; } else if (GetTriangle(v1, u, w) == -1) { m_vertices[v1].m_triangles.Insert(idTriangle); m_triangles[idTriangle][shift] = v1; } else { m_trianglesTags[idTriangle] = false; m_vertices[u].m_triangles.Erase(idTriangle); m_vertices[w].m_triangles.Erase(idTriangle); m_nTriangles--; } } long idEdge = 0; for(size_t itE = 0; itE < m_vertices[v2].m_edges.Size(); ++itE) { idEdge = m_vertices[v2].m_edges[itE]; w = (m_edges[idEdge].m_v1 == v2)? m_edges[idEdge].m_v2 : m_edges[idEdge].m_v1; if (w==v1) { m_edges[idEdge].m_tag = false; m_vertices[w].m_edges.Erase(idEdge); m_nEdges--; } else if ( GetEdge(v1, w) == -1) { if (m_edges[idEdge].m_v1 == v2) m_edges[idEdge].m_v1 = v1; else m_edges[idEdge].m_v2 = v1; m_vertices[v1].m_edges.Insert(idEdge); } else { m_edges[idEdge].m_tag = false; m_vertices[w].m_edges.Erase(idEdge); m_nEdges--; } } m_vertices[v2].m_tag = false; m_nVertices--; // update boundary edges SArray<long, 64> incidentVertices; incidentVertices.PushBack(v1); for(size_t itE = 0; itE < m_vertices[v1].m_edges.Size(); ++itE) { incidentVertices.PushBack((m_edges[idEdge].m_v1!= v1)?m_edges[idEdge].m_v1:m_edges[idEdge].m_v2); idEdge = m_vertices[v1].m_edges[itE]; m_edges[idEdge].m_onBoundary = (IsBoundaryEdge(m_edges[idEdge].m_v1, m_edges[idEdge].m_v2) != -1); } // update boundary vertices long idVertex; for(size_t itV = 0; itV < incidentVertices.Size(); ++itV) { idVertex = incidentVertices[itV]; m_vertices[idVertex].m_onBoundary = false; for(size_t itE = 0; itE < m_vertices[idVertex].m_edges.Size(); ++itE) { idEdge = m_vertices[idVertex].m_edges[itE]; if (m_edges[idEdge].m_onBoundary) { m_vertices[idVertex].m_onBoundary = true; break; } } } }