diff --git a/src/Mod/Mesh/App/Core/Degeneration.cpp b/src/Mod/Mesh/App/Core/Degeneration.cpp index 96f8a6b74b..11f87b37ac 100644 --- a/src/Mod/Mesh/App/Core/Degeneration.cpp +++ b/src/Mod/Mesh/App/Core/Degeneration.cpp @@ -1163,3 +1163,59 @@ bool MeshFixCorruptedFacets::Fixup() return true; } +// ---------------------------------------------------------------------- + +bool MeshEvalPointOnEdge::Evaluate () +{ + MeshFacetGrid facetGrid(_rclMesh); + const MeshPointArray& points = _rclMesh.GetPoints(); + const MeshFacetArray& facets = _rclMesh.GetFacets(); + + auto IsPointOnEdge = [&points](PointIndex idx, const MeshFacet& facet) { + // point must not be a corner of the facet + if (!facet.HasPoint(idx)) { + for (int i = 0; i < 3; i++) { + MeshGeomEdge edge; + edge._aclPoints[0] = points[facet._aulPoints[i]]; + edge._aclPoints[1] = points[facet._aulPoints[(i+1)%3]]; + + if (edge.GetBoundBox().IsInBox(points[idx])) { + if (edge.IsPointOf(points[idx], 0.001f)) + return true; + } + } + } + return false; + }; + + PointIndex maxPoints = _rclMesh.CountPoints(); + for (PointIndex i = 0; i < maxPoints; i++) { + std::vector elements; + facetGrid.GetElements(points[i], elements); + + for (const auto& it : elements) { + const MeshFacet& face = facets[it]; + if (IsPointOnEdge(i, face)) { + pointsIndices.push_back(i); + } + } + } + return pointsIndices.empty(); +} + +std::vector MeshEvalPointOnEdge::GetIndices() const +{ + return pointsIndices; +} + +bool MeshFixPointOnEdge::Fixup () +{ + if (pointsIndices.empty()) { + MeshEvalPointOnEdge eval(_rclMesh); + eval.Evaluate(); + pointsIndices = eval.GetIndices(); + } + + _rclMesh.DeletePoints(pointsIndices); + return true; +} diff --git a/src/Mod/Mesh/App/Core/Degeneration.h b/src/Mod/Mesh/App/Core/Degeneration.h index fdd6dfc876..b544c294bc 100644 --- a/src/Mod/Mesh/App/Core/Degeneration.h +++ b/src/Mod/Mesh/App/Core/Degeneration.h @@ -741,6 +741,62 @@ public: bool Fixup (); }; +/** + * The MeshEvalPointOnEdge class searches for points that lie on or close to an edge of a triangle. + * @see MeshFixPointOnEdge + * @author Werner Mayer + */ +class MeshExport MeshEvalPointOnEdge : public MeshEvaluation +{ +public: + /** + * Construction. + */ + MeshEvalPointOnEdge (const MeshKernel &rclM) : MeshEvaluation( rclM ) { } + /** + * Destruction. + */ + ~MeshEvalPointOnEdge () { } + /** + * Searches for points that lie on edge of triangle. + */ + bool Evaluate (); + /** + * Returns the indices of all corrupt facets. + */ + std::vector GetIndices() const; + +private: + std::vector pointsIndices; +}; + +/** + * The MeshFixPointOnEdge class removes points that lie on or close to an edge of a triangle. + * @see MeshEvalPointOnEdge + * @author Werner Mayer + */ +class MeshExport MeshFixPointOnEdge : public MeshValidation +{ +public: + /** + * Construction. + */ + MeshFixPointOnEdge (MeshKernel &rclM) : MeshValidation( rclM ) { } + MeshFixPointOnEdge (MeshKernel &rclM, const std::vector& points) + : MeshValidation( rclM ), pointsIndices(points) { } + /** + * Destruction. + */ + ~MeshFixPointOnEdge () { } + /** + * Removes points that lie on edges of triangles. + */ + bool Fixup (); + +private: + std::vector pointsIndices; +}; + } // namespace MeshCore #endif // MESH_DEGENERATION_H diff --git a/src/Mod/Mesh/App/Core/Elements.cpp b/src/Mod/Mesh/App/Core/Elements.cpp index 3d36923482..488effb791 100644 --- a/src/Mod/Mesh/App/Core/Elements.cpp +++ b/src/Mod/Mesh/App/Core/Elements.cpp @@ -350,6 +350,26 @@ void MeshGeomEdge::ClosestPointsToLine(const Base::Vector3f &linePt, const Base: } } +bool MeshGeomEdge::IsPointOf (const Base::Vector3f &rclPoint, float fDistance) const +{ + float len2 = Base::DistanceP2(_aclPoints[0], _aclPoints[1]); + if (len2 == 0.0f) { + return _aclPoints[0].IsEqual(rclPoint, 0.0f); + } + + Base::Vector3f p2p1 = _aclPoints[1] - _aclPoints[0]; + Base::Vector3f pXp1 = rclPoint - _aclPoints[0]; + + float dot = pXp1 * p2p1; + float t = dot / len2; + if (t < 0.0f || t > 1.0f) + return false; + + // point on the edge + Base::Vector3f ptEdge = t * p2p1 + _aclPoints[0]; + return Base::Distance(ptEdge, rclPoint) <= fDistance; +} + // ----------------------------------------------------------------- MeshGeomFacet::MeshGeomFacet () diff --git a/src/Mod/Mesh/App/Core/Elements.h b/src/Mod/Mesh/App/Core/Elements.h index 22c48c4cba..b2c1f62372 100644 --- a/src/Mod/Mesh/App/Core/Elements.h +++ b/src/Mod/Mesh/App/Core/Elements.h @@ -184,6 +184,12 @@ public: */ void ClosestPointsToLine(const Base::Vector3f &linePt, const Base::Vector3f &lineDir, Base::Vector3f& rclPnt1, Base::Vector3f& rclPnt2) const; + /** + * Checks if the point is part of the facet. A point is regarded as part + * of a facet if the distance is lower \a fDistance and the projected point + * in the facet normal direction is inside the triangle. + */ + bool IsPointOf (const Base::Vector3f &rclPoint, float fDistance) const; public: Base::Vector3f _aclPoints[2]; /**< Corner points */ diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 1ba161800f..cf215e0722 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -1495,6 +1495,18 @@ void MeshObject::removeInvalidPoints() deletePoints(nan.GetIndices()); } +bool MeshObject::hasPointsOnEdge() const +{ + MeshCore::MeshEvalPointOnEdge nan(_kernel); + return !nan.Evaluate(); +} + +void MeshObject::removePointsOnEdge() +{ + MeshCore::MeshFixPointOnEdge nan(_kernel); + nan.Fixup(); +} + void MeshObject::mergeFacets() { unsigned long count = _kernel.CountFacets(); diff --git a/src/Mod/Mesh/App/Mesh.h b/src/Mod/Mesh/App/Mesh.h index 4ca1df4565..810c5dbde5 100644 --- a/src/Mod/Mesh/App/Mesh.h +++ b/src/Mod/Mesh/App/Mesh.h @@ -298,6 +298,8 @@ public: bool hasInvalidPoints() const; void removeInvalidPoints(); void mergeFacets(); + bool hasPointsOnEdge() const; + void removePointsOnEdge(); //@} /** @name Mesh segments */ diff --git a/src/Mod/Mesh/App/MeshPy.xml b/src/Mod/Mesh/App/MeshPy.xml index 4469c29af1..6ae9295dfb 100644 --- a/src/Mod/Mesh/App/MeshPy.xml +++ b/src/Mod/Mesh/App/MeshPy.xml @@ -291,6 +291,16 @@ for c in mesh.getSeparatecomponents(): Remove points with invalid coordinates (NaN) + + + Check if points lie on edges + + + + + Remove points that lie on edges + + Check if the mesh has invalid neighbourhood indices diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index a736502c83..b2e9fc3beb 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -1094,6 +1094,28 @@ PyObject* MeshPy::removeInvalidPoints(PyObject *args) Py_Return; } +PyObject* MeshPy::hasPointsOnEdge(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + bool ok = getMeshObjectPtr()->hasPointsOnEdge(); + return Py_BuildValue("O", (ok ? Py_True : Py_False)); +} + +PyObject* MeshPy::removePointsOnEdge(PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return nullptr; + try { + getMeshObjectPtr()->removePointsOnEdge(); + } + catch (const Base::Exception& e) { + PyErr_SetString(Base::BaseExceptionFreeCADError, e.what()); + return nullptr; + } + Py_Return; +} + PyObject* MeshPy::flipNormals(PyObject *args) { if (!PyArg_ParseTuple(args, ""))