| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| | #include <algorithm> |
| | #include <vector> |
| |
|
| |
|
| | #include <Base/Matrix.h> |
| | #include <Base/Sequencer.h> |
| |
|
| | #include "Algorithm.h" |
| | #include "Approximation.h" |
| | #include "Evaluation.h" |
| | #include "Functional.h" |
| | #include "Grid.h" |
| | #include "Iterator.h" |
| | #include "TopoAlgorithm.h" |
| |
|
| |
|
| | using namespace MeshCore; |
| |
|
| |
|
| | MeshOrientationVisitor::MeshOrientationVisitor() = default; |
| |
|
| | bool MeshOrientationVisitor::Visit( |
| | const MeshFacet& rclFacet, |
| | const MeshFacet& rclFrom, |
| | FacetIndex ulFInd, |
| | unsigned long ulLevel |
| | ) |
| | { |
| | (void)ulFInd; |
| | (void)ulLevel; |
| | if (!rclFrom.HasSameOrientation(rclFacet)) { |
| | _nonuniformOrientation = true; |
| | return false; |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | bool MeshOrientationVisitor::HasNonUnifomOrientedFacets() const |
| | { |
| | return _nonuniformOrientation; |
| | } |
| |
|
| | MeshOrientationCollector::MeshOrientationCollector( |
| | std::vector<FacetIndex>& aulIndices, |
| | std::vector<FacetIndex>& aulComplement |
| | ) |
| | : _aulIndices(aulIndices) |
| | , _aulComplement(aulComplement) |
| | {} |
| |
|
| | bool MeshOrientationCollector::Visit( |
| | const MeshFacet& rclFacet, |
| | const MeshFacet& rclFrom, |
| | FacetIndex ulFInd, |
| | unsigned long ulLevel |
| | ) |
| | { |
| | (void)ulLevel; |
| | |
| | if (!rclFacet.HasSameOrientation(rclFrom)) { |
| | |
| | if (!rclFrom.IsFlag(MeshFacet::TMP0)) { |
| | |
| | rclFacet.SetFlag(MeshFacet::TMP0); |
| | _aulIndices.push_back(ulFInd); |
| | } |
| | else { |
| | _aulComplement.push_back(ulFInd); |
| | } |
| | } |
| | else { |
| | |
| | |
| | if (rclFrom.IsFlag(MeshFacet::TMP0)) { |
| | |
| | rclFacet.SetFlag(MeshFacet::TMP0); |
| | _aulIndices.push_back(ulFInd); |
| | } |
| | else { |
| | _aulComplement.push_back(ulFInd); |
| | } |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | MeshSameOrientationCollector::MeshSameOrientationCollector(std::vector<FacetIndex>& aulIndices) |
| | : _aulIndices(aulIndices) |
| | {} |
| |
|
| | bool MeshSameOrientationCollector::Visit( |
| | const MeshFacet& rclFacet, |
| | const MeshFacet& rclFrom, |
| | FacetIndex ulFInd, |
| | unsigned long ulLevel |
| | ) |
| | { |
| | |
| | (void)ulLevel; |
| | if (rclFacet.HasSameOrientation(rclFrom)) { |
| | _aulIndices.push_back(ulFInd); |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | |
| |
|
| | MeshEvalOrientation::MeshEvalOrientation(const MeshKernel& rclM) |
| | : MeshEvaluation(rclM) |
| | {} |
| |
|
| | bool MeshEvalOrientation::Evaluate() |
| | { |
| | const MeshFacetArray& rFAry = _rclMesh.GetFacets(); |
| | MeshFacetArray::_TConstIterator iBeg = rFAry.begin(); |
| | MeshFacetArray::_TConstIterator iEnd = rFAry.end(); |
| | for (auto it = iBeg; it != iEnd; ++it) { |
| | for (int i = 0; i < 3; i++) { |
| | if (it->_aulNeighbours[i] != FACET_INDEX_MAX) { |
| | const MeshFacet& rclFacet = iBeg[it->_aulNeighbours[i]]; |
| | for (int j = 0; j < 3; j++) { |
| | if (it->_aulPoints[i] == rclFacet._aulPoints[j]) { |
| | if ((it->_aulPoints[(i + 1) % 3] == rclFacet._aulPoints[(j + 1) % 3]) |
| | || (it->_aulPoints[(i + 2) % 3] == rclFacet._aulPoints[(j + 2) % 3])) { |
| | return false; |
| | } |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | unsigned long MeshEvalOrientation::HasFalsePositives(const std::vector<FacetIndex>& inds) const |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | const MeshFacetArray& rFAry = _rclMesh.GetFacets(); |
| | MeshFacetArray::_TConstIterator iBeg = rFAry.begin(); |
| | for (FacetIndex it : inds) { |
| | const MeshFacet& f = iBeg[it]; |
| | for (FacetIndex nbIndex : f._aulNeighbours) { |
| | if (nbIndex != FACET_INDEX_MAX) { |
| | const MeshFacet& n = iBeg[nbIndex]; |
| | if (f.IsFlag(MeshFacet::TMP0) && !n.IsFlag(MeshFacet::TMP0)) { |
| | for (int j = 0; j < 3; j++) { |
| | if (f.HasSameOrientation(n)) { |
| | |
| | return nbIndex; |
| | } |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | return FACET_INDEX_MAX; |
| | } |
| |
|
| | std::vector<FacetIndex> MeshEvalOrientation::GetIndices() const |
| | { |
| | FacetIndex ulStartFacet {}, ulVisited {}; |
| |
|
| | if (_rclMesh.CountFacets() == 0) { |
| | return {}; |
| | } |
| |
|
| | |
| | MeshAlgorithm cAlg(_rclMesh); |
| | cAlg.ResetFacetFlag(MeshFacet::VISIT); |
| | cAlg.ResetFacetFlag(MeshFacet::TMP0); |
| |
|
| | const MeshFacetArray& rFAry = _rclMesh.GetFacets(); |
| | MeshFacetArray::_TConstIterator iTri = rFAry.begin(); |
| | MeshFacetArray::_TConstIterator iBeg = rFAry.begin(); |
| | MeshFacetArray::_TConstIterator iEnd = rFAry.end(); |
| |
|
| | ulStartFacet = 0; |
| |
|
| | std::vector<FacetIndex> uIndices, uComplement; |
| | MeshOrientationCollector clHarmonizer(uIndices, uComplement); |
| |
|
| | while (ulStartFacet != FACET_INDEX_MAX) { |
| | unsigned long wrongFacets = uIndices.size(); |
| |
|
| | uComplement.clear(); |
| | uComplement.push_back(ulStartFacet); |
| | ulVisited = _rclMesh.VisitNeighbourFacets(clHarmonizer, ulStartFacet) + 1; |
| |
|
| | |
| | |
| | |
| | if (uComplement.size() < static_cast<unsigned long>(0.4F * static_cast<float>(ulVisited))) { |
| | uIndices.erase(uIndices.begin() + wrongFacets, uIndices.end()); |
| | uIndices.insert(uIndices.end(), uComplement.begin(), uComplement.end()); |
| | } |
| |
|
| | |
| | |
| | |
| | MeshIsNotFlag<MeshFacet> flag; |
| | 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; |
| | } |
| | } |
| |
|
| | |
| | |
| | cAlg.ResetFacetFlag(MeshFacet::TMP0); |
| | cAlg.SetFacetsFlag(uIndices, MeshFacet::TMP0); |
| | ulStartFacet = HasFalsePositives(uIndices); |
| | while (ulStartFacet != FACET_INDEX_MAX) { |
| | cAlg.ResetFacetsFlag(uIndices, MeshFacet::VISIT); |
| | std::vector<FacetIndex> falsePos; |
| | MeshSameOrientationCollector coll(falsePos); |
| | _rclMesh.VisitNeighbourFacets(coll, ulStartFacet); |
| |
|
| | std::sort(uIndices.begin(), uIndices.end()); |
| | std::sort(falsePos.begin(), falsePos.end()); |
| |
|
| | std::vector<FacetIndex> diff; |
| | std::back_insert_iterator<std::vector<FacetIndex>> biit(diff); |
| | std::set_difference(uIndices.begin(), uIndices.end(), falsePos.begin(), falsePos.end(), biit); |
| | uIndices = diff; |
| |
|
| | cAlg.ResetFacetFlag(MeshFacet::TMP0); |
| | cAlg.SetFacetsFlag(uIndices, MeshFacet::TMP0); |
| | FacetIndex current = ulStartFacet; |
| | ulStartFacet = HasFalsePositives(uIndices); |
| | if (current == ulStartFacet) { |
| | break; |
| | } |
| | } |
| |
|
| | return uIndices; |
| | } |
| |
|
| | MeshFixOrientation::MeshFixOrientation(MeshKernel& rclM) |
| | : MeshValidation(rclM) |
| | {} |
| |
|
| | bool MeshFixOrientation::Fixup() |
| | { |
| | MeshTopoAlgorithm(_rclMesh).HarmonizeNormals(); |
| | return MeshEvalOrientation(_rclMesh).Evaluate(); |
| | } |
| |
|
| | |
| |
|
| | MeshEvalSolid::MeshEvalSolid(const MeshKernel& rclM) |
| | : MeshEvaluation(rclM) |
| | {} |
| |
|
| | bool MeshEvalSolid::Evaluate() |
| | { |
| | std::vector<MeshGeomEdge> edges; |
| | _rclMesh.GetEdges(edges); |
| | for (const auto& it : edges) { |
| | if (it._bBorder) { |
| | return false; |
| | } |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | |
| |
|
| | namespace MeshCore |
| | { |
| |
|
| | struct Edge_Index |
| | { |
| | PointIndex p0, p1; |
| | FacetIndex f; |
| | }; |
| |
|
| | struct Edge_Less |
| | { |
| | bool operator()(const Edge_Index& x, const Edge_Index& y) const |
| | { |
| | if (x.p0 < y.p0) { |
| | return true; |
| | } |
| | if (x.p0 > y.p0) { |
| | return false; |
| | } |
| | if (x.p1 < y.p1) { |
| | return true; |
| | } |
| | if (x.p1 > y.p1) { |
| | return false; |
| | } |
| | return false; |
| | } |
| | }; |
| |
|
| | } |
| |
|
| | bool MeshEvalTopology::Evaluate() |
| | { |
| | |
| | |
| | const MeshFacetArray& rclFAry = _rclMesh.GetFacets(); |
| | std::vector<Edge_Index> edges; |
| | edges.reserve(3 * rclFAry.size()); |
| |
|
| | |
| | MeshFacetArray::_TConstIterator pI; |
| | Base::SequencerLauncher seq("Checking topology...", rclFAry.size()); |
| | for (pI = rclFAry.begin(); pI != rclFAry.end(); ++pI) { |
| | for (int i = 0; i < 3; i++) { |
| | Edge_Index item {}; |
| | item.p0 = std::min<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]); |
| | item.p1 = std::max<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]); |
| | item.f = pI - rclFAry.begin(); |
| | edges.push_back(item); |
| | } |
| |
|
| | seq.next(); |
| | } |
| |
|
| | |
| | std::sort(edges.begin(), edges.end(), Edge_Less()); |
| |
|
| | |
| | PointIndex p0 = POINT_INDEX_MAX, p1 = POINT_INDEX_MAX; |
| | nonManifoldList.clear(); |
| | nonManifoldFacets.clear(); |
| |
|
| | int count = 0; |
| | std::vector<FacetIndex> facets; |
| | std::vector<Edge_Index>::iterator pE; |
| | for (pE = edges.begin(); pE != edges.end(); ++pE) { |
| | if (p0 == pE->p0 && p1 == pE->p1) { |
| | count++; |
| | facets.push_back(pE->f); |
| | } |
| | else { |
| | if (count > 2) { |
| | |
| | nonManifoldList.emplace_back(p0, p1); |
| | nonManifoldFacets.push_back(facets); |
| | } |
| |
|
| | p0 = pE->p0; |
| | p1 = pE->p1; |
| | facets.clear(); |
| | facets.push_back(pE->f); |
| | count = 1; |
| | } |
| | } |
| |
|
| | return nonManifoldList.empty(); |
| | } |
| |
|
| | |
| | void MeshEvalTopology::GetFacetManifolds(std::vector<FacetIndex>& raclFacetIndList) const |
| | { |
| | raclFacetIndList.clear(); |
| | const MeshFacetArray& rclFAry = _rclMesh.GetFacets(); |
| | MeshFacetArray::_TConstIterator pI; |
| |
|
| | for (pI = rclFAry.begin(); pI != rclFAry.end(); ++pI) { |
| | for (int i = 0; i < 3; i++) { |
| | 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]); |
| | std::pair<PointIndex, PointIndex> edge = std::make_pair(ulPt0, ulPt1); |
| |
|
| | if (std::ranges::find(nonManifoldList, edge) != nonManifoldList.end()) { |
| | raclFacetIndList.push_back(pI - rclFAry.begin()); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | unsigned long MeshEvalTopology::CountManifolds() const |
| | { |
| | return nonManifoldList.size(); |
| | } |
| |
|
| | bool MeshFixTopology::Fixup() |
| | { |
| | #if 0 |
| | MeshEvalTopology eval(_rclMesh); |
| | if (!eval.Evaluate()) { |
| | eval.GetFacetManifolds(deletedFaces); |
| |
|
| | |
| | std::sort(deletedFaces.begin(), deletedFaces.end()); |
| | deletedFaces.erase(std::unique(deletedFaces.begin(), deletedFaces.end()), deletedFaces.end()); |
| |
|
| | _rclMesh.DeleteFacets(deletedFaces); |
| | } |
| | #else |
| | const MeshFacetArray& rFaces = _rclMesh.GetFacets(); |
| | deletedFaces.reserve(3 * nonManifoldList.size()); |
| | for (const auto& it : nonManifoldList) { |
| | std::vector<FacetIndex> non_mf; |
| | non_mf.reserve(it.size()); |
| | for (FacetIndex jt : it) { |
| | |
| | unsigned short numOpenEdges = rFaces[jt].CountOpenEdges(); |
| | if (numOpenEdges == 2) { |
| | non_mf.push_back(jt); |
| | } |
| | else if (rFaces[jt].IsDegenerated()) { |
| | non_mf.push_back(jt); |
| | } |
| | } |
| |
|
| | |
| | if (it.size() - non_mf.size() == 2) { |
| | deletedFaces.insert(deletedFaces.end(), non_mf.begin(), non_mf.end()); |
| | } |
| | else { |
| | deletedFaces.insert(deletedFaces.end(), it.begin(), it.end()); |
| | } |
| | } |
| |
|
| | if (!deletedFaces.empty()) { |
| | |
| | std::sort(deletedFaces.begin(), deletedFaces.end()); |
| | deletedFaces.erase(std::unique(deletedFaces.begin(), deletedFaces.end()), deletedFaces.end()); |
| |
|
| | _rclMesh.DeleteFacets(deletedFaces); |
| | _rclMesh.RebuildNeighbours(); |
| | } |
| | #endif |
| |
|
| | return true; |
| | } |
| |
|
| | |
| |
|
| | bool MeshEvalPointManifolds::Evaluate() |
| | { |
| | this->nonManifoldPoints.clear(); |
| | this->facetsOfNonManifoldPoints.clear(); |
| |
|
| | MeshCore::MeshRefPointToPoints vv_it(_rclMesh); |
| | MeshCore::MeshRefPointToFacets vf_it(_rclMesh); |
| |
|
| | unsigned long ctPoints = _rclMesh.CountPoints(); |
| | for (PointIndex index = 0; index < ctPoints; index++) { |
| | |
| | const std::set<FacetIndex>& nf = vf_it[index]; |
| | const std::set<PointIndex>& np = vv_it[index]; |
| |
|
| | std::set<unsigned long>::size_type sp {}, sf {}; |
| | sp = np.size(); |
| | sf = nf.size(); |
| | |
| | |
| | |
| | |
| | if (sp > sf + 1) { |
| | nonManifoldPoints.push_back(index); |
| | std::vector<FacetIndex> faces; |
| | faces.insert(faces.end(), nf.begin(), nf.end()); |
| | this->facetsOfNonManifoldPoints.push_back(faces); |
| | } |
| | } |
| |
|
| | return this->nonManifoldPoints.empty(); |
| | } |
| |
|
| | void MeshEvalPointManifolds::GetFacetIndices(std::vector<FacetIndex>& facets) const |
| | { |
| | std::list<std::vector<FacetIndex>>::const_iterator it; |
| | for (it = facetsOfNonManifoldPoints.begin(); it != facetsOfNonManifoldPoints.end(); ++it) { |
| | facets.insert(facets.end(), it->begin(), it->end()); |
| | } |
| |
|
| | if (!facets.empty()) { |
| | |
| | std::sort(facets.begin(), facets.end()); |
| | facets.erase(std::unique(facets.begin(), facets.end()), facets.end()); |
| | } |
| | } |
| |
|
| | |
| |
|
| | bool MeshEvalSingleFacet::Evaluate() |
| | { |
| | |
| | (void)MeshEvalTopology::Evaluate(); |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | return (nonManifoldList.empty()); |
| | } |
| |
|
| | bool MeshFixSingleFacet::Fixup() |
| | { |
| | std::vector<FacetIndex> aulInvalids; |
| | for (const auto& it : _raclManifoldList) { |
| | for (FacetIndex it2 : it) { |
| | aulInvalids.push_back(it2); |
| | } |
| | } |
| |
|
| | _rclMesh.DeleteFacets(aulInvalids); |
| | return true; |
| | } |
| |
|
| | |
| |
|
| | bool MeshEvalSelfIntersection::Evaluate() |
| | { |
| | |
| | std::vector<Base::BoundBox3f> boxes; |
| |
|
| | |
| | MeshFacetGrid cMeshFacetGrid(_rclMesh); |
| | const MeshFacetArray& rFaces = _rclMesh.GetFacets(); |
| | MeshGridIterator clGridIter(cMeshFacetGrid); |
| | unsigned long ulGridX {}, ulGridY {}, ulGridZ {}; |
| | cMeshFacetGrid.GetCtGrids(ulGridX, ulGridY, ulGridZ); |
| |
|
| | MeshFacetIterator cMFI(_rclMesh); |
| | for (cMFI.Begin(); cMFI.More(); cMFI.Next()) { |
| | boxes.push_back((*cMFI).GetBoundBox()); |
| | } |
| |
|
| | |
| | Base::SequencerLauncher seq("Checking for self-intersections...", ulGridX * ulGridY * ulGridZ); |
| | for (clGridIter.Init(); clGridIter.More(); clGridIter.Next()) { |
| | |
| | std::vector<FacetIndex> aulGridElements; |
| | clGridIter.GetElements(aulGridElements); |
| |
|
| | seq.next(); |
| | if (aulGridElements.empty()) { |
| | continue; |
| | } |
| |
|
| | MeshGeomFacet facet1, facet2; |
| | Base::Vector3f pt1, pt2; |
| | for (auto it = aulGridElements.begin(); it != aulGridElements.end(); ++it) { |
| | const Base::BoundBox3f& box1 = boxes[*it]; |
| | cMFI.Set(*it); |
| | facet1 = *cMFI; |
| | const MeshFacet& rface1 = rFaces[*it]; |
| | for (auto jt = it; jt != aulGridElements.end(); ++jt) { |
| | if (jt == it) { |
| | continue; |
| | } |
| | |
| | |
| | |
| | const MeshFacet& rface2 = rFaces[*jt]; |
| | if (rface1._aulPoints[0] == rface2._aulPoints[0] |
| | || rface1._aulPoints[0] == rface2._aulPoints[1] |
| | || rface1._aulPoints[0] == rface2._aulPoints[2]) { |
| | continue; |
| | } |
| | if (rface1._aulPoints[1] == rface2._aulPoints[0] |
| | || rface1._aulPoints[1] == rface2._aulPoints[1] |
| | || rface1._aulPoints[1] == rface2._aulPoints[2]) { |
| | continue; |
| | } |
| | if (rface1._aulPoints[2] == rface2._aulPoints[0] |
| | || rface1._aulPoints[2] == rface2._aulPoints[1] |
| | || rface1._aulPoints[2] == rface2._aulPoints[2]) { |
| | continue; |
| | } |
| |
|
| | const Base::BoundBox3f& box2 = boxes[*jt]; |
| | if (box1 && box2) { |
| | cMFI.Set(*jt); |
| | facet2 = *cMFI; |
| | int ret = facet1.IntersectWithFacet(facet2, pt1, pt2); |
| | if (ret == 2) { |
| | |
| | return false; |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | void MeshEvalSelfIntersection::GetIntersections( |
| | const std::vector<std::pair<FacetIndex, FacetIndex>>& indices, |
| | std::vector<std::pair<Base::Vector3f, Base::Vector3f>>& intersection |
| | ) const |
| | { |
| | intersection.reserve(indices.size()); |
| | MeshFacetIterator cMF1(_rclMesh); |
| | MeshFacetIterator cMF2(_rclMesh); |
| |
|
| | Base::Vector3f pt1, pt2; |
| | std::vector<std::pair<FacetIndex, FacetIndex>>::const_iterator it; |
| | for (it = indices.begin(); it != indices.end(); ++it) { |
| | cMF1.Set(it->first); |
| | cMF2.Set(it->second); |
| |
|
| | Base::BoundBox3f box1 = cMF1->GetBoundBox(); |
| | Base::BoundBox3f box2 = cMF2->GetBoundBox(); |
| | if (box1 && box2) { |
| | int ret = cMF1->IntersectWithFacet(*cMF2, pt1, pt2); |
| | if (ret == 2) { |
| | intersection.emplace_back(pt1, pt2); |
| | } |
| | } |
| | } |
| | } |
| |
|
| | void MeshEvalSelfIntersection::GetIntersections( |
| | std::vector<std::pair<FacetIndex, FacetIndex>>& intersection |
| | ) const |
| | { |
| | |
| | std::vector<Base::BoundBox3f> boxes; |
| | |
| |
|
| | |
| | MeshFacetGrid cMeshFacetGrid(_rclMesh); |
| | const MeshFacetArray& rFaces = _rclMesh.GetFacets(); |
| | MeshGridIterator clGridIter(cMeshFacetGrid); |
| | unsigned long ulGridX {}, ulGridY {}, ulGridZ {}; |
| | cMeshFacetGrid.GetCtGrids(ulGridX, ulGridY, ulGridZ); |
| |
|
| | MeshFacetIterator cMFI(_rclMesh); |
| | for (cMFI.Begin(); cMFI.More(); cMFI.Next()) { |
| | boxes.push_back((*cMFI).GetBoundBox()); |
| | } |
| |
|
| | |
| | Base::SequencerLauncher seq("Checking for self-intersections...", ulGridX * ulGridY * ulGridZ); |
| | for (clGridIter.Init(); clGridIter.More(); clGridIter.Next()) { |
| | |
| | std::vector<FacetIndex> aulGridElements; |
| | clGridIter.GetElements(aulGridElements); |
| |
|
| | seq.next(true); |
| | if (aulGridElements.empty()) { |
| | continue; |
| | } |
| |
|
| | MeshGeomFacet facet1, facet2; |
| | Base::Vector3f pt1, pt2; |
| | for (auto it = aulGridElements.begin(); it != aulGridElements.end(); ++it) { |
| | const Base::BoundBox3f& box1 = boxes[*it]; |
| | cMFI.Set(*it); |
| | facet1 = *cMFI; |
| | const MeshFacet& rface1 = rFaces[*it]; |
| | for (auto jt = it; jt != aulGridElements.end(); ++jt) { |
| | if (jt == it) { |
| | continue; |
| | } |
| | |
| | |
| | |
| | const MeshFacet& rface2 = rFaces[*jt]; |
| | if (rface1._aulPoints[0] == rface2._aulPoints[0] |
| | || rface1._aulPoints[0] == rface2._aulPoints[1] |
| | || rface1._aulPoints[0] == rface2._aulPoints[2]) { |
| | continue; |
| | } |
| | if (rface1._aulPoints[1] == rface2._aulPoints[0] |
| | || rface1._aulPoints[1] == rface2._aulPoints[1] |
| | || rface1._aulPoints[1] == rface2._aulPoints[2]) { |
| | continue; |
| | } |
| | if (rface1._aulPoints[2] == rface2._aulPoints[0] |
| | || rface1._aulPoints[2] == rface2._aulPoints[1] |
| | || rface1._aulPoints[2] == rface2._aulPoints[2]) { |
| | continue; |
| | } |
| |
|
| | const Base::BoundBox3f& box2 = boxes[*jt]; |
| | if (box1 && box2) { |
| | cMFI.Set(*jt); |
| | facet2 = *cMFI; |
| | int ret = facet1.IntersectWithFacet(facet2, pt1, pt2); |
| | if (ret == 2) { |
| | intersection.emplace_back(*it, *jt); |
| | } |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | std::vector<FacetIndex> MeshFixSelfIntersection::GetFacets() const |
| | { |
| | std::vector<FacetIndex> indices; |
| | const MeshFacetArray& rFaces = _rclMesh.GetFacets(); |
| | for (const auto& it : selfIntersectons) { |
| | unsigned short numOpenEdges1 = rFaces[it.first].CountOpenEdges(); |
| | unsigned short numOpenEdges2 = rFaces[it.second].CountOpenEdges(); |
| |
|
| | |
| | |
| | if (numOpenEdges1 == 0 && numOpenEdges2 > 0) { |
| | indices.push_back(it.second); |
| | } |
| | else if (numOpenEdges1 > 0 && numOpenEdges2 == 0) { |
| | indices.push_back(it.first); |
| | } |
| | else { |
| | indices.push_back(it.first); |
| | indices.push_back(it.second); |
| | } |
| | } |
| |
|
| | |
| | std::sort(indices.begin(), indices.end()); |
| | indices.erase(std::unique(indices.begin(), indices.end()), indices.end()); |
| |
|
| | return indices; |
| | } |
| |
|
| | bool MeshFixSelfIntersection::Fixup() |
| | { |
| | _rclMesh.DeleteFacets(GetFacets()); |
| | return true; |
| | } |
| |
|
| | |
| |
|
| | bool MeshEvalNeighbourhood::Evaluate() |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const MeshFacetArray& rclFAry = _rclMesh.GetFacets(); |
| | std::vector<Edge_Index> edges; |
| | edges.reserve(3 * rclFAry.size()); |
| |
|
| | |
| | MeshFacetArray::_TConstIterator pI; |
| | Base::SequencerLauncher seq("Checking indices...", rclFAry.size()); |
| | for (pI = rclFAry.begin(); pI != rclFAry.end(); ++pI) { |
| | for (int i = 0; i < 3; i++) { |
| | Edge_Index item {}; |
| | item.p0 = std::min<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]); |
| | item.p1 = std::max<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]); |
| | item.f = pI - rclFAry.begin(); |
| | edges.push_back(item); |
| | } |
| |
|
| | seq.next(); |
| | } |
| |
|
| | |
| | std::sort(edges.begin(), edges.end(), Edge_Less()); |
| |
|
| | PointIndex p0 = POINT_INDEX_MAX, p1 = POINT_INDEX_MAX; |
| | PointIndex f0 = FACET_INDEX_MAX, f1 = FACET_INDEX_MAX; |
| | int count = 0; |
| | std::vector<Edge_Index>::iterator pE; |
| | for (pE = edges.begin(); pE != edges.end(); ++pE) { |
| | if (p0 == pE->p0 && p1 == pE->p1) { |
| | f1 = pE->f; |
| | count++; |
| | } |
| | else { |
| | |
| | |
| | if (count == 2) { |
| | const MeshFacet& rFace0 = rclFAry[f0]; |
| | const MeshFacet& rFace1 = rclFAry[f1]; |
| | unsigned short side0 = rFace0.Side(p0, p1); |
| | unsigned short side1 = rFace1.Side(p0, p1); |
| | |
| | |
| | if (rFace0._aulNeighbours[side0] != f1 || rFace1._aulNeighbours[side1] != f0) { |
| | return false; |
| | } |
| | } |
| | else if (count == 1) { |
| | const MeshFacet& rFace = rclFAry[f0]; |
| | unsigned short side = rFace.Side(p0, p1); |
| | |
| | if (rFace._aulNeighbours[side] != FACET_INDEX_MAX) { |
| | return false; |
| | } |
| | } |
| |
|
| | p0 = pE->p0; |
| | p1 = pE->p1; |
| | f0 = pE->f; |
| | count = 1; |
| | } |
| | } |
| |
|
| | return true; |
| | } |
| |
|
| | std::vector<FacetIndex> MeshEvalNeighbourhood::GetIndices() const |
| | { |
| | std::vector<FacetIndex> inds; |
| | const MeshFacetArray& rclFAry = _rclMesh.GetFacets(); |
| | std::vector<Edge_Index> edges; |
| | edges.reserve(3 * rclFAry.size()); |
| |
|
| | |
| | MeshFacetArray::_TConstIterator pI; |
| | Base::SequencerLauncher seq("Checking indices...", rclFAry.size()); |
| | for (pI = rclFAry.begin(); pI != rclFAry.end(); ++pI) { |
| | for (int i = 0; i < 3; i++) { |
| | Edge_Index item {}; |
| | item.p0 = std::min<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]); |
| | item.p1 = std::max<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]); |
| | item.f = pI - rclFAry.begin(); |
| | edges.push_back(item); |
| | } |
| |
|
| | seq.next(); |
| | } |
| |
|
| | |
| | std::sort(edges.begin(), edges.end(), Edge_Less()); |
| |
|
| | PointIndex p0 = POINT_INDEX_MAX, p1 = POINT_INDEX_MAX; |
| | PointIndex f0 = FACET_INDEX_MAX, f1 = FACET_INDEX_MAX; |
| | int count = 0; |
| | std::vector<Edge_Index>::iterator pE; |
| | for (pE = edges.begin(); pE != edges.end(); ++pE) { |
| | if (p0 == pE->p0 && p1 == pE->p1) { |
| | f1 = pE->f; |
| | count++; |
| | } |
| | else { |
| | |
| | |
| | if (count == 2) { |
| | const MeshFacet& rFace0 = rclFAry[f0]; |
| | const MeshFacet& rFace1 = rclFAry[f1]; |
| | unsigned short side0 = rFace0.Side(p0, p1); |
| | unsigned short side1 = rFace1.Side(p0, p1); |
| | |
| | |
| | if (rFace0._aulNeighbours[side0] != f1 || rFace1._aulNeighbours[side1] != f0) { |
| | inds.push_back(f0); |
| | inds.push_back(f1); |
| | } |
| | } |
| | else if (count == 1) { |
| | const MeshFacet& rFace = rclFAry[f0]; |
| | unsigned short side = rFace.Side(p0, p1); |
| | |
| | if (rFace._aulNeighbours[side] != FACET_INDEX_MAX) { |
| | inds.push_back(f0); |
| | } |
| | } |
| |
|
| | p0 = pE->p0; |
| | p1 = pE->p1; |
| | f0 = pE->f; |
| | count = 1; |
| | } |
| | } |
| |
|
| | |
| | std::sort(inds.begin(), inds.end()); |
| | inds.erase(std::unique(inds.begin(), inds.end()), inds.end()); |
| |
|
| | return inds; |
| | } |
| |
|
| | bool MeshFixNeighbourhood::Fixup() |
| | { |
| | _rclMesh.RebuildNeighbours(); |
| | return true; |
| | } |
| |
|
| | void MeshKernel::RebuildNeighbours(FacetIndex index) |
| | { |
| | std::vector<Edge_Index> edges; |
| | edges.reserve(3 * (this->_aclFacetArray.size() - index)); |
| |
|
| | |
| | auto pB = this->_aclFacetArray.begin(); |
| | for (auto pI = pB + index; pI != this->_aclFacetArray.end(); ++pI) { |
| | for (int i = 0; i < 3; i++) { |
| | Edge_Index item {}; |
| | item.p0 = std::min<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]); |
| | item.p1 = std::max<PointIndex>(pI->_aulPoints[i], pI->_aulPoints[(i + 1) % 3]); |
| | item.f = pI - pB; |
| | edges.push_back(item); |
| | } |
| | } |
| |
|
| | |
| | |
| | int threads = int(std::thread::hardware_concurrency()); |
| | MeshCore::parallel_sort(edges.begin(), edges.end(), Edge_Less(), threads); |
| |
|
| | PointIndex p0 = POINT_INDEX_MAX, p1 = POINT_INDEX_MAX; |
| | PointIndex f0 = FACET_INDEX_MAX, f1 = FACET_INDEX_MAX; |
| | int count = 0; |
| | std::vector<Edge_Index>::iterator pE; |
| | for (pE = edges.begin(); pE != edges.end(); ++pE) { |
| | if (p0 == pE->p0 && p1 == pE->p1) { |
| | f1 = pE->f; |
| | count++; |
| | } |
| | else { |
| | |
| | |
| | if (count == 2) { |
| | MeshFacet& rFace0 = this->_aclFacetArray[f0]; |
| | MeshFacet& rFace1 = this->_aclFacetArray[f1]; |
| | unsigned short side0 = rFace0.Side(p0, p1); |
| | unsigned short side1 = rFace1.Side(p0, p1); |
| | rFace0._aulNeighbours[side0] = f1; |
| | rFace1._aulNeighbours[side1] = f0; |
| | } |
| | else if (count == 1) { |
| | MeshFacet& rFace = this->_aclFacetArray[f0]; |
| | unsigned short side = rFace.Side(p0, p1); |
| | rFace._aulNeighbours[side] = FACET_INDEX_MAX; |
| | } |
| |
|
| | p0 = pE->p0; |
| | p1 = pE->p1; |
| | f0 = pE->f; |
| | count = 1; |
| | } |
| | } |
| |
|
| | |
| | |
| | if (count == 2) { |
| | MeshFacet& rFace0 = this->_aclFacetArray[f0]; |
| | MeshFacet& rFace1 = this->_aclFacetArray[f1]; |
| | unsigned short side0 = rFace0.Side(p0, p1); |
| | unsigned short side1 = rFace1.Side(p0, p1); |
| | rFace0._aulNeighbours[side0] = f1; |
| | rFace1._aulNeighbours[side1] = f0; |
| | } |
| | else if (count == 1) { |
| | MeshFacet& rFace = this->_aclFacetArray[f0]; |
| | unsigned short side = rFace.Side(p0, p1); |
| | rFace._aulNeighbours[side] = FACET_INDEX_MAX; |
| | } |
| | } |
| |
|
| | void MeshKernel::RebuildNeighbours() |
| | { |
| | |
| | RebuildNeighbours(0); |
| | } |
| |
|
| | |
| |
|
| | MeshEigensystem::MeshEigensystem(const MeshKernel& rclB) |
| | : MeshEvaluation(rclB) |
| | , _cU(1.0F, 0.0F, 0.0F) |
| | , _cV(0.0F, 1.0F, 0.0F) |
| | , _cW(0.0F, 0.0F, 1.0F) |
| | { |
| | |
| | Base::BoundBox3f box = _rclMesh.GetBoundBox(); |
| | _fU = box.LengthX(); |
| | _fV = box.LengthY(); |
| | _fW = box.LengthZ(); |
| | } |
| |
|
| | Base::Matrix4D MeshEigensystem::Transform() const |
| | { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | Base::Matrix4D clTMat; |
| | |
| | clTMat[0][0] = double(_cU.x); |
| | clTMat[0][1] = double(_cU.y); |
| | clTMat[0][2] = double(_cU.z); |
| | clTMat[0][3] = 0.0; |
| | clTMat[1][0] = double(_cV.x); |
| | clTMat[1][1] = double(_cV.y); |
| | clTMat[1][2] = double(_cV.z); |
| | clTMat[1][3] = 0.0; |
| | clTMat[2][0] = double(_cW.x); |
| | clTMat[2][1] = double(_cW.y); |
| | clTMat[2][2] = double(_cW.z); |
| | clTMat[2][3] = 0.0; |
| | clTMat[3][0] = 0.0; |
| | clTMat[3][1] = 0.0; |
| | clTMat[3][2] = 0.0; |
| | clTMat[3][3] = 1.0; |
| |
|
| | Base::Vector3f c(_cC); |
| | c = clTMat * c; |
| |
|
| | |
| | clTMat[0][3] = double(-c.x); |
| | clTMat[1][3] = double(-c.y); |
| | clTMat[2][3] = double(-c.z); |
| |
|
| | return clTMat; |
| | } |
| |
|
| | bool MeshEigensystem::Evaluate() |
| | { |
| | CalculateLocalSystem(); |
| |
|
| | float xmin = 0.0F, xmax = 0.0F, ymin = 0.0F, ymax = 0.0F, zmin = 0.0F, zmax = 0.0F; |
| |
|
| | Base::Vector3f clVect, clProj; |
| | float fH {}; |
| |
|
| | const MeshPointArray& aclPoints = _rclMesh.GetPoints(); |
| | for (const auto& it : aclPoints) { |
| | |
| | clVect = it - _cC; |
| | clProj.ProjectToLine(clVect, _cU); |
| | clVect = clVect + clProj; |
| | fH = clVect.Length(); |
| |
|
| | |
| | if ((clVect * _cU) < 0.0F) { |
| | fH = -fH; |
| | } |
| |
|
| | xmax = std::max<float>(xmax, fH); |
| | xmin = std::min<float>(xmin, fH); |
| |
|
| | |
| | clVect = it - _cC; |
| | clProj.ProjectToLine(clVect, _cV); |
| | clVect = clVect + clProj; |
| | fH = clVect.Length(); |
| |
|
| | |
| | if ((clVect * _cV) < 0.0F) { |
| | fH = -fH; |
| | } |
| |
|
| | ymax = std::max<float>(ymax, fH); |
| | ymin = std::min<float>(ymin, fH); |
| |
|
| | |
| | clVect = it - _cC; |
| | clProj.ProjectToLine(clVect, _cW); |
| | clVect = clVect + clProj; |
| | fH = clVect.Length(); |
| |
|
| | |
| | if ((clVect * _cW) < 0.0F) { |
| | fH = -fH; |
| | } |
| |
|
| | zmax = std::max<float>(zmax, fH); |
| | zmin = std::min<float>(zmin, fH); |
| | } |
| |
|
| | _fU = xmax - xmin; |
| | _fV = ymax - ymin; |
| | _fW = zmax - zmin; |
| |
|
| | return false; |
| | } |
| |
|
| | Base::Vector3f MeshEigensystem::GetBoundings() const |
| | { |
| | return Base::Vector3f(_fU, _fV, _fW); |
| | } |
| |
|
| | void MeshEigensystem::CalculateLocalSystem() |
| | { |
| | |
| | if (_rclMesh.CountFacets() < 1) { |
| | return; |
| | } |
| |
|
| | const MeshPointArray& aclPoints = _rclMesh.GetPoints(); |
| | MeshPointArray::_TConstIterator it; |
| |
|
| | PlaneFit planeFit; |
| | for (it = aclPoints.begin(); it != aclPoints.end(); ++it) { |
| | planeFit.AddPoint(*it); |
| | } |
| |
|
| | planeFit.Fit(); |
| | _cC = planeFit.GetBase(); |
| | _cU = planeFit.GetDirU(); |
| | _cV = planeFit.GetDirV(); |
| | _cW = planeFit.GetNormal(); |
| |
|
| | |
| | float fSumU {0.0F}, fSumV {0.0F}, fSumW {0.0F}; |
| | for (it = aclPoints.begin(); it != aclPoints.end(); ++it) { |
| | float fU = _cU * (*it - _cC); |
| | float fV = _cV * (*it - _cC); |
| | float fW = _cW * (*it - _cC); |
| | fSumU += (fU > 0 ? fU * fU : -fU * fU); |
| | fSumV += (fV > 0 ? fV * fV : -fV * fV); |
| | fSumW += (fW > 0 ? fW * fW : -fW * fW); |
| | } |
| |
|
| | |
| | if (fSumU < 0.0F) { |
| | _cU *= -1.0F; |
| | } |
| | if (fSumV < 0.0F) { |
| | _cV *= -1.0F; |
| | } |
| | if (fSumW < 0.0F) { |
| | _cW *= -1.0F; |
| | } |
| |
|
| | if ((_cU % _cV) * _cW < 0.0F) { |
| | _cW = -_cW; |
| | } |
| | } |
| |
|