diff --git a/src/Mod/Mesh/App/Core/MeshIO.cpp b/src/Mod/Mesh/App/Core/MeshIO.cpp index 074fdc870..71198287c 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.cpp +++ b/src/Mod/Mesh/App/Core/MeshIO.cpp @@ -27,6 +27,7 @@ #include "MeshKernel.h" #include "MeshIO.h" +#include "Algorithm.h" #include "Builder.h" #include @@ -961,12 +962,16 @@ bool MeshInput::LoadPLY (std::istream &inp) } this->_rclMesh.Clear(); // remove all data before - // Don't use Assign() because Merge() checks which points are really needed. - // This method sets already the correct neighbourhood +#if 1 + MeshCleanup(meshPoints,meshFacets).RemoveInvalids(); + MeshPointFacetAdjacency meshAdj(meshPoints.size(),meshFacets); + meshAdj.SetFacetNeighbourhood(); + this->_rclMesh.Adopt(meshPoints,meshFacets); +#else MeshKernel tmp; tmp.Adopt(meshPoints,meshFacets); this->_rclMesh.Merge(tmp); - +#endif return true; } @@ -2448,3 +2453,164 @@ bool MeshOutput::SaveVRML (std::ostream &rstrOut) const return true; } + +// ---------------------------------------------------------------------------- + +MeshCleanup::MeshCleanup(MeshPointArray& p, MeshFacetArray& f) + : pointArray(p) + , facetArray(f) +{ +} + +MeshCleanup::~MeshCleanup() +{ +} + +void MeshCleanup::RemoveInvalids() +{ + // first mark all points as invalid + pointArray.SetFlag(MeshPoint::INVALID); + std::size_t numPoints = pointArray.size(); + + // Now go through the facets and invalidate facets with wrong indices + // If a facet is valid all its referenced points are validated again + // Points that are not referenced are still invalid and thus can be deleted + for (MeshFacetArray::_TIterator it = facetArray.begin(); it != facetArray.end(); ++it) { + for (int i=0; i<3; i++) { + // vertex index out of range + if (it->_aulPoints[i] >= numPoints) { + it->SetInvalid(); + break; + } + } + + // validate referenced points + if (it->IsValid()) { + pointArray[it->_aulPoints[0]].ResetInvalid(); + pointArray[it->_aulPoints[1]].ResetInvalid(); + pointArray[it->_aulPoints[2]].ResetInvalid(); + } + } + + // Remove the invalid items + RemoveInvalidFacets(); + RemoveInvalidPoints(); +} + +void MeshCleanup::RemoveInvalidFacets() +{ + std::size_t countInvalidFacets = std::count_if(facetArray.begin(), facetArray.end(), + std::bind2nd(MeshIsFlag(), MeshFacet::INVALID)); + if (countInvalidFacets > 0) { + MeshFacetArray copy_facets(facetArray.size() - countInvalidFacets); + // copy all valid facets to the new array + std::remove_copy_if(facetArray.begin(), facetArray.end(), copy_facets.begin(), + std::bind2nd(MeshIsFlag(), MeshFacet::INVALID)); + facetArray.swap(copy_facets); + } +} + +void MeshCleanup::RemoveInvalidPoints() +{ + std::size_t countInvalidPoints = std::count_if(pointArray.begin(), pointArray.end(), + std::bind2nd(MeshIsFlag(), MeshPoint::INVALID)); + if (countInvalidPoints > 0) { + // generate array of decrements + std::vector decrements; + decrements.resize(pointArray.size()); + unsigned long decr = 0; + + MeshPointArray::_TIterator p_end = pointArray.end(); + std::vector::iterator decr_it = decrements.begin(); + for (MeshPointArray::_TIterator p_it = pointArray.begin(); p_it != p_end; ++p_it, ++decr_it) { + *decr_it = decr; + if (!p_it->IsValid()) + decr++; + } + + // correct point indices of the facets + MeshFacetArray::_TIterator f_end = facetArray.end(); + for (MeshFacetArray::_TIterator f_it = facetArray.begin(); f_it != f_end; ++f_it) { + f_it->_aulPoints[0] -= decrements[f_it->_aulPoints[0]]; + f_it->_aulPoints[1] -= decrements[f_it->_aulPoints[1]]; + f_it->_aulPoints[2] -= decrements[f_it->_aulPoints[2]]; + } + + // delete point, number of valid points + std::size_t validPoints = pointArray.size() - countInvalidPoints; + MeshPointArray copy_points(validPoints); + // copy all valid facets to the new array + std::remove_copy_if(pointArray.begin(), pointArray.end(), copy_points.begin(), + std::bind2nd(MeshIsFlag(), MeshPoint::INVALID)); + pointArray.swap(copy_points); + } +} + +// ---------------------------------------------------------------------------- + +MeshPointFacetAdjacency::MeshPointFacetAdjacency(std::size_t p, MeshFacetArray& f) + : numPoints(p) + , facets(f) +{ + Build(); +} + +MeshPointFacetAdjacency::~MeshPointFacetAdjacency() +{ + std::size_t numPoints = pointFacetAdjacency.size(); + for (std::size_t i = 0; i < numPoints; i++) { + pointFacetAdjacency[i].swap(std::vector()); + } + pointFacetAdjacency.clear(); +} + +void MeshPointFacetAdjacency::Build() +{ + std::vector numFacetAdjacency(numPoints); + for (MeshFacetArray::iterator it = facets.begin(); it != facets.end(); ++it) { + numFacetAdjacency[it->_aulPoints[0]]++; + numFacetAdjacency[it->_aulPoints[1]]++; + numFacetAdjacency[it->_aulPoints[2]]++; + } + + pointFacetAdjacency.resize(numPoints); + for (std::size_t i = 0; i < numPoints; i++) + pointFacetAdjacency[i].reserve(numFacetAdjacency[i]); + + std::size_t numFacets = facets.size(); + for (int i = 0; i < numFacets; i++) { + for (int j = 0; j < 3; j++) { + pointFacetAdjacency[facets[i]._aulPoints[j]].push_back(i); + } + } +} + +void MeshPointFacetAdjacency::SetFacetNeighbourhood() +{ + std::size_t numFacets = facets.size(); + std::size_t index = 0; + for (std::size_t index = 0; index < numFacets; index++) { + MeshFacet& facet1 = facets[index]; + for (int i = 0; i < 3; i++) { + std::size_t n1 = facet1._aulPoints[i]; + std::size_t n2 = facet1._aulPoints[(i+1)%3]; + + bool success = false; + const std::vector& refFacets = pointFacetAdjacency[n1]; + for (std::vector::const_iterator it = refFacets.begin(); it != refFacets.end(); ++it) { + if (*it != index) { + MeshFacet& facet2 = facets[*it]; + if (facet2.HasPoint(n2)) { + facet1._aulNeighbours[i] = *it; + success = true; + break; + } + } + } + + if (!success) { + facet1._aulNeighbours[i] = ULONG_MAX; + } + } + } +} diff --git a/src/Mod/Mesh/App/Core/MeshIO.h b/src/Mod/Mesh/App/Core/MeshIO.h index 1d225889d..04a9d2d37 100644 --- a/src/Mod/Mesh/App/Core/MeshIO.h +++ b/src/Mod/Mesh/App/Core/MeshIO.h @@ -176,6 +176,75 @@ protected: static std::string stl_header; }; +/*! + The MeshCleanup class is a helper class to remove points from the point array that are not + referenced by any facet. It also removes facet with point indices that are out of range. + */ +class MeshCleanup +{ +public: + /*! + \brief Construction. + \param p -- the point array + \param f -- the facet array + */ + MeshCleanup(MeshPointArray& p, MeshFacetArray& f); + ~MeshCleanup(); + + /*! + \brief Remove unreferenced and invalid facets. + */ + void RemoveInvalids(); + +private: + /*! + \brief Remove invalid facets. + */ + void RemoveInvalidFacets(); + /*! + \brief Remove invalid points. + */ + void RemoveInvalidPoints(); + +private: + MeshPointArray& pointArray; + MeshFacetArray& facetArray; +}; + +/*! + The MeshPointFacetAdjacency class is a helper class to get all facets per vertex + and set the neighbourhood of the facets. + At this point the MeshFacetArray only references the points but does not have set + the neighbourhood of two adjacent facets. + */ +class MeshPointFacetAdjacency +{ +public: + /*! + \brief Construction. + \param p -- the number of points + \param f -- the facet array + */ + MeshPointFacetAdjacency(std::size_t p, MeshFacetArray& f); + ~MeshPointFacetAdjacency(); + + /*! + \brief Set the neighbourhood of two adjacent facets. + */ + void SetFacetNeighbourhood(); + +private: + /*! + \brief Build up the adjacency information. + */ + void Build(); + +private: + std::size_t numPoints; + MeshFacetArray& facets; + std::vector< std::vector > pointFacetAdjacency; +}; + } // namespace MeshCore