double Mesh::ComputeVolume() const { const size_t nV = GetNPoints(); const size_t nT = GetNTriangles(); if (nV == 0 || nT == 0) { return 0.0; } Vec3<double> bary(0.0, 0.0, 0.0); for (size_t v = 0; v < nV; v++) { bary += GetPoint(v); } bary /= static_cast<double>(nV); Vec3<double> ver0, ver1, ver2; double totalVolume = 0.0; for(size_t t = 0; t < nT; t++) { const Vec3<int> & tri = GetTriangle(t); ver0 = GetPoint(tri[0]); ver1 = GetPoint(tri[1]); ver2 = GetPoint(tri[2]); totalVolume += ComputeVolume4(ver0, ver1, ver2, bary); } return totalVolume/6.0; }
bool ICHull::IsInside(const Vec3<double>& pt0, const double eps) { const Vec3<double> pt(pt0.X(), pt0.Y(), pt0.Z()); if (m_isFlat) { size_t nT = m_mesh.m_triangles.GetSize(); Vec3<double> ver0, ver1, ver2, a, b, c; double u, v; for (size_t t = 0; t < nT; t++) { ver0.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.X(); ver0.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Y(); ver0.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Z(); ver1.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.X(); ver1.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Y(); ver1.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Z(); ver2.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.X(); ver2.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Y(); ver2.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Z(); a = ver1 - ver0; b = ver2 - ver0; c = pt - ver0; u = c * a; v = c * b; if (u >= 0.0 && u <= 1.0 && v >= 0.0 && u + v <= 1.0) { return true; } m_mesh.m_triangles.Next(); } return false; } else { size_t nT = m_mesh.m_triangles.GetSize(); Vec3<double> ver0, ver1, ver2; double vol; for (size_t t = 0; t < nT; t++) { ver0.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.X(); ver0.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Y(); ver0.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Z(); ver1.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.X(); ver1.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Y(); ver1.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Z(); ver2.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.X(); ver2.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Y(); ver2.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Z(); vol = ComputeVolume4(ver0, ver1, ver2, pt); if (vol < eps) { return false; } m_mesh.m_triangles.Next(); } 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; }
bool Mesh::IsInside(const Vec3<double> & pt) const { const size_t nV = GetNPoints(); const size_t nT = GetNTriangles(); if (nV == 0 || nT == 0) { return false; } Vec3<double> ver0, ver1, ver2; double volume; for (size_t t = 0; t < nT; t++) { const Vec3<int> & tri = GetTriangle(t); ver0 = GetPoint(tri[0]); ver1 = GetPoint(tri[1]); ver2 = GetPoint(tri[2]); volume = ComputeVolume4(ver0, ver1, ver2, pt); if (volume < 0.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; }