diff --git a/src/Mod/Mesh/App/Core/Degeneration.cpp b/src/Mod/Mesh/App/Core/Degeneration.cpp index 699d186955..297b5f41b5 100644 --- a/src/Mod/Mesh/App/Core/Degeneration.cpp +++ b/src/Mod/Mesh/App/Core/Degeneration.cpp @@ -524,13 +524,16 @@ bool MeshRemoveNeedles::Fixup() std::vector, std::greater > todo; for (std::size_t index = 0; index < facetCount; index++) { + const MeshFacet& facet = rclFAry[index]; + MeshGeomFacet tria(_rclMesh.GetFacet(facet)); + float perimeter = tria.Perimeter(); + float fMinLen = perimeter * fMinEdgeLength; for (int i=0; i<3; i++) { - const MeshFacet& facet = rclFAry[index]; const Base::Vector3f& p1 = rclPAry[facet._aulPoints[i]]; const Base::Vector3f& p2 = rclPAry[facet._aulPoints[(i+1)%3]]; float distance = Base::Distance(p1, p2); - if (distance < fMinEdgeLength) { + if (distance < fMinLen) { unsigned long facetIndex = static_cast(index); todo.push(std::make_pair(distance, std::make_pair(facetIndex, i))); } @@ -548,10 +551,13 @@ bool MeshRemoveNeedles::Fixup() // the facet points may have changed, so check the current distance again const MeshFacet& facet = rclFAry[faceedge.first]; + MeshGeomFacet tria(_rclMesh.GetFacet(facet)); + float perimeter = tria.Perimeter(); + float fMinLen = perimeter * fMinEdgeLength; const Base::Vector3f& p1 = rclPAry[facet._aulPoints[faceedge.second]]; const Base::Vector3f& p2 = rclPAry[facet._aulPoints[(faceedge.second+1)%3]]; float distance = Base::Distance(p1, p2); - if (distance >= fMinEdgeLength) + if (distance >= fMinLen) continue; // collect the collapse-edge information diff --git a/src/Mod/Mesh/App/Core/Degeneration.h b/src/Mod/Mesh/App/Core/Degeneration.h index 442ab16344..17fdebf24d 100644 --- a/src/Mod/Mesh/App/Core/Degeneration.h +++ b/src/Mod/Mesh/App/Core/Degeneration.h @@ -340,11 +340,13 @@ private: class MeshExport MeshRemoveNeedles : public MeshValidation { public: - /** - * Construction. - */ - MeshRemoveNeedles (MeshKernel &rclM, float fMinEdgeLen = MeshDefinitions::_fMinPointDistance) - : MeshValidation(rclM), fMinEdgeLength(fMinEdgeLen) { } + /** + * Construction. The \arg fMinEdgeLen must be in the range of 0.0 and 0.25. + * It defines the amount of perimeter of a triangle for which the shortest + * edge is considered for removal. + */ + MeshRemoveNeedles (MeshKernel &rclM, float fMinEdgeLen = 0.05f) + : MeshValidation(rclM), fMinEdgeLength(std::min(fMinEdgeLen, 0.25f)) {} /** * Destruction. */ diff --git a/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp b/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp index 8b36f3a064..6ad518dd84 100644 --- a/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp +++ b/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp @@ -973,6 +973,14 @@ bool MeshTopoAlgorithm::IsCollapseEdgeLegal(const EdgeCollapse& ec) const return false; } + // If the data structure is valid and the algorithm works as expected + // it should never happen to reject the edge-collapse here! + 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; @@ -988,12 +996,33 @@ bool MeshTopoAlgorithm::CollapseEdge(const EdgeCollapse& ec) for (it = ec._removeFacets.begin(); it != ec._removeFacets.end(); ++it) { MeshFacet& f = _rclMesh._aclFacetArray[*it]; f.SetInvalid(); + + // adjust the neighbourhood + std::vector neighbours; + for (int i=0; i<3; i++) { + // get the neighbours of the facet that won't be invalidated + if (f._aulNeighbours[i] != ULONG_MAX) { + if (std::find(ec._removeFacets.begin(), ec._removeFacets.end(), + f._aulNeighbours[i]) == ec._removeFacets.end()) { + neighbours.push_back(f._aulNeighbours[i]); + } + } + } + + 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, ULONG_MAX); + } } for (it = ec._changeFacets.begin(); it != ec._changeFacets.end(); ++it) { MeshFacet& f = _rclMesh._aclFacetArray[*it]; - - // The neighbourhood might be broken from now on!!! f.Transpose(ec._fromPoint, ec._toPoint); }