bool ICHull::CleanVertices(unsigned int& addedPoints) { // mark all vertices incident to some undeleted edge as on the hull CircularList<TMMEdge>& edges = m_mesh.GetEdges(); CircularListElement<TMMEdge>* e = edges.GetHead(); size_t nE = edges.GetSize(); for (size_t i = 0; i < nE; i++) { e->GetData().m_vertices[0]->GetData().m_onHull = true; e->GetData().m_vertices[1]->GetData().m_onHull = true; e = e->GetNext(); } // delete all the vertices that have been processed but are not on the hull CircularList<TMMVertex>& vertices = m_mesh.GetVertices(); CircularListElement<TMMVertex>* vHead = vertices.GetHead(); CircularListElement<TMMVertex>* v = vHead; v = v->GetPrev(); do { if (v->GetData().m_tag && !v->GetData().m_onHull) { CircularListElement<TMMVertex>* tmp = v->GetPrev(); vertices.Delete(v); v = tmp; addedPoints--; } else { v->GetData().m_duplicate = 0; v->GetData().m_onHull = false; v = v->GetPrev(); } } while (v->GetData().m_tag && v != vHead); return true; }
bool ICHull::ProcessPoint() { double totalVolume = 0.0; if (!ComputePointVolume(totalVolume, true)) { return false; } // Mark edges in interior of visible region for deletion. // Create a new face based on each border edge CircularListElement<TMMVertex>* v0 = m_mesh.GetVertices().GetHead(); CircularListElement<TMMEdge>* eHead = m_mesh.GetEdges().GetHead(); CircularListElement<TMMEdge>* e = eHead; CircularListElement<TMMEdge>* tmp = 0; int nvisible = 0; m_edgesToDelete.Resize(0); m_edgesToUpdate.Resize(0); do { tmp = e->GetNext(); nvisible = 0; for (int k = 0; k < 2; k++) { if (e->GetData().m_triangles[k]->GetData().m_visible) { nvisible++; } } if (nvisible == 2) { m_edgesToDelete.PushBack(e); } else if (nvisible == 1) { e->GetData().m_newFace = MakeConeFace(e, v0); m_edgesToUpdate.PushBack(e); } e = tmp; } while (e != eHead); return true; }
bool ICHull::FindMaxVolumePoint(const double minVolume) { CircularList<TMMVertex>& vertices = m_mesh.GetVertices(); CircularListElement<TMMVertex>* vMaxVolume = 0; CircularListElement<TMMVertex>* vHeadPrev = vertices.GetHead()->GetPrev(); double maxVolume = minVolume; double volume = 0.0; while (!vertices.GetData().m_tag) // not processed { if (ComputePointVolume(volume, false)) { if (maxVolume < volume) { maxVolume = volume; vMaxVolume = vertices.GetHead(); } vertices.Next(); } } CircularListElement<TMMVertex>* vHead = vHeadPrev->GetNext(); vertices.GetHead() = vHead; if (!vMaxVolume) { return false; } if (vMaxVolume != vHead) { Vec3<double> pos = vHead->GetData().m_pos; int id = vHead->GetData().m_name; vHead->GetData().m_pos = vMaxVolume->GetData().m_pos; vHead->GetData().m_name = vMaxVolume->GetData().m_name; vMaxVolume->GetData().m_pos = pos; vHead->GetData().m_name = id; } return true; }
bool ICHull::ComputePointVolume(double& totalVolume, bool markVisibleFaces) { // mark visible faces CircularListElement<TMMTriangle>* fHead = m_mesh.GetTriangles().GetHead(); CircularListElement<TMMTriangle>* f = fHead; CircularList<TMMVertex>& vertices = m_mesh.GetVertices(); CircularListElement<TMMVertex>* vertex0 = vertices.GetHead(); bool visible = false; Vec3<double> pos0 = Vec3<double>(vertex0->GetData().m_pos.X(), vertex0->GetData().m_pos.Y(), vertex0->GetData().m_pos.Z()); double vol = 0.0; totalVolume = 0.0; Vec3<double> ver0, ver1, ver2; do { ver0.X() = f->GetData().m_vertices[0]->GetData().m_pos.X(); ver0.Y() = f->GetData().m_vertices[0]->GetData().m_pos.Y(); ver0.Z() = f->GetData().m_vertices[0]->GetData().m_pos.Z(); ver1.X() = f->GetData().m_vertices[1]->GetData().m_pos.X(); ver1.Y() = f->GetData().m_vertices[1]->GetData().m_pos.Y(); ver1.Z() = f->GetData().m_vertices[1]->GetData().m_pos.Z(); ver2.X() = f->GetData().m_vertices[2]->GetData().m_pos.X(); ver2.Y() = f->GetData().m_vertices[2]->GetData().m_pos.Y(); ver2.Z() = f->GetData().m_vertices[2]->GetData().m_pos.Z(); vol = ComputeVolume4(ver0, ver1, ver2, pos0); if (vol < -sc_eps) { vol = fabs(vol); totalVolume += vol; if (markVisibleFaces) { f->GetData().m_visible = true; m_trianglesToDelete.PushBack(f); } visible = true; } f = f->GetNext(); } while (f != fHead); if (m_trianglesToDelete.Size() == m_mesh.m_triangles.GetSize()) { for (size_t i = 0; i < m_trianglesToDelete.Size(); i++) { m_trianglesToDelete[i]->GetData().m_visible = false; } visible = false; } // if no faces visible from p then p is inside the hull if (!visible && markVisibleFaces) { vertices.Delete(); m_trianglesToDelete.Resize(0); return false; } return true; }
ICHullError ICHull::DoubleTriangle() { // find three non colinear points m_isFlat = false; CircularList<TMMVertex>& vertices = m_mesh.GetVertices(); CircularListElement<TMMVertex>* v0 = vertices.GetHead(); while (Colinear(v0->GetData().m_pos, v0->GetNext()->GetData().m_pos, v0->GetNext()->GetNext()->GetData().m_pos)) { if ((v0 = v0->GetNext()) == vertices.GetHead()) { return ICHullErrorCoplanarPoints; } } CircularListElement<TMMVertex>* v1 = v0->GetNext(); CircularListElement<TMMVertex>* v2 = v1->GetNext(); // mark points as processed v0->GetData().m_tag = v1->GetData().m_tag = v2->GetData().m_tag = true; // create two triangles CircularListElement<TMMTriangle>* f0 = MakeFace(v0, v1, v2, 0); MakeFace(v2, v1, v0, f0); // find a fourth non-coplanar point to form tetrahedron CircularListElement<TMMVertex>* v3 = v2->GetNext(); vertices.GetHead() = v3; double vol = ComputeVolume4(v0->GetData().m_pos, v1->GetData().m_pos, v2->GetData().m_pos, v3->GetData().m_pos); while (fabs(vol) < sc_eps && !v3->GetNext()->GetData().m_tag) { v3 = v3->GetNext(); vol = ComputeVolume4(v0->GetData().m_pos, v1->GetData().m_pos, v2->GetData().m_pos, v3->GetData().m_pos); } if (fabs(vol) < sc_eps) { // compute the barycenter Vec3<double> bary(0.0, 0.0, 0.0); CircularListElement<TMMVertex>* vBary = v0; do { bary += vBary->GetData().m_pos; } while ((vBary = vBary->GetNext()) != v0); bary /= static_cast<double>(vertices.GetSize()); // 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(); // add dummy vertex placed at (bary + normal) vertices.GetHead() = v2; Vec3<double> newPt = bary + m_normal; AddPoint(newPt, sc_dummyIndex); m_isFlat = true; return ICHullErrorOK; } else if (v3 != vertices.GetHead()) { TMMVertex temp; temp.m_name = v3->GetData().m_name; temp.m_pos = v3->GetData().m_pos; v3->GetData().m_name = vertices.GetHead()->GetData().m_name; v3->GetData().m_pos = vertices.GetHead()->GetData().m_pos; vertices.GetHead()->GetData().m_name = temp.m_name; vertices.GetHead()->GetData().m_pos = temp.m_pos; } return ICHullErrorOK; }