/*************************************************************************** * Copyright (c) 2005 Imetric 3D GmbH * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include #endif #include "Tools.h" #include "Iterator.h" using namespace MeshCore; MeshSearchNeighbours::MeshSearchNeighbours (const MeshKernel &rclM, float fSampleDistance) : _rclMesh(rclM), _rclFAry(rclM.GetFacets()), _rclPAry(rclM.GetPoints()), _clPt2Fa(rclM), _fSampleDistance(fSampleDistance) { MeshAlgorithm(_rclMesh).ResetFacetFlag(MeshFacet::MARKED); MeshAlgorithm(_rclMesh).ResetPointFlag(MeshPoint::MARKED); } void MeshSearchNeighbours::Reinit (float fSampleDistance) { _fSampleDistance = fSampleDistance; MeshAlgorithm(_rclMesh).ResetFacetFlag(MeshFacet::MARKED); MeshAlgorithm(_rclMesh).ResetPointFlag(MeshPoint::MARKED); } unsigned long MeshSearchNeighbours::NeighboursFromFacet (unsigned long ulFacetIdx, float fDistance, unsigned long ulMinPoints, std::vector &raclResultPoints) { bool bAddPoints = false; _fMaxDistanceP2 = fDistance * fDistance; _clCenter = _rclMesh.GetFacet(ulFacetIdx).GetGravityPoint(); unsigned long ulVisited = 1; std::vector aclTestedFacet; _aclResult.clear(); _aclOuter.clear(); // add start facet bool bFound = CheckDistToFacet(_rclFAry[ulFacetIdx]); _rclFAry[ulFacetIdx].SetFlag(MeshFacet::MARKED); aclTestedFacet.push_back(_rclFAry.begin() + ulFacetIdx); if ((bFound == false) && (_aclResult.size() < ulMinPoints)) { bAddPoints = true; bFound = ExpandRadius(ulMinPoints); } int nCtExpandRadius = 0; // search neighbours, add not marked facets, test distance, add outer points MeshFacetArray::_TConstIterator f_beg = _rclFAry.begin(); while ((bFound == true) && (nCtExpandRadius < 10)) { bFound = false; std::set aclTmp; aclTmp.swap(_aclOuter); for (std::set::iterator pI = aclTmp.begin(); pI != aclTmp.end(); ++pI) { const std::set &rclISet = _clPt2Fa[*pI]; // search all facets hanging on this point for (std::set::const_iterator pJ = rclISet.begin(); pJ != rclISet.end(); ++pJ) { const MeshFacet &rclF = f_beg[*pJ]; if (rclF.IsFlag(MeshFacet::MARKED) == false) { bool bLF = CheckDistToFacet(rclF); bFound = bFound || bLF; rclF.SetFlag(MeshFacet::MARKED); aclTestedFacet.push_back(f_beg+*pJ); } } ulVisited += rclISet.size(); } // too few points inside radius found -> expand radius if ((bFound == false) && (_aclResult.size() < ulMinPoints)) { nCtExpandRadius++; bAddPoints = true; bFound = ExpandRadius(ulMinPoints); } else nCtExpandRadius = 0; } // reset marked facets, points for (std::vector::iterator pF = aclTestedFacet.begin(); pF != aclTestedFacet.end(); ++pF) (*pF)->ResetFlag(MeshFacet::MARKED); for (std::set::iterator pR = _aclResult.begin(); pR != _aclResult.end(); ++pR) _rclPAry[*pR].ResetFlag(MeshPoint::MARKED); // copy points in result container raclResultPoints.resize(_aclResult.size()); int i = 0; for (std::set::iterator pI = _aclResult.begin(); pI != _aclResult.end(); ++pI, i++) raclResultPoints[i] = _rclPAry[*pI]; if (bAddPoints == true) { // sort points, remove points lying furthest from center std::sort(raclResultPoints.begin(), raclResultPoints.end(), CDistRad(_clCenter)); raclResultPoints.erase(raclResultPoints.begin() + ulMinPoints, raclResultPoints.end()); } return ulVisited; } void MeshSearchNeighbours::SampleAllFacets (void) { if (_aclSampledFacets.size() == _rclMesh.CountFacets()) return; // already sampled, do nothing _aclSampledFacets.resize(_rclMesh.CountFacets()); MeshFacetIterator clFIter(_rclMesh); int i = 0; for (clFIter.Init(); clFIter.More(); clFIter.Next(), i++) { std::vector clPoints; clFIter->SubSample(_fSampleDistance, clPoints); _aclSampledFacets[i].resize(clPoints.size()); std::copy(clPoints.begin(), clPoints.end(), _aclSampledFacets[i].begin()); } } unsigned long MeshSearchNeighbours::NeighboursFromSampledFacets (unsigned long ulFacetIdx, float fDistance, std::vector &raclResultPoints) { SampleAllFacets(); _fMaxDistanceP2 = fDistance * fDistance; _clCenter = _rclMesh.GetFacet(ulFacetIdx).GetGravityPoint(); _akSphere.Center = Wm4::Vector3(_clCenter.x, _clCenter.y, _clCenter.z); _akSphere.Radius = fDistance; unsigned long ulVisited = 1; std::vector aclTestedFacet; _aclResult.clear(); _aclOuter.clear(); _aclPointsResult.clear(); // add start facet bool bFound = AccumulateNeighbours(_rclFAry[ulFacetIdx], ulFacetIdx); _rclFAry[ulFacetIdx].SetFlag(MeshFacet::MARKED); // search neighbours, add not marked facets, test distance, add outer points MeshFacetArray::_TConstIterator f_beg = _rclFAry.begin(); while (bFound == true) { bFound = false; std::set aclTmp; aclTmp.swap(_aclOuter); for (std::set::iterator pI = aclTmp.begin(); pI != aclTmp.end(); ++pI) { const std::set &rclISet = _clPt2Fa[*pI]; // search all facets hanging on this point for (std::set::const_iterator pJ = rclISet.begin(); pJ != rclISet.end(); ++pJ) { const MeshFacet &rclF = f_beg[*pJ]; if (rclF.IsFlag(MeshFacet::MARKED) == false) { bool bLF = AccumulateNeighbours(rclF, *pJ); bFound = bFound || bLF; rclF.SetFlag(MeshFacet::MARKED); aclTestedFacet.push_back(f_beg+*pJ); } } ulVisited += rclISet.size(); } } // reset marked facets for (std::vector::iterator pF = aclTestedFacet.begin(); pF != aclTestedFacet.end(); ++pF) (*pF)->ResetFlag(MeshFacet::MARKED); // copy points in result container raclResultPoints.resize(_aclPointsResult.size()); std::copy(_aclPointsResult.begin(), _aclPointsResult.end(), raclResultPoints.begin()); // facet points for (std::set::iterator pI = _aclResult.begin(); pI != _aclResult.end(); ++pI) { if (InnerPoint(_rclPAry[*pI]) == true) raclResultPoints.push_back(_rclPAry[*pI]); } return ulVisited; } bool MeshSearchNeighbours::AccumulateNeighbours (const MeshFacet &rclF, unsigned long ulFIdx) { int k = 0; for (int i = 0; i < 3; i++) { unsigned long ulPIdx = rclF._aulPoints[i]; _aclOuter.insert(ulPIdx); _aclResult.insert(ulPIdx); if (Base::DistanceP2(_clCenter, _rclPAry[ulPIdx]) < _fMaxDistanceP2) k++; } bool bFound = false; if (k == 3) { // add all sample points _aclPointsResult.insert(_aclPointsResult.end(), _aclSampledFacets[ulFIdx].begin(), _aclSampledFacets[ulFIdx].end()); bFound = true; } else { // add points inner radius bFound = TriangleCutsSphere(rclF); if (bFound == true) { std::vector &rclT = _aclSampledFacets[ulFIdx]; std::vector clTmp; clTmp.reserve(rclT.size()); for (std::vector::iterator pI = rclT.begin(); pI != rclT.end(); ++pI) { if (InnerPoint(*pI) == true) clTmp.push_back(*pI); } _aclPointsResult.insert(_aclPointsResult.end(), clTmp.begin(), clTmp.end()); } } return bFound; } bool MeshSearchNeighbours::ExpandRadius (unsigned long ulMinPoints) { // add facets from current level _aclResult.insert(_aclOuter.begin(), _aclOuter.end()); for (std::set::iterator pI = _aclOuter.begin(); pI != _aclOuter.end(); ++pI) _rclPAry[*pI].SetFlag(MeshPoint::MARKED); if (_aclResult.size() < ulMinPoints) { _fMaxDistanceP2 *= float(ulMinPoints) / float(_aclResult.size()); return true; } else return false; } unsigned long MeshSearchNeighbours::NeighboursFacetFromFacet (unsigned long ulFacetIdx, float fDistance, std::vector &raclResultPoints, std::vector &raclResultFacets) { std::set aulFacetSet; _fMaxDistanceP2 = fDistance * fDistance; _clCenter = _rclMesh.GetFacet(ulFacetIdx).GetGravityPoint(); unsigned long ulVisited = 1; std::vector aclTestedFacet; _aclResult.clear(); _aclOuter.clear(); // add start facet bool bFound = CheckDistToFacet(_rclFAry[ulFacetIdx]); _rclFAry[ulFacetIdx].SetFlag(MeshFacet::MARKED); aclTestedFacet.push_back(_rclFAry.begin() + ulFacetIdx); aulFacetSet.insert(ulFacetIdx); // search neighbours, add not marked facets, test distance, add outer points MeshFacetArray::_TConstIterator f_beg = _rclFAry.begin(); while (bFound == true) { bFound = false; std::set aclTmp; aclTmp.swap(_aclOuter); for (std::set::iterator pI = aclTmp.begin(); pI != aclTmp.end(); ++pI) { const std::set &rclISet = _clPt2Fa[*pI]; // search all facets hanging on this point for (std::set::const_iterator pJ = rclISet.begin(); pJ != rclISet.end(); ++pJ) { const MeshFacet &rclF = f_beg[*pJ]; for (int i = 0; i < 3; i++) { if (Base::DistanceP2(_clCenter, _rclPAry[rclF._aulPoints[i]]) < _fMaxDistanceP2) { aulFacetSet.insert(*pJ); break; } } if (rclF.IsFlag(MeshFacet::MARKED) == false) { bool bLF = CheckDistToFacet(rclF); bFound = bFound || bLF; rclF.SetFlag(MeshFacet::MARKED); aclTestedFacet.push_back(f_beg+*pJ); } } ulVisited += rclISet.size(); } } // reset marked facets, points for (std::vector::iterator pF = aclTestedFacet.begin(); pF != aclTestedFacet.end(); ++pF) (*pF)->ResetFlag(MeshFacet::MARKED); for (std::set::iterator pR = _aclResult.begin(); pR != _aclResult.end(); ++pR) _rclPAry[*pR].ResetFlag(MeshPoint::MARKED); // copy points in result container raclResultPoints.resize(_aclResult.size()); int i = 0; for (std::set::iterator pI = _aclResult.begin(); pI != _aclResult.end(); ++pI, i++) raclResultPoints[i] = _rclPAry[*pI]; // copy facets in result container raclResultFacets.insert(raclResultFacets.begin(), aulFacetSet.begin(), aulFacetSet.end()); return ulVisited; }