| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| |
|
| | #include <algorithm>
|
| | #include <boost/core/ignore_unused.hpp>
|
| | #include <cmath>
|
| | #include <limits>
|
| | #include <queue>
|
| | #include <utility>
|
| |
|
| |
|
| | #include <Base/Console.h>
|
| | #include <Mod/Mesh/App/WildMagic4/Wm4MeshCurvature.h>
|
| |
|
| | #include "Evaluation.h"
|
| | #include "Iterator.h"
|
| | #include "MeshKernel.h"
|
| | #include "TopoAlgorithm.h"
|
| | #include "Triangulation.h"
|
| |
|
| |
|
| | using namespace MeshCore;
|
| |
|
| | MeshTopoAlgorithm::MeshTopoAlgorithm(MeshKernel& rclM)
|
| | : _rclMesh(rclM)
|
| | {}
|
| |
|
| | MeshTopoAlgorithm::~MeshTopoAlgorithm()
|
| | {
|
| | if (_needsCleanup) {
|
| | Cleanup();
|
| | }
|
| | EndCache();
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::InsertVertex(FacetIndex ulFacetPos, const Base::Vector3f& rclPoint)
|
| | {
|
| | MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
|
| | MeshFacet clNewFacet1, clNewFacet2;
|
| |
|
| |
|
| | PointIndex ulPtCnt = _rclMesh._aclPointArray.size();
|
| | PointIndex ulPtInd = this->GetOrAddIndex(rclPoint);
|
| | FacetIndex ulSize = _rclMesh._aclFacetArray.size();
|
| |
|
| | if (ulPtInd < ulPtCnt) {
|
| | return false;
|
| |
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| | clNewFacet1._aulPoints[0] = rclF._aulPoints[1];
|
| | clNewFacet1._aulPoints[1] = rclF._aulPoints[2];
|
| | clNewFacet1._aulPoints[2] = ulPtInd;
|
| | clNewFacet1._aulNeighbours[0] = rclF._aulNeighbours[1];
|
| | clNewFacet1._aulNeighbours[1] = ulSize + 1;
|
| | clNewFacet1._aulNeighbours[2] = ulFacetPos;
|
| |
|
| | clNewFacet2._aulPoints[0] = rclF._aulPoints[2];
|
| | clNewFacet2._aulPoints[1] = rclF._aulPoints[0];
|
| | clNewFacet2._aulPoints[2] = ulPtInd;
|
| | clNewFacet2._aulNeighbours[0] = rclF._aulNeighbours[2];
|
| | clNewFacet2._aulNeighbours[1] = ulFacetPos;
|
| | clNewFacet2._aulNeighbours[2] = ulSize;
|
| |
|
| | if (rclF._aulNeighbours[1] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclF._aulNeighbours[1]].ReplaceNeighbour(ulFacetPos, ulSize);
|
| | }
|
| | if (rclF._aulNeighbours[2] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclF._aulNeighbours[2]].ReplaceNeighbour(ulFacetPos, ulSize + 1);
|
| | }
|
| |
|
| | rclF._aulPoints[2] = ulPtInd;
|
| | rclF._aulNeighbours[1] = ulSize;
|
| | rclF._aulNeighbours[2] = ulSize + 1;
|
| |
|
| |
|
| | _rclMesh._aclFacetArray.push_back(clNewFacet1);
|
| | _rclMesh._aclFacetArray.push_back(clNewFacet2);
|
| |
|
| | return true;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::SnapVertex(FacetIndex ulFacetPos, const Base::Vector3f& rP)
|
| | {
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[ulFacetPos];
|
| | if (!rFace.HasOpenEdge()) {
|
| | return false;
|
| | }
|
| | Base::Vector3f cNo1 = _rclMesh.GetNormal(rFace);
|
| | for (unsigned short i = 0; i < 3; i++) {
|
| | if (rFace._aulNeighbours[i] == FACET_INDEX_MAX) {
|
| | const Base::Vector3f& rPt1 = _rclMesh._aclPointArray[rFace._aulPoints[i]];
|
| | const Base::Vector3f& rPt2 = _rclMesh._aclPointArray[rFace._aulPoints[(i + 1) % 3]];
|
| | Base::Vector3f cNo2 = (rPt2 - rPt1) % cNo1;
|
| | Base::Vector3f cNo3 = (rP - rPt1) % (rPt2 - rPt1);
|
| | float fD2 = Base::DistanceP2(rPt1, rPt2);
|
| | float fTV = (rP - rPt1) * (rPt2 - rPt1);
|
| |
|
| |
|
| | if (cNo3.Length() < std::numeric_limits<float>::epsilon()) {
|
| | return SplitOpenEdge(ulFacetPos, i, rP);
|
| | }
|
| | if ((rP - rPt1) * cNo2 > 0.0F && fD2 >= fTV && fTV >= 0.0F) {
|
| | MeshFacet cTria;
|
| | cTria._aulPoints[0] = this->GetOrAddIndex(rP);
|
| | cTria._aulPoints[1] = rFace._aulPoints[(i + 1) % 3];
|
| | cTria._aulPoints[2] = rFace._aulPoints[i];
|
| | cTria._aulNeighbours[1] = ulFacetPos;
|
| | rFace._aulNeighbours[i] = _rclMesh.CountFacets();
|
| | _rclMesh._aclFacetArray.push_back(cTria);
|
| | return true;
|
| | }
|
| | }
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::OptimizeTopology(float fMaxAngle)
|
| | {
|
| |
|
| |
|
| | std::map<std::pair<PointIndex, PointIndex>, std::vector<FacetIndex>> aEdge2Face;
|
| | for (auto pI = _rclMesh._aclFacetArray.begin(); pI != _rclMesh._aclFacetArray.end(); ++pI) {
|
| | for (int i = 0; i < 3; i++) {
|
| |
|
| | if (pI->_aulNeighbours[i] != FACET_INDEX_MAX) {
|
| | PointIndex ulPt0 = std::min<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]);
|
| | PointIndex ulPt1 = std::max<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]);
|
| | aEdge2Face[std::pair<PointIndex, PointIndex>(ulPt0, ulPt1)].push_back(
|
| | pI - _rclMesh._aclFacetArray.begin()
|
| | );
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | std::list<std::pair<PointIndex, PointIndex>> aEdgeList;
|
| | std::map<std::pair<PointIndex, PointIndex>, std::vector<FacetIndex>>::iterator pE;
|
| | for (pE = aEdge2Face.begin(); pE != aEdge2Face.end(); ++pE) {
|
| | if (pE->second.size() == 2) {
|
| | aEdgeList.push_back(pE->first);
|
| | }
|
| | }
|
| |
|
| |
|
| | unsigned long uMaxIter = 5 * aEdge2Face.size();
|
| |
|
| |
|
| | while (!aEdgeList.empty() && uMaxIter > 0) {
|
| |
|
| | std::pair<PointIndex, PointIndex> aEdge = aEdgeList.front();
|
| | aEdgeList.pop_front();
|
| | uMaxIter--;
|
| |
|
| |
|
| | pE = aEdge2Face.find(aEdge);
|
| |
|
| |
|
| | if (pE == aEdge2Face.end()) {
|
| | continue;
|
| | }
|
| |
|
| |
|
| | if (!ShouldSwapEdge(pE->second[0], pE->second[1], fMaxAngle)) {
|
| | continue;
|
| | }
|
| |
|
| |
|
| | if ( true) {
|
| |
|
| | SwapEdge(pE->second[0], pE->second[1]);
|
| |
|
| | MeshFacet& rF1 = _rclMesh._aclFacetArray[pE->second[0]];
|
| | MeshFacet& rF2 = _rclMesh._aclFacetArray[pE->second[1]];
|
| | unsigned short side1 = rF1.Side(aEdge.first, aEdge.second);
|
| | unsigned short side2 = rF2.Side(aEdge.first, aEdge.second);
|
| |
|
| |
|
| | for (int i = 0; i < 3; i++) {
|
| | std::map<std::pair<PointIndex, PointIndex>, std::vector<FacetIndex>>::iterator it;
|
| |
|
| | PointIndex ulPt0 = std::min<PointIndex>(rF1._aulPoints[i], rF1._aulPoints[(i + 1) % 3]);
|
| | PointIndex ulPt1 = std::max<PointIndex>(rF1._aulPoints[i], rF1._aulPoints[(i + 1) % 3]);
|
| | it = aEdge2Face.find(std::make_pair(ulPt0, ulPt1));
|
| | if (it != aEdge2Face.end()) {
|
| | if (it->second[0] == pE->second[1]) {
|
| | it->second[0] = pE->second[0];
|
| | }
|
| | else if (it->second[1] == pE->second[1]) {
|
| | it->second[1] = pE->second[0];
|
| | }
|
| | aEdgeList.push_back(it->first);
|
| | }
|
| |
|
| |
|
| | ulPt0 = std::min<PointIndex>(rF2._aulPoints[i], rF2._aulPoints[(i + 1) % 3]);
|
| | ulPt1 = std::max<PointIndex>(rF2._aulPoints[i], rF2._aulPoints[(i + 1) % 3]);
|
| | it = aEdge2Face.find(std::make_pair(ulPt0, ulPt1));
|
| | if (it != aEdge2Face.end()) {
|
| | if (it->second[0] == pE->second[0]) {
|
| | it->second[0] = pE->second[1];
|
| | }
|
| | else if (it->second[1] == pE->second[0]) {
|
| | it->second[1] = pE->second[1];
|
| | }
|
| | aEdgeList.push_back(it->first);
|
| | }
|
| | }
|
| |
|
| |
|
| | PointIndex ulPt0 = std::min<PointIndex>(
|
| | rF1._aulPoints[(side1 + 1) % 3],
|
| | rF2._aulPoints[(side2 + 1) % 3]
|
| | );
|
| | PointIndex ulPt1 = std::max<PointIndex>(
|
| | rF1._aulPoints[(side1 + 1) % 3],
|
| | rF2._aulPoints[(side2 + 1) % 3]
|
| | );
|
| | std::pair<PointIndex, PointIndex> aNewEdge = std::make_pair(ulPt0, ulPt1);
|
| | aEdge2Face[aNewEdge] = pE->second;
|
| | aEdge2Face.erase(pE);
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | static float cos_maxangle(const Base::Vector3f& v1, const Base::Vector3f& v2, const Base::Vector3f& v3)
|
| | {
|
| | float a = Base::Distance(v2, v3);
|
| | float b = Base::Distance(v3, v1);
|
| | float c = Base::Distance(v1, v2);
|
| | float A = a * (b * b + c * c - a * a);
|
| | float B = b * (c * c + a * a - b * b);
|
| | float C = c * (a * a + b * b - c * c);
|
| | return 0.5F * std::min<float>(std::min<float>(A, B), C) / (a * b * c);
|
| | }
|
| |
|
| | static float swap_benefit(
|
| | const Base::Vector3f& v1,
|
| | const Base::Vector3f& v2,
|
| | const Base::Vector3f& v3,
|
| | const Base::Vector3f& v4
|
| | )
|
| | {
|
| | Base::Vector3f n124 = (v4 - v2) % (v1 - v2);
|
| | Base::Vector3f n234 = (v3 - v2) % (v4 - v2);
|
| | if ((n124 * n234) <= 0.0F) {
|
| | return 0.0F;
|
| | }
|
| |
|
| | return std::max<float>(-cos_maxangle(v1, v2, v3), -cos_maxangle(v1, v3, v4))
|
| | - std::max<float>(-cos_maxangle(v1, v2, v4), -cos_maxangle(v2, v3, v4));
|
| | }
|
| |
|
| | float MeshTopoAlgorithm::SwapEdgeBenefit(FacetIndex f, int e) const
|
| | {
|
| | const MeshFacetArray& faces = _rclMesh.GetFacets();
|
| | const MeshPointArray& vertices = _rclMesh.GetPoints();
|
| |
|
| | FacetIndex n = faces[f]._aulNeighbours[e];
|
| | if (n == FACET_INDEX_MAX) {
|
| | return 0.0F;
|
| | }
|
| |
|
| | PointIndex v1 = faces[f]._aulPoints[e];
|
| | PointIndex v2 = faces[f]._aulPoints[(e + 1) % 3];
|
| | PointIndex v3 = faces[f]._aulPoints[(e + 2) % 3];
|
| | unsigned short s = faces[n].Side(faces[f]);
|
| | if (s == std::numeric_limits<unsigned short>::max()) {
|
| | std::cerr << "MeshTopoAlgorithm::SwapEdgeBenefit: error in neighbourhood "
|
| | << "of faces " << f << " and " << n << std::endl;
|
| | return 0.0F;
|
| | }
|
| | PointIndex v4 = faces[n]._aulPoints[(s + 2) % 3];
|
| | if (v3 == v4) {
|
| | std::cerr << "MeshTopoAlgorithm::SwapEdgeBenefit: duplicate faces " << f << " and " << n
|
| | << std::endl;
|
| | return 0.0F;
|
| | }
|
| | return swap_benefit(vertices[v2], vertices[v3], vertices[v1], vertices[v4]);
|
| | }
|
| |
|
| | using FaceEdge = std::pair<FacetIndex, int>;
|
| | using FaceEdgePriority = std::pair<float, FaceEdge>;
|
| |
|
| | void MeshTopoAlgorithm::OptimizeTopology()
|
| | {
|
| |
|
| |
|
| | const MeshFacetArray& faces = _rclMesh.GetFacets();
|
| | FacetIndex nf = _rclMesh.CountFacets();
|
| | std::priority_queue<FaceEdgePriority> todo;
|
| | for (FacetIndex i = 0; i < nf; i++) {
|
| | for (int j = 0; j < 3; j++) {
|
| | float b = SwapEdgeBenefit(i, j);
|
| | if (b > 0.0F) {
|
| | todo.push(std::make_pair(b, std::make_pair(i, j)));
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | while (!todo.empty()) {
|
| | FacetIndex f = todo.top().second.first;
|
| | int e = todo.top().second.second;
|
| | todo.pop();
|
| |
|
| | if (SwapEdgeBenefit(f, e) <= 0.0F) {
|
| | continue;
|
| | }
|
| |
|
| | FacetIndex f2 = faces[f]._aulNeighbours[e];
|
| | SwapEdge(f, f2);
|
| |
|
| | for (int j = 0; j < 3; j++) {
|
| | float b = SwapEdgeBenefit(f, j);
|
| | if (b > 0.0F) {
|
| | todo.push(std::make_pair(b, std::make_pair(f, j)));
|
| | }
|
| | }
|
| | for (int j = 0; j < 3; j++) {
|
| | float b = SwapEdgeBenefit(f2, j);
|
| | if (b > 0.0F) {
|
| | todo.push(std::make_pair(b, std::make_pair(f2, j)));
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::DelaunayFlip(float fMaxAngle)
|
| | {
|
| |
|
| | std::set<std::pair<FacetIndex, FacetIndex>> aEdge2Face;
|
| | FacetIndex index = 0;
|
| | for (auto pI = _rclMesh._aclFacetArray.begin(); pI != _rclMesh._aclFacetArray.end();
|
| | ++pI, index++) {
|
| | for (FacetIndex nbIndex : pI->_aulNeighbours) {
|
| |
|
| | if (nbIndex != FACET_INDEX_MAX) {
|
| | FacetIndex ulFt0 = std::min<FacetIndex>(index, nbIndex);
|
| | FacetIndex ulFt1 = std::max<FacetIndex>(index, nbIndex);
|
| | aEdge2Face.insert(std::pair<FacetIndex, FacetIndex>(ulFt0, ulFt1));
|
| | }
|
| | }
|
| | }
|
| |
|
| | Base::Vector3f center;
|
| | while (!aEdge2Face.empty()) {
|
| | std::set<std::pair<FacetIndex, FacetIndex>>::iterator it = aEdge2Face.begin();
|
| | std::pair<FacetIndex, FacetIndex> edge = *it;
|
| | aEdge2Face.erase(it);
|
| | if (ShouldSwapEdge(edge.first, edge.second, fMaxAngle)) {
|
| | float radius = _rclMesh.GetFacet(edge.first).CenterOfCircumCircle(center);
|
| | radius *= radius;
|
| | const MeshFacet& face_1 = _rclMesh._aclFacetArray[edge.first];
|
| | const MeshFacet& face_2 = _rclMesh._aclFacetArray[edge.second];
|
| | unsigned short side = face_2.Side(edge.first);
|
| | MeshPoint vertex = _rclMesh.GetPoint(face_2._aulPoints[(side + 1) % 3]);
|
| | if (Base::DistanceP2(center, vertex) < radius) {
|
| | SwapEdge(edge.first, edge.second);
|
| | for (int i = 0; i < 3; i++) {
|
| | if (face_1._aulNeighbours[i] != FACET_INDEX_MAX
|
| | && face_1._aulNeighbours[i] != edge.second) {
|
| | FacetIndex ulFt0 = std::min<FacetIndex>(edge.first, face_1._aulNeighbours[i]);
|
| | FacetIndex ulFt1 = std::max<FacetIndex>(edge.first, face_1._aulNeighbours[i]);
|
| | aEdge2Face.insert(std::pair<FacetIndex, FacetIndex>(ulFt0, ulFt1));
|
| | }
|
| | if (face_2._aulNeighbours[i] != FACET_INDEX_MAX
|
| | && face_2._aulNeighbours[i] != edge.first) {
|
| | FacetIndex ulFt0 = std::min<FacetIndex>(edge.second, face_2._aulNeighbours[i]);
|
| | FacetIndex ulFt1 = std::max<FacetIndex>(edge.second, face_2._aulNeighbours[i]);
|
| | aEdge2Face.insert(std::pair<FacetIndex, FacetIndex>(ulFt0, ulFt1));
|
| | }
|
| | }
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| | int MeshTopoAlgorithm::DelaunayFlip()
|
| | {
|
| | int cnt_swap = 0;
|
| | _rclMesh._aclFacetArray.ResetFlag(MeshFacet::TMP0);
|
| | size_t cnt_facets = _rclMesh._aclFacetArray.size();
|
| | for (size_t i = 0; i < cnt_facets; i++) {
|
| | const MeshFacet& f_face = _rclMesh._aclFacetArray[i];
|
| | if (f_face.IsFlag(MeshFacet::TMP0)) {
|
| | continue;
|
| | }
|
| | for (int j = 0; j < 3; j++) {
|
| | FacetIndex n = f_face._aulNeighbours[j];
|
| | if (n != FACET_INDEX_MAX) {
|
| | const MeshFacet& n_face = _rclMesh._aclFacetArray[n];
|
| | if (n_face.IsFlag(MeshFacet::TMP0)) {
|
| | continue;
|
| | }
|
| | unsigned short k = n_face.Side(f_face);
|
| | MeshGeomFacet f1 = _rclMesh.GetFacet(f_face);
|
| | MeshGeomFacet f2 = _rclMesh.GetFacet(n_face);
|
| | Base::Vector3f c1, c2, p1, p2;
|
| | p1 = f1._aclPoints[(j + 2) % 3];
|
| | p2 = f2._aclPoints[(k + 2) % 3];
|
| | float r1 = f1.CenterOfCircumCircle(c1);
|
| | r1 = r1 * r1;
|
| | float r2 = f2.CenterOfCircumCircle(c2);
|
| | r2 = r2 * r2;
|
| | float d1 = Base::DistanceP2(c1, p2);
|
| | float d2 = Base::DistanceP2(c2, p1);
|
| | if (d1 < r1 || d2 < r2) {
|
| | SwapEdge(i, n);
|
| | cnt_swap++;
|
| | f_face.SetFlag(MeshFacet::TMP0);
|
| | n_face.SetFlag(MeshFacet::TMP0);
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| | return cnt_swap;
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::AdjustEdgesToCurvatureDirection()
|
| | {
|
| | std::vector<Wm4::Vector3<float>> aPnts;
|
| | MeshPointIterator cPIt(_rclMesh);
|
| | aPnts.reserve(_rclMesh.CountPoints());
|
| | for (cPIt.Init(); cPIt.More(); cPIt.Next()) {
|
| | aPnts.emplace_back(cPIt->x, cPIt->y, cPIt->z);
|
| | }
|
| |
|
| |
|
| | std::vector<int> aIdx;
|
| | const MeshFacetArray& raFts = _rclMesh.GetFacets();
|
| | aIdx.reserve(3 * raFts.size());
|
| |
|
| |
|
| | FacetIndex k = 0;
|
| | std::map<std::pair<PointIndex, PointIndex>, std::list<FacetIndex>> aclEdgeMap;
|
| | for (auto jt = raFts.begin(); jt != raFts.end(); ++jt, k++) {
|
| | for (int i = 0; i < 3; i++) {
|
| | PointIndex ulT0 = jt->_aulPoints[i];
|
| | PointIndex ulT1 = jt->_aulPoints[(i + 1) % 3];
|
| | PointIndex ulP0 = std::min<PointIndex>(ulT0, ulT1);
|
| | PointIndex ulP1 = std::max<PointIndex>(ulT0, ulT1);
|
| | aclEdgeMap[std::make_pair(ulP0, ulP1)].push_front(k);
|
| | aIdx.push_back(static_cast<int>(jt->_aulPoints[i]));
|
| | }
|
| | }
|
| |
|
| |
|
| | Wm4::MeshCurvature<float> meshCurv(
|
| | static_cast<int>(_rclMesh.CountPoints()),
|
| | aPnts.data(),
|
| | static_cast<int>(_rclMesh.CountFacets()),
|
| | aIdx.data()
|
| | );
|
| |
|
| |
|
| | const Wm4::Vector3<float>* aMaxCurvDir = meshCurv.GetMaxDirections();
|
| | const Wm4::Vector3<float>* aMinCurvDir = meshCurv.GetMinDirections();
|
| | const float* aMaxCurv = meshCurv.GetMaxCurvatures();
|
| | const float* aMinCurv = meshCurv.GetMinCurvatures();
|
| |
|
| | raFts.ResetFlag(MeshFacet::VISIT);
|
| | const MeshPointArray& raPts = _rclMesh.GetPoints();
|
| | for (auto& kt : aclEdgeMap) {
|
| | if (kt.second.size() == 2) {
|
| | PointIndex uPt1 = kt.first.first;
|
| | PointIndex uPt2 = kt.first.second;
|
| | FacetIndex uFt1 = kt.second.front();
|
| | FacetIndex uFt2 = kt.second.back();
|
| |
|
| | const MeshFacet& rFace1 = raFts[uFt1];
|
| | const MeshFacet& rFace2 = raFts[uFt2];
|
| | if (rFace1.IsFlag(MeshFacet::VISIT) || rFace2.IsFlag(MeshFacet::VISIT)) {
|
| | continue;
|
| | }
|
| |
|
| | PointIndex uPt3 {}, uPt4 {};
|
| | unsigned short side = rFace1.Side(uPt1, uPt2);
|
| | uPt3 = rFace1._aulPoints[(side + 2) % 3];
|
| | side = rFace2.Side(uPt1, uPt2);
|
| | uPt4 = rFace2._aulPoints[(side + 2) % 3];
|
| |
|
| | Wm4::Vector3<float> dir;
|
| | float fActCurvature {};
|
| | if (std::fabs(aMinCurv[uPt1]) > std::fabs(aMaxCurv[uPt1])) {
|
| | fActCurvature = aMinCurv[uPt1];
|
| | dir = aMaxCurvDir[uPt1];
|
| | }
|
| | else {
|
| | fActCurvature = aMaxCurv[uPt1];
|
| | dir = aMinCurvDir[uPt1];
|
| | }
|
| |
|
| | Base::Vector3f cMinDir(dir.X(), dir.Y(), dir.Z());
|
| | Base::Vector3f cEdgeDir1 = raPts[uPt1] - raPts[uPt2];
|
| | Base::Vector3f cEdgeDir2 = raPts[uPt3] - raPts[uPt4];
|
| | cMinDir.Normalize();
|
| | cEdgeDir1.Normalize();
|
| | cEdgeDir2.Normalize();
|
| |
|
| |
|
| | MeshGeomFacet cPlane(raPts[uPt1], raPts[uPt2], raPts[uPt3]);
|
| |
|
| | float fDist = raPts[uPt4].DistanceToPlane(cPlane._aclPoints[0], cPlane.GetNormal());
|
| |
|
| | float fLength12 = Base::Distance(raPts[uPt1], raPts[uPt2]);
|
| | float fLength34 = Base::Distance(raPts[uPt3], raPts[uPt4]);
|
| | if (fabs(cEdgeDir1 * cMinDir) < fabs(cEdgeDir2 * cMinDir)) {
|
| | if (IsSwapEdgeLegal(uFt1, uFt2) && fLength34 < 1.05F * fLength12
|
| | && fActCurvature * fDist > 0.0F) {
|
| | SwapEdge(uFt1, uFt2);
|
| | rFace1.SetFlag(MeshFacet::VISIT);
|
| | rFace2.SetFlag(MeshFacet::VISIT);
|
| | }
|
| | }
|
| | }
|
| | }
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::InsertVertexAndSwapEdge(
|
| | FacetIndex ulFacetPos,
|
| | const Base::Vector3f& rclPoint,
|
| | float fMaxAngle
|
| | )
|
| | {
|
| | if (!InsertVertex(ulFacetPos, rclPoint)) {
|
| | return false;
|
| | }
|
| |
|
| |
|
| | FacetIndex ulF1Ind = _rclMesh._aclFacetArray.size() - 2;
|
| | FacetIndex ulF2Ind = _rclMesh._aclFacetArray.size() - 1;
|
| | MeshFacet& rclF1 = _rclMesh._aclFacetArray[ulFacetPos];
|
| | MeshFacet& rclF2 = _rclMesh._aclFacetArray[ulF1Ind];
|
| | MeshFacet& rclF3 = _rclMesh._aclFacetArray[ulF2Ind];
|
| |
|
| |
|
| | for (FacetIndex uNeighbour : rclF1._aulNeighbours) {
|
| | if (uNeighbour != FACET_INDEX_MAX && uNeighbour != ulF1Ind && uNeighbour != ulF2Ind) {
|
| | if (ShouldSwapEdge(ulFacetPos, uNeighbour, fMaxAngle)) {
|
| | SwapEdge(ulFacetPos, uNeighbour);
|
| | break;
|
| | }
|
| | }
|
| | }
|
| | for (FacetIndex uNeighbour : rclF2._aulNeighbours) {
|
| |
|
| | if (uNeighbour != FACET_INDEX_MAX && uNeighbour != ulFacetPos && uNeighbour != ulF2Ind) {
|
| | if (ShouldSwapEdge(ulF1Ind, uNeighbour, fMaxAngle)) {
|
| | SwapEdge(ulF1Ind, uNeighbour);
|
| | break;
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | for (FacetIndex uNeighbour : rclF3._aulNeighbours) {
|
| | if (uNeighbour != FACET_INDEX_MAX && uNeighbour != ulFacetPos && uNeighbour != ulF1Ind) {
|
| | if (ShouldSwapEdge(ulF2Ind, uNeighbour, fMaxAngle)) {
|
| | SwapEdge(ulF2Ind, uNeighbour);
|
| | break;
|
| | }
|
| | }
|
| | }
|
| |
|
| | return true;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::IsSwapEdgeLegal(FacetIndex ulFacetPos, FacetIndex ulNeighbour) const
|
| | {
|
| | MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
|
| | MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
|
| |
|
| | unsigned short uFSide = rclF.Side(rclN);
|
| | unsigned short uNSide = rclN.Side(rclF);
|
| |
|
| | constexpr auto max = std::numeric_limits<unsigned short>::max();
|
| | if (uFSide == max || uNSide == max) {
|
| | return false;
|
| | }
|
| |
|
| | Base::Vector3f cP1 = _rclMesh._aclPointArray[rclF._aulPoints[uFSide]];
|
| | Base::Vector3f cP2 = _rclMesh._aclPointArray[rclF._aulPoints[(uFSide + 1) % 3]];
|
| | Base::Vector3f cP3 = _rclMesh._aclPointArray[rclF._aulPoints[(uFSide + 2) % 3]];
|
| | Base::Vector3f cP4 = _rclMesh._aclPointArray[rclN._aulPoints[(uNSide + 2) % 3]];
|
| |
|
| |
|
| | MeshGeomFacet cT3(cP4, cP3, cP1);
|
| | if (cT3.IsDegenerated(MeshDefinitions::_fMinPointDistanceP2)) {
|
| | return false;
|
| | }
|
| | MeshGeomFacet cT4(cP3, cP4, cP2);
|
| | if (cT4.IsDegenerated(MeshDefinitions::_fMinPointDistanceP2)) {
|
| | return false;
|
| | }
|
| |
|
| |
|
| |
|
| | Base::Vector3f cU = cP2 - cP1;
|
| | Base::Vector3f cV = cP4 - cP3;
|
| |
|
| | Base::Vector3f cN1 = (cU % cV) % cU;
|
| | if (((cP3 - cP1) * cN1) * ((cP4 - cP1) * cN1) >= 0.0F) {
|
| | return false;
|
| | }
|
| |
|
| | Base::Vector3f cN2 = (cU % cV) % cV;
|
| | if (((cP1 - cP3) * cN2) * ((cP2 - cP3) * cN2) >= 0.0F) {
|
| | return false;
|
| | }
|
| |
|
| | return true;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::ShouldSwapEdge(FacetIndex ulFacetPos, FacetIndex ulNeighbour, float fMaxAngle) const
|
| | {
|
| | if (!IsSwapEdgeLegal(ulFacetPos, ulNeighbour)) {
|
| | return false;
|
| | }
|
| |
|
| | MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
|
| | MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
|
| |
|
| | unsigned short uFSide = rclF.Side(rclN);
|
| | unsigned short uNSide = rclN.Side(rclF);
|
| |
|
| | Base::Vector3f cP1 = _rclMesh._aclPointArray[rclF._aulPoints[uFSide]];
|
| | Base::Vector3f cP2 = _rclMesh._aclPointArray[rclF._aulPoints[(uFSide + 1) % 3]];
|
| | Base::Vector3f cP3 = _rclMesh._aclPointArray[rclF._aulPoints[(uFSide + 2) % 3]];
|
| | Base::Vector3f cP4 = _rclMesh._aclPointArray[rclN._aulPoints[(uNSide + 2) % 3]];
|
| |
|
| | MeshGeomFacet cT1(cP1, cP2, cP3);
|
| | float fMax1 = cT1.MaximumAngle();
|
| | MeshGeomFacet cT2(cP2, cP1, cP4);
|
| | float fMax2 = cT2.MaximumAngle();
|
| | MeshGeomFacet cT3(cP4, cP3, cP1);
|
| | float fMax3 = cT3.MaximumAngle();
|
| | MeshGeomFacet cT4(cP3, cP4, cP2);
|
| | float fMax4 = cT4.MaximumAngle();
|
| |
|
| |
|
| | Base::Vector3f cN1 = cT1.GetNormal();
|
| | Base::Vector3f cN2 = cT2.GetNormal();
|
| | if (cN1.GetAngle(cN2) > fMaxAngle) {
|
| | return false;
|
| | }
|
| |
|
| | float fMax12 = std::max<float>(fMax1, fMax2);
|
| | float fMax34 = std::max<float>(fMax3, fMax4);
|
| |
|
| | return fMax12 > fMax34;
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::SwapEdge(FacetIndex ulFacetPos, FacetIndex ulNeighbour)
|
| | {
|
| | MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
|
| | MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
|
| |
|
| | unsigned short uFSide = rclF.Side(rclN);
|
| | unsigned short uNSide = rclN.Side(rclF);
|
| |
|
| | constexpr auto max = std::numeric_limits<unsigned short>::max();
|
| | if (uFSide == max || uNSide == max) {
|
| | return;
|
| | }
|
| |
|
| |
|
| | if (rclF._aulNeighbours[(uFSide + 1) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclF._aulNeighbours[(uFSide + 1) % 3]].ReplaceNeighbour(
|
| | ulFacetPos,
|
| | ulNeighbour
|
| | );
|
| | }
|
| | if (rclN._aulNeighbours[(uNSide + 1) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide + 1) % 3]].ReplaceNeighbour(
|
| | ulNeighbour,
|
| | ulFacetPos
|
| | );
|
| | }
|
| |
|
| |
|
| | rclF._aulPoints[(uFSide + 1) % 3] = rclN._aulPoints[(uNSide + 2) % 3];
|
| | rclN._aulPoints[(uNSide + 1) % 3] = rclF._aulPoints[(uFSide + 2) % 3];
|
| | rclF._aulNeighbours[uFSide] = rclN._aulNeighbours[(uNSide + 1) % 3];
|
| | rclN._aulNeighbours[uNSide] = rclF._aulNeighbours[(uFSide + 1) % 3];
|
| | rclF._aulNeighbours[(uFSide + 1) % 3] = ulNeighbour;
|
| | rclN._aulNeighbours[(uNSide + 1) % 3] = ulFacetPos;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::SplitEdge(FacetIndex ulFacetPos, FacetIndex ulNeighbour, const Base::Vector3f& rP)
|
| | {
|
| | MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
|
| | MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
|
| |
|
| | unsigned short uFSide = rclF.Side(rclN);
|
| | unsigned short uNSide = rclN.Side(rclF);
|
| |
|
| | constexpr auto max = std::numeric_limits<unsigned short>::max();
|
| | if (uFSide == max || uNSide == max) {
|
| | return false;
|
| | }
|
| |
|
| | PointIndex uPtCnt = _rclMesh._aclPointArray.size();
|
| | PointIndex uPtInd = this->GetOrAddIndex(rP);
|
| | FacetIndex ulSize = _rclMesh._aclFacetArray.size();
|
| |
|
| |
|
| |
|
| | if (uPtInd < uPtCnt) {
|
| | return false;
|
| | }
|
| |
|
| |
|
| | if (rclF._aulNeighbours[(uFSide + 1) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclF._aulNeighbours[(uFSide + 1) % 3]].ReplaceNeighbour(
|
| | ulFacetPos,
|
| | ulSize
|
| | );
|
| | }
|
| | if (rclN._aulNeighbours[(uNSide + 2) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide + 2) % 3]].ReplaceNeighbour(
|
| | ulNeighbour,
|
| | ulSize + 1
|
| | );
|
| | }
|
| |
|
| | MeshFacet cNew1, cNew2;
|
| | cNew1._aulPoints[0] = uPtInd;
|
| | cNew1._aulPoints[1] = rclF._aulPoints[(uFSide + 1) % 3];
|
| | cNew1._aulPoints[2] = rclF._aulPoints[(uFSide + 2) % 3];
|
| | cNew1._aulNeighbours[0] = ulSize + 1;
|
| | cNew1._aulNeighbours[1] = rclF._aulNeighbours[(uFSide + 1) % 3];
|
| | cNew1._aulNeighbours[2] = ulFacetPos;
|
| |
|
| | cNew2._aulPoints[0] = rclN._aulPoints[uNSide];
|
| | cNew2._aulPoints[1] = uPtInd;
|
| | cNew2._aulPoints[2] = rclN._aulPoints[(uNSide + 2) % 3];
|
| | cNew2._aulNeighbours[0] = ulSize;
|
| | cNew2._aulNeighbours[1] = ulNeighbour;
|
| | cNew2._aulNeighbours[2] = rclN._aulNeighbours[(uNSide + 2) % 3];
|
| |
|
| |
|
| | rclF._aulPoints[(uFSide + 1) % 3] = uPtInd;
|
| | rclF._aulNeighbours[(uFSide + 1) % 3] = ulSize;
|
| | rclN._aulPoints[uNSide] = uPtInd;
|
| | rclN._aulNeighbours[(uNSide + 2) % 3] = ulSize + 1;
|
| |
|
| |
|
| | _rclMesh._aclFacetArray.push_back(cNew1);
|
| | _rclMesh._aclFacetArray.push_back(cNew2);
|
| |
|
| | return true;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::SplitOpenEdge(
|
| | FacetIndex ulFacetPos,
|
| | unsigned short uSide,
|
| | const Base::Vector3f& rP
|
| | )
|
| | {
|
| | MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
|
| | if (rclF._aulNeighbours[uSide] != FACET_INDEX_MAX) {
|
| | return false;
|
| | }
|
| |
|
| | PointIndex uPtCnt = _rclMesh._aclPointArray.size();
|
| | PointIndex uPtInd = this->GetOrAddIndex(rP);
|
| | FacetIndex ulSize = _rclMesh._aclFacetArray.size();
|
| |
|
| | if (uPtInd < uPtCnt) {
|
| | return false;
|
| |
|
| | }
|
| |
|
| |
|
| | if (rclF._aulNeighbours[(uSide + 1) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclF._aulNeighbours[(uSide + 1) % 3]].ReplaceNeighbour(
|
| | ulFacetPos,
|
| | ulSize
|
| | );
|
| | }
|
| |
|
| | MeshFacet cNew;
|
| | cNew._aulPoints[0] = uPtInd;
|
| | cNew._aulPoints[1] = rclF._aulPoints[(uSide + 1) % 3];
|
| | cNew._aulPoints[2] = rclF._aulPoints[(uSide + 2) % 3];
|
| | cNew._aulNeighbours[0] = FACET_INDEX_MAX;
|
| | cNew._aulNeighbours[1] = rclF._aulNeighbours[(uSide + 1) % 3];
|
| | cNew._aulNeighbours[2] = ulFacetPos;
|
| |
|
| |
|
| | rclF._aulPoints[(uSide + 1) % 3] = uPtInd;
|
| | rclF._aulNeighbours[(uSide + 1) % 3] = ulSize;
|
| |
|
| |
|
| | _rclMesh._aclFacetArray.push_back(cNew);
|
| | return true;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::Vertex_Less::operator()(const Base::Vector3f& u, const Base::Vector3f& v) const
|
| | {
|
| | if (std::fabs(u.x - v.x) > std::numeric_limits<float>::epsilon()) {
|
| | return u.x < v.x;
|
| | }
|
| | if (std::fabs(u.y - v.y) > std::numeric_limits<float>::epsilon()) {
|
| | return u.y < v.y;
|
| | }
|
| | if (std::fabs(u.z - v.z) > std::numeric_limits<float>::epsilon()) {
|
| | return u.z < v.z;
|
| | }
|
| | return false;
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::BeginCache()
|
| | {
|
| | delete _cache;
|
| | _cache = new tCache();
|
| | PointIndex nbPoints = _rclMesh._aclPointArray.size();
|
| | for (unsigned int pntCpt = 0; pntCpt < nbPoints; ++pntCpt) {
|
| | _cache->insert(std::make_pair(_rclMesh._aclPointArray[pntCpt], pntCpt));
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::EndCache()
|
| | {
|
| | if (_cache) {
|
| | _cache->clear();
|
| | delete _cache;
|
| | _cache = nullptr;
|
| | }
|
| | }
|
| |
|
| | PointIndex MeshTopoAlgorithm::GetOrAddIndex(const MeshPoint& rclPoint)
|
| | {
|
| | if (!_cache) {
|
| | return _rclMesh._aclPointArray.GetOrAddIndex(rclPoint);
|
| | }
|
| |
|
| | unsigned long sz = _rclMesh._aclPointArray.size();
|
| | std::pair<tCache::iterator, bool> retval = _cache->insert(std::make_pair(rclPoint, sz));
|
| | if (retval.second) {
|
| | _rclMesh._aclPointArray.push_back(rclPoint);
|
| | }
|
| | return retval.first->second;
|
| | }
|
| |
|
| | std::vector<FacetIndex> MeshTopoAlgorithm::GetFacetsToPoint(FacetIndex uFacetPos, PointIndex uPointPos) const
|
| | {
|
| |
|
| | std::list<FacetIndex> aReference;
|
| | aReference.push_back(uFacetPos);
|
| | std::set<FacetIndex> aRefFacet;
|
| | while (!aReference.empty()) {
|
| | FacetIndex uIndex = aReference.front();
|
| | aReference.pop_front();
|
| | aRefFacet.insert(uIndex);
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[uIndex];
|
| | for (int i = 0; i < 3; i++) {
|
| | if (rFace._aulPoints[i] == uPointPos) {
|
| | if (rFace._aulNeighbours[i] != FACET_INDEX_MAX) {
|
| | if (aRefFacet.find(rFace._aulNeighbours[i]) == aRefFacet.end()) {
|
| | aReference.push_back(rFace._aulNeighbours[i]);
|
| | }
|
| | }
|
| | if (rFace._aulNeighbours[(i + 2) % 3] != FACET_INDEX_MAX) {
|
| | if (aRefFacet.find(rFace._aulNeighbours[(i + 2) % 3]) == aRefFacet.end()) {
|
| | aReference.push_back(rFace._aulNeighbours[(i + 2) % 3]);
|
| | }
|
| | }
|
| | break;
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | std::vector<FacetIndex> aRefs;
|
| | aRefs.insert(aRefs.end(), aRefFacet.begin(), aRefFacet.end());
|
| | return aRefs;
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::Cleanup()
|
| | {
|
| | _rclMesh.RemoveInvalids();
|
| | _needsCleanup = false;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::CollapseVertex(const VertexCollapse& vc)
|
| | {
|
| | if (vc._circumFacets.size() != vc._circumPoints.size()) {
|
| | return false;
|
| | }
|
| |
|
| | if (vc._circumFacets.size() != 3) {
|
| | return false;
|
| | }
|
| |
|
| | if (!_rclMesh._aclPointArray[vc._point].IsValid()) {
|
| | return false;
|
| | }
|
| |
|
| | MeshFacet& rFace1 = _rclMesh._aclFacetArray[vc._circumFacets[0]];
|
| | MeshFacet& rFace2 = _rclMesh._aclFacetArray[vc._circumFacets[1]];
|
| | MeshFacet& rFace3 = _rclMesh._aclFacetArray[vc._circumFacets[2]];
|
| |
|
| |
|
| | PointIndex ptIndex = POINT_INDEX_MAX;
|
| | std::vector<PointIndex>::const_iterator it;
|
| | for (it = vc._circumPoints.begin(); it != vc._circumPoints.end(); ++it) {
|
| | if (!rFace1.HasPoint(*it)) {
|
| | ptIndex = *it;
|
| | break;
|
| | }
|
| | }
|
| |
|
| | if (ptIndex == POINT_INDEX_MAX) {
|
| | return false;
|
| | }
|
| |
|
| | FacetIndex neighbour1 = FACET_INDEX_MAX;
|
| | FacetIndex neighbour2 = FACET_INDEX_MAX;
|
| |
|
| | const std::vector<FacetIndex>& faces = vc._circumFacets;
|
| |
|
| | for (int i = 0; i < 3; i++) {
|
| | if (std::ranges::find(faces, rFace2._aulNeighbours[i]) == faces.end()) {
|
| | neighbour1 = rFace2._aulNeighbours[i];
|
| | }
|
| | if (std::ranges::find(faces, rFace3._aulNeighbours[i]) == faces.end()) {
|
| | neighbour2 = rFace3._aulNeighbours[i];
|
| | }
|
| | }
|
| |
|
| |
|
| | rFace1.Transpose(vc._point, ptIndex);
|
| | rFace1.ReplaceNeighbour(vc._circumFacets[1], neighbour1);
|
| | rFace1.ReplaceNeighbour(vc._circumFacets[2], neighbour2);
|
| |
|
| | if (neighbour1 != FACET_INDEX_MAX) {
|
| | MeshFacet& rFace4 = _rclMesh._aclFacetArray[neighbour1];
|
| | rFace4.ReplaceNeighbour(vc._circumFacets[1], vc._circumFacets[0]);
|
| | }
|
| | if (neighbour2 != FACET_INDEX_MAX) {
|
| | MeshFacet& rFace5 = _rclMesh._aclFacetArray[neighbour2];
|
| | rFace5.ReplaceNeighbour(vc._circumFacets[2], vc._circumFacets[0]);
|
| | }
|
| |
|
| |
|
| | rFace2.SetInvalid();
|
| | rFace3.SetInvalid();
|
| | _rclMesh._aclPointArray[vc._point].SetInvalid();
|
| |
|
| | _needsCleanup = true;
|
| |
|
| | return true;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::CollapseEdge(FacetIndex ulFacetPos, FacetIndex ulNeighbour)
|
| | {
|
| | MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
|
| | MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
|
| |
|
| | unsigned short uFSide = rclF.Side(rclN);
|
| | unsigned short uNSide = rclN.Side(rclF);
|
| |
|
| | constexpr auto max = std::numeric_limits<unsigned short>::max();
|
| | if (uFSide == max || uNSide == max) {
|
| | return false;
|
| | }
|
| |
|
| | if (!rclF.IsValid() || !rclN.IsValid()) {
|
| | return false;
|
| | }
|
| |
|
| |
|
| | PointIndex ulPointPos = rclF._aulPoints[uFSide];
|
| | PointIndex ulPointNew = rclN._aulPoints[uNSide];
|
| |
|
| |
|
| | std::vector<FacetIndex> aRefs = GetFacetsToPoint(ulFacetPos, ulPointPos);
|
| | for (FacetIndex it : aRefs) {
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[it];
|
| | rFace.Transpose(ulPointPos, ulPointNew);
|
| | }
|
| |
|
| |
|
| | if (rclF._aulNeighbours[(uFSide + 1) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclF._aulNeighbours[(uFSide + 1) % 3]].ReplaceNeighbour(
|
| | ulFacetPos,
|
| | rclF._aulNeighbours[(uFSide + 2) % 3]
|
| | );
|
| | }
|
| | if (rclF._aulNeighbours[(uFSide + 2) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclF._aulNeighbours[(uFSide + 2) % 3]].ReplaceNeighbour(
|
| | ulFacetPos,
|
| | rclF._aulNeighbours[(uFSide + 1) % 3]
|
| | );
|
| | }
|
| | if (rclN._aulNeighbours[(uNSide + 1) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide + 1) % 3]].ReplaceNeighbour(
|
| | ulNeighbour,
|
| | rclN._aulNeighbours[(uNSide + 2) % 3]
|
| | );
|
| | }
|
| | if (rclN._aulNeighbours[(uNSide + 2) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide + 2) % 3]].ReplaceNeighbour(
|
| | ulNeighbour,
|
| | rclN._aulNeighbours[(uNSide + 1) % 3]
|
| | );
|
| | }
|
| |
|
| |
|
| | rclF._aulNeighbours[0] = FACET_INDEX_MAX;
|
| | rclF._aulNeighbours[1] = FACET_INDEX_MAX;
|
| | rclF._aulNeighbours[2] = FACET_INDEX_MAX;
|
| | rclF.SetInvalid();
|
| | rclN._aulNeighbours[0] = FACET_INDEX_MAX;
|
| | rclN._aulNeighbours[1] = FACET_INDEX_MAX;
|
| | rclN._aulNeighbours[2] = FACET_INDEX_MAX;
|
| | rclN.SetInvalid();
|
| | _rclMesh._aclPointArray[ulPointPos].SetInvalid();
|
| |
|
| | _needsCleanup = true;
|
| |
|
| | return true;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::IsCollapseEdgeLegal(const EdgeCollapse& ec) const
|
| | {
|
| |
|
| |
|
| |
|
| | std::vector<PointIndex> commonPoints;
|
| | std::set_intersection(
|
| | ec._adjacentFrom.begin(),
|
| | ec._adjacentFrom.end(),
|
| | ec._adjacentTo.begin(),
|
| | ec._adjacentTo.end(),
|
| | std::back_insert_iterator<std::vector<PointIndex>>(commonPoints)
|
| | );
|
| | if (commonPoints.size() > 2) {
|
| | return false;
|
| | }
|
| |
|
| |
|
| | std::vector<FacetIndex>::const_iterator it;
|
| | for (it = ec._changeFacets.begin(); it != ec._changeFacets.end(); ++it) {
|
| | MeshFacet f = _rclMesh._aclFacetArray[*it];
|
| | if (!f.IsValid()) {
|
| | return false;
|
| | }
|
| |
|
| |
|
| | if (f.HasPoint(ec._fromPoint) && f.HasPoint(ec._toPoint)) {
|
| | continue;
|
| | }
|
| |
|
| | MeshGeomFacet tria1 = _rclMesh.GetFacet(f);
|
| | f.Transpose(ec._fromPoint, ec._toPoint);
|
| | MeshGeomFacet tria2 = _rclMesh.GetFacet(f);
|
| |
|
| | if (tria1.GetNormal() * tria2.GetNormal() < 0.0F) {
|
| | return false;
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| | for (it = ec._removeFacets.begin(); it != ec._removeFacets.end(); ++it) {
|
| | MeshFacet f = _rclMesh._aclFacetArray[*it];
|
| | if (!f.IsValid()) {
|
| | return false;
|
| | }
|
| | }
|
| |
|
| | if (!_rclMesh._aclPointArray[ec._fromPoint].IsValid()) {
|
| | return false;
|
| | }
|
| |
|
| | if (!_rclMesh._aclPointArray[ec._toPoint].IsValid()) {
|
| | return false;
|
| | }
|
| |
|
| | return true;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::CollapseEdge(const EdgeCollapse& ec)
|
| | {
|
| | std::vector<FacetIndex>::const_iterator it;
|
| | for (it = ec._removeFacets.begin(); it != ec._removeFacets.end(); ++it) {
|
| | MeshFacet& f = _rclMesh._aclFacetArray[*it];
|
| | f.SetInvalid();
|
| |
|
| |
|
| | std::vector<FacetIndex> neighbours;
|
| | for (FacetIndex nbIndex : f._aulNeighbours) {
|
| |
|
| | if (nbIndex != FACET_INDEX_MAX) {
|
| | if (std::ranges::find(ec._removeFacets, nbIndex) == ec._removeFacets.end()) {
|
| | neighbours.push_back(nbIndex);
|
| | }
|
| | }
|
| | }
|
| |
|
| | if (neighbours.size() == 2) {
|
| | MeshFacet& n1 = _rclMesh._aclFacetArray[neighbours[0]];
|
| | n1.ReplaceNeighbour(*it, neighbours[1]);
|
| | MeshFacet& n2 = _rclMesh._aclFacetArray[neighbours[1]];
|
| | n2.ReplaceNeighbour(*it, neighbours[0]);
|
| | }
|
| | else if (neighbours.size() == 1) {
|
| | MeshFacet& n1 = _rclMesh._aclFacetArray[neighbours[0]];
|
| | n1.ReplaceNeighbour(*it, FACET_INDEX_MAX);
|
| | }
|
| | }
|
| |
|
| | for (it = ec._changeFacets.begin(); it != ec._changeFacets.end(); ++it) {
|
| | MeshFacet& f = _rclMesh._aclFacetArray[*it];
|
| | f.Transpose(ec._fromPoint, ec._toPoint);
|
| | }
|
| |
|
| | _rclMesh._aclPointArray[ec._fromPoint].SetInvalid();
|
| |
|
| | _needsCleanup = true;
|
| | return true;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::CollapseFacet(FacetIndex ulFacetPos)
|
| | {
|
| | MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
|
| | if (!rclF.IsValid()) {
|
| | return false;
|
| | }
|
| |
|
| |
|
| | PointIndex ulPointInd0 = rclF._aulPoints[0];
|
| | PointIndex ulPointInd1 = rclF._aulPoints[1];
|
| | PointIndex ulPointInd2 = rclF._aulPoints[2];
|
| |
|
| |
|
| | Base::Vector3f cCenter = _rclMesh.GetGravityPoint(rclF);
|
| | _rclMesh._aclPointArray[ulPointInd0] = cCenter;
|
| |
|
| |
|
| | std::vector<FacetIndex> aRefs = GetFacetsToPoint(ulFacetPos, ulPointInd1);
|
| | for (FacetIndex it : aRefs) {
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[it];
|
| | rFace.Transpose(ulPointInd1, ulPointInd0);
|
| | }
|
| |
|
| | aRefs = GetFacetsToPoint(ulFacetPos, ulPointInd2);
|
| | for (FacetIndex it : aRefs) {
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[it];
|
| | rFace.Transpose(ulPointInd2, ulPointInd0);
|
| | }
|
| |
|
| |
|
| | for (FacetIndex nbIndex : rclF._aulNeighbours) {
|
| | if (nbIndex == FACET_INDEX_MAX) {
|
| | continue;
|
| | }
|
| | MeshFacet& rclN = _rclMesh._aclFacetArray[nbIndex];
|
| | unsigned short uNSide = rclN.Side(rclF);
|
| |
|
| | if (rclN._aulNeighbours[(uNSide + 1) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide + 1) % 3]].ReplaceNeighbour(
|
| | nbIndex,
|
| | rclN._aulNeighbours[(uNSide + 2) % 3]
|
| | );
|
| | }
|
| | if (rclN._aulNeighbours[(uNSide + 2) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide + 2) % 3]].ReplaceNeighbour(
|
| | nbIndex,
|
| | rclN._aulNeighbours[(uNSide + 1) % 3]
|
| | );
|
| | }
|
| |
|
| |
|
| | rclN._aulNeighbours[0] = FACET_INDEX_MAX;
|
| | rclN._aulNeighbours[1] = FACET_INDEX_MAX;
|
| | rclN._aulNeighbours[2] = FACET_INDEX_MAX;
|
| | rclN.SetInvalid();
|
| | }
|
| |
|
| |
|
| | rclF._aulNeighbours[0] = FACET_INDEX_MAX;
|
| | rclF._aulNeighbours[1] = FACET_INDEX_MAX;
|
| | rclF._aulNeighbours[2] = FACET_INDEX_MAX;
|
| | rclF.SetInvalid();
|
| | _rclMesh._aclPointArray[ulPointInd1].SetInvalid();
|
| | _rclMesh._aclPointArray[ulPointInd2].SetInvalid();
|
| |
|
| | _needsCleanup = true;
|
| |
|
| | return true;
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::SplitFacet(
|
| | FacetIndex ulFacetPos,
|
| | const Base::Vector3f& rP1,
|
| | const Base::Vector3f& rP2
|
| | )
|
| | {
|
| | float fEps = MESH_MIN_EDGE_LEN;
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[ulFacetPos];
|
| | MeshPoint& rVertex0 = _rclMesh._aclPointArray[rFace._aulPoints[0]];
|
| | MeshPoint& rVertex1 = _rclMesh._aclPointArray[rFace._aulPoints[1]];
|
| | MeshPoint& rVertex2 = _rclMesh._aclPointArray[rFace._aulPoints[2]];
|
| |
|
| | auto pointIndex = [=](const Base::Vector3f& rP) {
|
| | unsigned short equalP = std::numeric_limits<unsigned short>::max();
|
| | if (Base::Distance(rVertex0, rP) < fEps) {
|
| | equalP = 0;
|
| | }
|
| | else if (Base::Distance(rVertex1, rP) < fEps) {
|
| | equalP = 1;
|
| | }
|
| | else if (Base::Distance(rVertex2, rP) < fEps) {
|
| | equalP = 2;
|
| | }
|
| | return equalP;
|
| | };
|
| |
|
| | unsigned short equalP1 = pointIndex(rP1);
|
| | unsigned short equalP2 = pointIndex(rP2);
|
| |
|
| | constexpr auto max = std::numeric_limits<unsigned short>::max();
|
| |
|
| | if (equalP1 != max && equalP2 != max) {
|
| | return;
|
| | }
|
| |
|
| | if (equalP1 != max) {
|
| |
|
| | SplitFacetOnOneEdge(ulFacetPos, rP2);
|
| | }
|
| | else if (equalP2 != max) {
|
| |
|
| | SplitFacetOnOneEdge(ulFacetPos, rP1);
|
| | }
|
| | else {
|
| | SplitFacetOnTwoEdges(ulFacetPos, rP1, rP2);
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::SplitFacetOnOneEdge(FacetIndex ulFacetPos, const Base::Vector3f& rP)
|
| | {
|
| | float fMinDist = std::numeric_limits<float>::max();
|
| | unsigned short iEdgeNo = std::numeric_limits<unsigned short>::max();
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[ulFacetPos];
|
| |
|
| | for (unsigned short i = 0; i < 3; i++) {
|
| | Base::Vector3f cBase(_rclMesh._aclPointArray[rFace._aulPoints[i]]);
|
| | Base::Vector3f cEnd(_rclMesh._aclPointArray[rFace._aulPoints[(i + 1) % 3]]);
|
| | Base::Vector3f cDir = cEnd - cBase;
|
| |
|
| | float fDist = rP.DistanceToLine(cBase, cDir);
|
| | if (fDist < fMinDist) {
|
| | fMinDist = fDist;
|
| | iEdgeNo = i;
|
| | }
|
| | }
|
| |
|
| | if (fMinDist < 0.05F) {
|
| | if (rFace._aulNeighbours[iEdgeNo] != FACET_INDEX_MAX) {
|
| | SplitEdge(ulFacetPos, rFace._aulNeighbours[iEdgeNo], rP);
|
| | }
|
| | else {
|
| | SplitOpenEdge(ulFacetPos, iEdgeNo, rP);
|
| | }
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::SplitFacetOnTwoEdges(
|
| | FacetIndex ulFacetPos,
|
| | const Base::Vector3f& rP1,
|
| | const Base::Vector3f& rP2
|
| | )
|
| | {
|
| |
|
| | unsigned short iEdgeNo1 = std::numeric_limits<unsigned short>::max();
|
| | unsigned short iEdgeNo2 = std::numeric_limits<unsigned short>::max();
|
| | float fMinDist1 = std::numeric_limits<float>::max();
|
| | float fMinDist2 = std::numeric_limits<float>::max();
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[ulFacetPos];
|
| |
|
| | for (unsigned short i = 0; i < 3; i++) {
|
| | Base::Vector3f cBase(_rclMesh._aclPointArray[rFace._aulPoints[i]]);
|
| | Base::Vector3f cEnd(_rclMesh._aclPointArray[rFace._aulPoints[(i + 1) % 3]]);
|
| | Base::Vector3f cDir = cEnd - cBase;
|
| |
|
| | float fDist = rP1.DistanceToLine(cBase, cDir);
|
| | if (fDist < fMinDist1) {
|
| | fMinDist1 = fDist;
|
| | iEdgeNo1 = i;
|
| | }
|
| | fDist = rP2.DistanceToLine(cBase, cDir);
|
| | if (fDist < fMinDist2) {
|
| | fMinDist2 = fDist;
|
| | iEdgeNo2 = i;
|
| | }
|
| | }
|
| |
|
| | if (iEdgeNo1 == iEdgeNo2 || fMinDist1 >= 0.05F || fMinDist2 >= 0.05F) {
|
| | return;
|
| | }
|
| |
|
| |
|
| | Base::Vector3f cP1 = rP1;
|
| | Base::Vector3f cP2 = rP2;
|
| | if ((iEdgeNo2 + 1) % 3 == iEdgeNo1) {
|
| | std::swap(iEdgeNo1, iEdgeNo2);
|
| | std::swap(cP1, cP2);
|
| | }
|
| |
|
| |
|
| | PointIndex cntPts1 = this->GetOrAddIndex(cP1);
|
| | PointIndex cntPts2 = this->GetOrAddIndex(cP2);
|
| | FacetIndex cntFts = _rclMesh.CountFacets();
|
| |
|
| | unsigned short v0 = (iEdgeNo2 + 1) % 3;
|
| | unsigned short v1 = iEdgeNo1;
|
| | unsigned short v2 = iEdgeNo2;
|
| |
|
| | PointIndex p0 = rFace._aulPoints[v0];
|
| | PointIndex p1 = rFace._aulPoints[v1];
|
| | PointIndex p2 = rFace._aulPoints[v2];
|
| |
|
| | FacetIndex n0 = rFace._aulNeighbours[v0];
|
| | FacetIndex n1 = rFace._aulNeighbours[v1];
|
| | FacetIndex n2 = rFace._aulNeighbours[v2];
|
| |
|
| |
|
| |
|
| | rFace._aulPoints[v0] = cntPts2;
|
| | rFace._aulPoints[v1] = cntPts1;
|
| | rFace._aulNeighbours[v0] = cntFts + 1;
|
| |
|
| | float dist1 = Base::DistanceP2(_rclMesh._aclPointArray[p0], cP1);
|
| | float dist2 = Base::DistanceP2(_rclMesh._aclPointArray[p1], cP2);
|
| |
|
| | if (dist1 > dist2) {
|
| | AddFacet(p0, p1, cntPts2, n0, cntFts + 1, n2);
|
| | AddFacet(p1, cntPts1, cntPts2, n1, ulFacetPos, cntFts);
|
| | }
|
| | else {
|
| | AddFacet(p0, p1, cntPts1, n0, n1, cntFts + 1);
|
| | AddFacet(p0, cntPts1, cntPts2, cntFts, ulFacetPos, n2);
|
| | }
|
| |
|
| | std::vector<FacetIndex> fixIndices;
|
| | fixIndices.push_back(ulFacetPos);
|
| |
|
| | if (n0 != FACET_INDEX_MAX) {
|
| | fixIndices.push_back(n0);
|
| | }
|
| |
|
| |
|
| | if (n1 != FACET_INDEX_MAX) {
|
| | fixIndices.push_back(n1);
|
| | MeshFacet& rN = _rclMesh._aclFacetArray[n1];
|
| | for (FacetIndex nbIndex : rN._aulNeighbours) {
|
| | fixIndices.push_back(nbIndex);
|
| | }
|
| | SplitFacet(n1, p1, p2, cntPts1);
|
| | }
|
| |
|
| | if (n2 != FACET_INDEX_MAX) {
|
| | fixIndices.push_back(n2);
|
| | MeshFacet& rN = _rclMesh._aclFacetArray[n2];
|
| | for (FacetIndex nbIndex : rN._aulNeighbours) {
|
| | fixIndices.push_back(nbIndex);
|
| | }
|
| | SplitFacet(n2, p2, p0, cntPts2);
|
| | }
|
| |
|
| | FacetIndex cntFts2 = _rclMesh.CountFacets();
|
| | for (FacetIndex i = cntFts; i < cntFts2; i++) {
|
| | fixIndices.push_back(i);
|
| | }
|
| |
|
| | std::sort(fixIndices.begin(), fixIndices.end());
|
| | fixIndices.erase(std::unique(fixIndices.begin(), fixIndices.end()), fixIndices.end());
|
| | HarmonizeNeighbours(fixIndices);
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::SplitFacet(FacetIndex ulFacetPos, PointIndex P1, PointIndex P2, PointIndex Pn)
|
| | {
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[ulFacetPos];
|
| | unsigned short side = rFace.Side(P1, P2);
|
| | if (side != std::numeric_limits<unsigned short>::max()) {
|
| | PointIndex V1 = rFace._aulPoints[(side + 1) % 3];
|
| | PointIndex V2 = rFace._aulPoints[(side + 2) % 3];
|
| | FacetIndex size = _rclMesh._aclFacetArray.size();
|
| |
|
| | rFace._aulPoints[(side + 1) % 3] = Pn;
|
| | FacetIndex N1 = rFace._aulNeighbours[(side + 1) % 3];
|
| | if (N1 != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[N1].ReplaceNeighbour(ulFacetPos, size);
|
| | }
|
| |
|
| | rFace._aulNeighbours[(side + 1) % 3] = ulFacetPos;
|
| | AddFacet(Pn, V1, V2);
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::AddFacet(PointIndex P1, PointIndex P2, PointIndex P3)
|
| | {
|
| | MeshFacet facet;
|
| | facet._aulPoints[0] = P1;
|
| | facet._aulPoints[1] = P2;
|
| | facet._aulPoints[2] = P3;
|
| |
|
| | _rclMesh._aclFacetArray.push_back(facet);
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::AddFacet(
|
| | PointIndex P1,
|
| | PointIndex P2,
|
| | PointIndex P3,
|
| | FacetIndex N1,
|
| | FacetIndex N2,
|
| | FacetIndex N3
|
| | )
|
| | {
|
| | MeshFacet facet;
|
| | facet._aulPoints[0] = P1;
|
| | facet._aulPoints[1] = P2;
|
| | facet._aulPoints[2] = P3;
|
| | facet._aulNeighbours[0] = N1;
|
| | facet._aulNeighbours[1] = N2;
|
| | facet._aulNeighbours[2] = N3;
|
| |
|
| | _rclMesh._aclFacetArray.push_back(facet);
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::HarmonizeNeighbours(const std::vector<FacetIndex>& ulFacets)
|
| | {
|
| | for (FacetIndex it : ulFacets) {
|
| | for (FacetIndex jt : ulFacets) {
|
| | HarmonizeNeighbours(it, jt);
|
| | }
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::HarmonizeNeighbours(FacetIndex facet1, FacetIndex facet2)
|
| | {
|
| | if (facet1 == facet2) {
|
| | return;
|
| | }
|
| |
|
| | MeshFacet& rFace1 = _rclMesh._aclFacetArray[facet1];
|
| | MeshFacet& rFace2 = _rclMesh._aclFacetArray[facet2];
|
| |
|
| | unsigned short side = rFace1.Side(rFace2);
|
| | if (side != std::numeric_limits<unsigned short>::max()) {
|
| | rFace1._aulNeighbours[side] = facet2;
|
| | }
|
| |
|
| | side = rFace2.Side(rFace1);
|
| | if (side != std::numeric_limits<unsigned short>::max()) {
|
| | rFace2._aulNeighbours[side] = facet1;
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::SplitNeighbourFacet(
|
| | FacetIndex ulFacetPos,
|
| | unsigned short uFSide,
|
| | const Base::Vector3f& rPoint
|
| | )
|
| | {
|
| | MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos];
|
| |
|
| | FacetIndex ulNeighbour = rclF._aulNeighbours[uFSide];
|
| | MeshFacet& rclN = _rclMesh._aclFacetArray[ulNeighbour];
|
| |
|
| | unsigned short uNSide = rclN.Side(rclF);
|
| |
|
| | PointIndex uPtInd = this->GetOrAddIndex(rPoint);
|
| | FacetIndex ulSize = _rclMesh._aclFacetArray.size();
|
| |
|
| |
|
| | if (rclN._aulNeighbours[(uNSide + 1) % 3] != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[rclN._aulNeighbours[(uNSide + 1) % 3]].ReplaceNeighbour(
|
| | ulNeighbour,
|
| | ulSize
|
| | );
|
| | }
|
| |
|
| | MeshFacet cNew;
|
| | cNew._aulPoints[0] = uPtInd;
|
| | cNew._aulPoints[1] = rclN._aulPoints[(uNSide + 1) % 3];
|
| | cNew._aulPoints[2] = rclN._aulPoints[(uNSide + 2) % 3];
|
| | cNew._aulNeighbours[0] = ulFacetPos;
|
| | cNew._aulNeighbours[1] = rclN._aulNeighbours[(uNSide + 1) % 3];
|
| | cNew._aulNeighbours[2] = ulNeighbour;
|
| |
|
| |
|
| | rclN._aulPoints[(uNSide + 1) % 3] = uPtInd;
|
| | rclN._aulNeighbours[(uNSide + 1) % 3] = ulSize;
|
| |
|
| |
|
| | _rclMesh._aclFacetArray.push_back(cNew);
|
| | }
|
| |
|
| | #if 0
|
| |
|
| | MeshGeomFacet clFacet;
|
| |
|
| |
|
| | clFacet._aclPoints[0] = cP1;
|
| | clFacet._aclPoints[1] = _rclMesh._aclPointArray[rFace._aulPoints[(iEdgeNo1+1)%3]];
|
| | clFacet._aclPoints[2] = cP2;
|
| | clFacet.CalcNormal();
|
| | _aclNewFacets.push_back(clFacet);
|
| |
|
| | clFacet._aclPoints[0] = cP2;
|
| | clFacet._aclPoints[1] = _rclMesh._aclPointArray[rFace._aulPoints[(iEdgeNo1+2)%3]];
|
| | clFacet._aclPoints[2] = _rclMesh._aclPointArray[rFace._aulPoints[iEdgeNo1]];
|
| | clFacet.CalcNormal();
|
| | _aclNewFacets.push_back(clFacet);
|
| |
|
| | clFacet._aclPoints[0] = cP2;
|
| | clFacet._aclPoints[1] = _rclMesh._aclPointArray[rFace._aulPoints[iEdgeNo1]];
|
| | clFacet._aclPoints[2] = cP1;
|
| | clFacet.CalcNormal();
|
| | _aclNewFacets.push_back(clFacet);
|
| | #endif
|
| |
|
| | bool MeshTopoAlgorithm::RemoveDegeneratedFacet(FacetIndex index)
|
| | {
|
| | if (index >= _rclMesh._aclFacetArray.size()) {
|
| | return false;
|
| | }
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[index];
|
| |
|
| |
|
| | for (int i = 0; i < 3; i++) {
|
| | const MeshPoint& rE0 = _rclMesh._aclPointArray[rFace._aulPoints[i]];
|
| | const MeshPoint& rE1 = _rclMesh._aclPointArray[rFace._aulPoints[(i + 1) % 3]];
|
| | if (rE0 == rE1) {
|
| | FacetIndex uN1 = rFace._aulNeighbours[(i + 1) % 3];
|
| | FacetIndex uN2 = rFace._aulNeighbours[(i + 2) % 3];
|
| | if (uN2 != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[uN2].ReplaceNeighbour(index, uN1);
|
| | }
|
| | if (uN1 != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[uN1].ReplaceNeighbour(index, uN2);
|
| | }
|
| |
|
| |
|
| | rFace._aulNeighbours[0] = FACET_INDEX_MAX;
|
| | rFace._aulNeighbours[1] = FACET_INDEX_MAX;
|
| | rFace._aulNeighbours[2] = FACET_INDEX_MAX;
|
| | _rclMesh.DeleteFacet(index);
|
| | return true;
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| | for (int j = 0; j < 3; j++) {
|
| | Base::Vector3f cVec1 = _rclMesh._aclPointArray[rFace._aulPoints[(j + 1) % 3]]
|
| | - _rclMesh._aclPointArray[rFace._aulPoints[j]];
|
| | Base::Vector3f cVec2 = _rclMesh._aclPointArray[rFace._aulPoints[(j + 2) % 3]]
|
| | - _rclMesh._aclPointArray[rFace._aulPoints[j]];
|
| |
|
| |
|
| | if (cVec1 * cVec2 < 0.0F) {
|
| | FacetIndex uN1 = rFace._aulNeighbours[(j + 1) % 3];
|
| | if (uN1 != FACET_INDEX_MAX) {
|
| |
|
| | MeshFacet& rNb = _rclMesh._aclFacetArray[uN1];
|
| | unsigned short side = rNb.Side(index);
|
| |
|
| |
|
| | rFace._aulPoints[(j + 2) % 3] = rNb._aulPoints[(side + 2) % 3];
|
| | rNb._aulPoints[(side + 1) % 3] = rFace._aulPoints[j];
|
| |
|
| |
|
| | FacetIndex uN2 = rFace._aulNeighbours[(j + 2) % 3];
|
| | rNb._aulNeighbours[side] = uN2;
|
| | if (uN2 != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[uN2].ReplaceNeighbour(index, uN1);
|
| | }
|
| | FacetIndex uN3 = rNb._aulNeighbours[(side + 1) % 3];
|
| | rFace._aulNeighbours[(j + 1) % 3] = uN3;
|
| | if (uN3 != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[uN3].ReplaceNeighbour(uN1, index);
|
| | }
|
| | rNb._aulNeighbours[(side + 1) % 3] = index;
|
| | rFace._aulNeighbours[(j + 2) % 3] = uN1;
|
| | }
|
| | else {
|
| | _rclMesh.DeleteFacet(index);
|
| | }
|
| |
|
| | return true;
|
| | }
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | bool MeshTopoAlgorithm::RemoveCorruptedFacet(FacetIndex index)
|
| | {
|
| | if (index >= _rclMesh._aclFacetArray.size()) {
|
| | return false;
|
| | }
|
| | MeshFacet& rFace = _rclMesh._aclFacetArray[index];
|
| |
|
| |
|
| | for (int i = 0; i < 3; i++) {
|
| | if (rFace._aulPoints[i] == rFace._aulPoints[(i + 1) % 3]) {
|
| | FacetIndex uN1 = rFace._aulNeighbours[(i + 1) % 3];
|
| | FacetIndex uN2 = rFace._aulNeighbours[(i + 2) % 3];
|
| | if (uN2 != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[uN2].ReplaceNeighbour(index, uN1);
|
| | }
|
| | if (uN1 != FACET_INDEX_MAX) {
|
| | _rclMesh._aclFacetArray[uN1].ReplaceNeighbour(index, uN2);
|
| | }
|
| |
|
| |
|
| | rFace._aulNeighbours[0] = FACET_INDEX_MAX;
|
| | rFace._aulNeighbours[1] = FACET_INDEX_MAX;
|
| | rFace._aulNeighbours[2] = FACET_INDEX_MAX;
|
| | _rclMesh.DeleteFacet(index);
|
| | return true;
|
| | }
|
| | }
|
| |
|
| | return false;
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::FillupHoles(
|
| | unsigned long length,
|
| | int level,
|
| | AbstractPolygonTriangulator& cTria,
|
| | std::list<std::vector<PointIndex>>& aFailed
|
| | )
|
| | {
|
| |
|
| | std::list<std::vector<PointIndex>> aBorders, aFillBorders;
|
| | MeshAlgorithm cAlgo(_rclMesh);
|
| | cAlgo.GetMeshBorders(aBorders);
|
| |
|
| |
|
| | cAlgo.SplitBoundaryLoops(aBorders);
|
| |
|
| | for (const auto& aBorder : aBorders) {
|
| | if (aBorder.size() - 1 <= length) {
|
| | aFillBorders.push_back(aBorder);
|
| | }
|
| | }
|
| |
|
| | if (!aFillBorders.empty()) {
|
| | FillupHoles(level, cTria, aFillBorders, aFailed);
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::FillupHoles(
|
| | int level,
|
| | AbstractPolygonTriangulator& cTria,
|
| | const std::list<std::vector<PointIndex>>& aBorders,
|
| | std::list<std::vector<PointIndex>>& aFailed
|
| | )
|
| | {
|
| |
|
| | MeshRefPointToFacets cPt2Fac(_rclMesh);
|
| | MeshAlgorithm cAlgo(_rclMesh);
|
| |
|
| | MeshFacetArray newFacets;
|
| | MeshPointArray newPoints;
|
| | unsigned long numberOfOldPoints = _rclMesh._aclPointArray.size();
|
| | for (const auto& aBorder : aBorders) {
|
| | MeshFacetArray cFacets;
|
| | MeshPointArray cPoints;
|
| | std::vector<PointIndex> bound = aBorder;
|
| | if (cAlgo.FillupHole(bound, cTria, cFacets, cPoints, level, &cPt2Fac)) {
|
| | if (bound.front() == bound.back()) {
|
| | bound.pop_back();
|
| | }
|
| |
|
| |
|
| | if (cPoints.size() > bound.size()) {
|
| | unsigned long countBoundaryPoints = bound.size();
|
| | unsigned long countDifference = cPoints.size() - countBoundaryPoints;
|
| | MeshPointArray::_TIterator pt = cPoints.begin() + countBoundaryPoints;
|
| | for (unsigned long i = 0; i < countDifference; i++, pt++) {
|
| | bound.push_back(numberOfOldPoints++);
|
| | newPoints.push_back(*pt);
|
| | }
|
| | }
|
| | if (cTria.NeedsReindexing()) {
|
| | for (auto& cFacet : cFacets) {
|
| | cFacet._aulPoints[0] = bound[cFacet._aulPoints[0]];
|
| | cFacet._aulPoints[1] = bound[cFacet._aulPoints[1]];
|
| | cFacet._aulPoints[2] = bound[cFacet._aulPoints[2]];
|
| | newFacets.push_back(cFacet);
|
| | }
|
| | }
|
| | else {
|
| | for (auto& cFacet : cFacets) {
|
| | newFacets.push_back(cFacet);
|
| | }
|
| | }
|
| | }
|
| | else {
|
| | aFailed.push_back(aBorder);
|
| | }
|
| | }
|
| |
|
| |
|
| | _rclMesh._aclPointArray.insert(_rclMesh._aclPointArray.end(), newPoints.begin(), newPoints.end());
|
| | for (const auto& newPoint : newPoints) {
|
| | _rclMesh._clBoundBox.Add(newPoint);
|
| | }
|
| | if (!newFacets.empty()) {
|
| |
|
| | MeshFacetArray addFacets;
|
| | addFacets.reserve(newFacets.size());
|
| | unsigned long ctPoints = _rclMesh.CountPoints();
|
| | for (auto& newFacet : newFacets) {
|
| | if (newFacet._aulPoints[0] >= ctPoints || newFacet._aulPoints[1] >= ctPoints
|
| | || newFacet._aulPoints[2] >= ctPoints) {
|
| | Base::Console().log(
|
| | "Ignore invalid face <%d, %d, %d> (%d vertices)\n",
|
| | newFacet._aulPoints[0],
|
| | newFacet._aulPoints[1],
|
| | newFacet._aulPoints[2],
|
| | ctPoints
|
| | );
|
| | }
|
| | else {
|
| | addFacets.push_back(newFacet);
|
| | }
|
| | }
|
| | _rclMesh.AddFacets(addFacets, true);
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::FindHoles(unsigned long length, std::list<std::vector<PointIndex>>& aBorders) const
|
| | {
|
| | std::list<std::vector<PointIndex>> border;
|
| | MeshAlgorithm cAlgo(_rclMesh);
|
| | cAlgo.GetMeshBorders(border);
|
| | for (const auto& it : border) {
|
| | if (it.size() <= length) {
|
| | aBorders.push_back(it);
|
| | }
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::FindComponents(unsigned long count, std::vector<FacetIndex>& findIndices)
|
| | {
|
| | std::vector<std::vector<FacetIndex>> segments;
|
| | MeshComponents comp(_rclMesh);
|
| | comp.SearchForComponents(MeshComponents::OverEdge, segments);
|
| |
|
| | for (const auto& segment : segments) {
|
| | if (segment.size() <= count) {
|
| | findIndices.insert(findIndices.end(), segment.begin(), segment.end());
|
| | }
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::RemoveComponents(unsigned long count)
|
| | {
|
| | std::vector<FacetIndex> removeFacets;
|
| | FindComponents(count, removeFacets);
|
| | if (!removeFacets.empty()) {
|
| | _rclMesh.DeleteFacets(removeFacets);
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::HarmonizeNormals()
|
| | {
|
| | std::vector<FacetIndex> uIndices = MeshEvalOrientation(_rclMesh).GetIndices();
|
| | for (FacetIndex index : uIndices) {
|
| | _rclMesh._aclFacetArray[index].FlipNormal();
|
| | }
|
| | }
|
| |
|
| | void MeshTopoAlgorithm::FlipNormals()
|
| | {
|
| | for (auto i = _rclMesh._aclFacetArray.begin(); i < _rclMesh._aclFacetArray.end(); ++i) {
|
| | i->FlipNormal();
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | MeshComponents::MeshComponents(const MeshKernel& rclMesh)
|
| | : _rclMesh(rclMesh)
|
| | {}
|
| |
|
| | void MeshComponents::SearchForComponents(TMode tMode, std::vector<std::vector<FacetIndex>>& aclT) const
|
| | {
|
| |
|
| | std::vector<FacetIndex> aulAllFacets(_rclMesh.CountFacets());
|
| | FacetIndex k = 0;
|
| | for (FacetIndex& aulAllFacet : aulAllFacets) {
|
| | aulAllFacet = k++;
|
| | }
|
| |
|
| | SearchForComponents(tMode, aulAllFacets, aclT);
|
| | }
|
| |
|
| | void MeshComponents::SearchForComponents(
|
| | TMode tMode,
|
| | const std::vector<FacetIndex>& aSegment,
|
| | std::vector<std::vector<FacetIndex>>& aclT
|
| | ) const
|
| | {
|
| | FacetIndex ulStartFacet {};
|
| |
|
| | if (_rclMesh.CountFacets() == 0) {
|
| | return;
|
| | }
|
| |
|
| |
|
| | MeshAlgorithm cAlgo(_rclMesh);
|
| | cAlgo.SetFacetFlag(MeshFacet::VISIT);
|
| | cAlgo.ResetFacetsFlag(aSegment, MeshFacet::VISIT);
|
| |
|
| | const MeshFacetArray& rFAry = _rclMesh.GetFacets();
|
| | MeshFacetArray::_TConstIterator iTri = rFAry.begin();
|
| | MeshFacetArray::_TConstIterator iBeg = rFAry.begin();
|
| | MeshFacetArray::_TConstIterator iEnd = rFAry.end();
|
| |
|
| |
|
| | unsigned long ulVisited = cAlgo.CountFacetFlag(MeshFacet::VISIT);
|
| | MeshIsNotFlag<MeshFacet> flag;
|
| | iTri = std::find_if(iTri, iEnd, [flag](const MeshFacet& f) { return flag(f, MeshFacet::VISIT); });
|
| | ulStartFacet = iTri - iBeg;
|
| |
|
| |
|
| | std::vector<FacetIndex> aclComponent;
|
| | std::vector<std::vector<FacetIndex>> aclConnectComp;
|
| | MeshTopFacetVisitor clFVisitor(aclComponent);
|
| |
|
| | while (ulStartFacet != FACET_INDEX_MAX) {
|
| |
|
| | aclComponent.clear();
|
| | if (tMode == OverEdge) {
|
| | ulVisited += _rclMesh.VisitNeighbourFacets(clFVisitor, ulStartFacet);
|
| | }
|
| | else if (tMode == OverPoint) {
|
| | ulVisited += _rclMesh.VisitNeighbourFacetsOverCorners(clFVisitor, ulStartFacet);
|
| | }
|
| |
|
| |
|
| | aclComponent.push_back(ulStartFacet);
|
| | aclConnectComp.push_back(aclComponent);
|
| |
|
| |
|
| |
|
| |
|
| | iTri = std::find_if(iTri, iEnd, [flag](const MeshFacet& f) {
|
| | return flag(f, MeshFacet::VISIT);
|
| | });
|
| |
|
| | if (iTri < iEnd) {
|
| | ulStartFacet = iTri - iBeg;
|
| | }
|
| | else {
|
| | ulStartFacet = FACET_INDEX_MAX;
|
| | }
|
| | }
|
| |
|
| |
|
| | std::sort(aclConnectComp.begin(), aclConnectComp.end(), CNofFacetsCompare());
|
| | aclT = aclConnectComp;
|
| | boost::ignore_unused(ulVisited);
|
| | }
|
| |
|