diff --git a/src/Mod/Mesh/App/Core/Degeneration.cpp b/src/Mod/Mesh/App/Core/Degeneration.cpp index da3849f5a2..07fcdf0848 100644 --- a/src/Mod/Mesh/App/Core/Degeneration.cpp +++ b/src/Mod/Mesh/App/Core/Degeneration.cpp @@ -701,6 +701,34 @@ bool MeshFixDeformedFacets::Fixup() // ---------------------------------------------------------------------- +bool MeshFixMergeFacets::Fixup() +{ + MeshCore::MeshRefPointToPoints vv_it(_rclMesh); + MeshCore::MeshRefPointToFacets vf_it(_rclMesh); + unsigned long countPoints = _rclMesh.CountPoints(); + + std::vector newFacets; + newFacets.reserve(countPoints/20); // 5% should be sufficient + + MeshTopoAlgorithm topAlg(_rclMesh); + for (unsigned long i=0; i& adjPts = vv_it[i]; + vc._circumPoints.insert(vc._circumPoints.begin(), adjPts.begin(), adjPts.end()); + const std::set& adjFts = vf_it[i]; + vc._circumFacets.insert(vc._circumFacets.begin(), adjFts.begin(), adjFts.end()); + topAlg.CollapseVertex(vc); + } + } + + topAlg.Cleanup(); + return true; +} + +// ---------------------------------------------------------------------- + bool MeshEvalDentsOnSurface::Evaluate() { this->indices.clear(); diff --git a/src/Mod/Mesh/App/Core/Degeneration.h b/src/Mod/Mesh/App/Core/Degeneration.h index 1cbe696a4a..7adabd7659 100644 --- a/src/Mod/Mesh/App/Core/Degeneration.h +++ b/src/Mod/Mesh/App/Core/Degeneration.h @@ -398,6 +398,32 @@ private: float fEpsilon; }; +/** + * The MeshFixMergeFacets class removes vertexes which have three adjacent vertexes and is referenced by three facets. + * Usually all the three facets that reference this vertex are not well-formed. If the number of adjacent vertexes + * is equal to the number of adjacent facets the affected vertex never lies on the boundary and thus it's safe to delete + * and replace the three facets with a single facet. + * Effectively this algorithm does the opposite of \ref MeshTopoAlgorithm::InsertVertex + * @author Werner Mayer + */ +class MeshExport MeshFixMergeFacets : public MeshValidation +{ +public: + /** + * Construction. + */ + MeshFixMergeFacets (MeshKernel &rclM) + : MeshValidation(rclM) { } + /** + * Destruction. + */ + ~MeshFixMergeFacets () { } + /** + * Removes deformed facets. + */ + bool Fixup (); +}; + /** * If an adjacent point (A) of a point (P) can be projected onto a triangle shared * by (P) but not by (A) then we have a local dent. The topology is not affected. diff --git a/src/Mod/Mesh/App/Core/Elements.h b/src/Mod/Mesh/App/Core/Elements.h index f49eea9c10..7d2ec37a14 100644 --- a/src/Mod/Mesh/App/Core/Elements.h +++ b/src/Mod/Mesh/App/Core/Elements.h @@ -79,6 +79,13 @@ struct MeshExport EdgeCollapse std::vector _changeFacets; }; +struct MeshExport VertexCollapse +{ + unsigned long _point; + std::vector _circumPoints; + std::vector _circumFacets; +}; + /** * The MeshPoint class represents a point in the mesh data structure. The class inherits from * Vector3f and provides some additional information such as flag state and property value. diff --git a/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp b/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp index 4d75e8a8a1..23f7ea2fa9 100644 --- a/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp +++ b/src/Mod/Mesh/App/Core/TopoAlgorithm.cpp @@ -835,6 +835,72 @@ void MeshTopoAlgorithm::Cleanup() _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; // the point is marked invalid from a previous run + + MeshFacet& rFace1 = _rclMesh._aclFacetArray[vc._circumFacets[0]]; + MeshFacet& rFace2 = _rclMesh._aclFacetArray[vc._circumFacets[1]]; + MeshFacet& rFace3 = _rclMesh._aclFacetArray[vc._circumFacets[2]]; + + // get the point that is not shared by rFace1 + unsigned long ptIndex = ULONG_MAX; + std::vector::const_iterator it; + for (it = vc._circumPoints.begin(); it != vc._circumPoints.end(); ++it) { + if (!rFace1.HasPoint(*it)) { + ptIndex = *it; + break; + } + } + + if (ptIndex == ULONG_MAX) + return false; + + unsigned long neighbour1 = ULONG_MAX; + unsigned long neighbour2 = ULONG_MAX; + + const std::vector& faces = vc._circumFacets; + // get neighbours that are not part of the faces to be removed + for (int i=0; i<3; i++) { + if (std::find(faces.begin(), faces.end(), rFace2._aulNeighbours[i]) == faces.end()) { + neighbour1 = rFace2._aulNeighbours[i]; + } + if (std::find(faces.begin(), faces.end(), rFace3._aulNeighbours[i]) == faces.end()) { + neighbour2 = rFace3._aulNeighbours[i]; + } + } + + // adjust point and neighbour indices + rFace1.Transpose(vc._point, ptIndex); + rFace1.ReplaceNeighbour(vc._circumFacets[1], neighbour1); + rFace1.ReplaceNeighbour(vc._circumFacets[2], neighbour2); + + if (neighbour1 != ULONG_MAX) { + MeshFacet& rFace4 = _rclMesh._aclFacetArray[neighbour1]; + rFace4.ReplaceNeighbour(vc._circumFacets[1], vc._circumFacets[0]); + } + if (neighbour2 != ULONG_MAX) { + MeshFacet& rFace5 = _rclMesh._aclFacetArray[neighbour2]; + rFace5.ReplaceNeighbour(vc._circumFacets[2], vc._circumFacets[0]); + } + + // the two facets and the point can be marked for removal + rFace2.SetInvalid(); + rFace3.SetInvalid(); + _rclMesh._aclPointArray[vc._point].SetInvalid(); + + _needsCleanup = true; + + return true; +} + bool MeshTopoAlgorithm::CollapseEdge(unsigned long ulFacetPos, unsigned long ulNeighbour) { MeshFacet& rclF = _rclMesh._aclFacetArray[ulFacetPos]; diff --git a/src/Mod/Mesh/App/Core/TopoAlgorithm.h b/src/Mod/Mesh/App/Core/TopoAlgorithm.h index c6bc1712fc..251219a118 100644 --- a/src/Mod/Mesh/App/Core/TopoAlgorithm.h +++ b/src/Mod/Mesh/App/Core/TopoAlgorithm.h @@ -111,6 +111,11 @@ public: */ void SplitFacet(unsigned long ulFacetPos, const Base::Vector3f& rP1, const Base::Vector3f& rP2); + /** + * Collapse a vertex. At the moment only removing inner vertexes referenced + * by three facets is supposrted. + */ + bool CollapseVertex(const VertexCollapse& vc); /** * Collapses the common edge of two adjacent facets. This operation removes * one common point of the collapsed edge and the facets \a ulFacetPos and