diff --git a/src/Mod/Mesh/App/Core/SetOperations.cpp b/src/Mod/Mesh/App/Core/SetOperations.cpp index 244b424228..463b6fb620 100644 --- a/src/Mod/Mesh/App/Core/SetOperations.cpp +++ b/src/Mod/Mesh/App/Core/SetOperations.cpp @@ -618,3 +618,232 @@ bool SetOperations::CollectFacetVisitor::AllowVisit (const MeshFacet& rclFacet, return true; } + +// ---------------------------------------------------------------------------- + +bool MeshIntersection::hasIntersection() const +{ + Base::BoundBox3f bbox1 = kernel1.GetBoundBox(); + Base::BoundBox3f bbox2 = kernel2.GetBoundBox(); + if (!(bbox1 && bbox2)) + return false; + + if (testIntersection(kernel1, kernel2)) + return true; + + return false; +} + +void MeshIntersection::getIntersection(std::list& intsct) const +{ + const MeshKernel& k1 = kernel1; + const MeshKernel& k2 = kernel2; + + // Contains bounding boxes for every facet of 'k1' + std::vector boxes1; + MeshFacetIterator cMFI1(k1); + for (cMFI1.Begin(); cMFI1.More(); cMFI1.Next()) { + boxes1.push_back((*cMFI1).GetBoundBox()); + } + + // Contains bounding boxes for every facet of 'k2' + std::vector boxes2; + MeshFacetIterator cMFI2(k2); + for (cMFI2.Begin(); cMFI2.More(); cMFI2.Next()) { + boxes2.push_back((*cMFI2).GetBoundBox()); + } + + // Splits the mesh using grid for speeding up the calculation + MeshFacetGrid cMeshFacetGrid(k1); + + const MeshFacetArray& rFaces2 = k2.GetFacets(); + Base::SequencerLauncher seq("Checking for intersections...", rFaces2.size()); + int index = 0; + MeshGeomFacet facet1, facet2; + Base::Vector3f pt1, pt2; + + // Iterate over the facets of the 2nd mesh and find the grid elements of the 1st mesh + for (MeshFacetArray::_TConstIterator it = rFaces2.begin(); it != rFaces2.end(); ++it, index++) { + seq.next(); + std::vector elements; + cMeshFacetGrid.Inside(boxes2[index], elements, true); + + cMFI2.Set(index); + facet2 = *cMFI2; + + for (std::vector::iterator jt = elements.begin(); jt != elements.end(); ++jt) { + if (boxes2[index] && boxes1[*jt]) { + cMFI1.Set(*jt); + facet1 = *cMFI1; + int ret = facet1.IntersectWithFacet(facet2, pt1, pt2); + if (ret == 2) { + Tuple d; + d.p1 = pt1; + d.p2 = pt2; + d.f1 = *jt; + d.f2 = index; + intsct.push_back(d); + } + } + } + } +} + +bool MeshIntersection::testIntersection(const MeshKernel& k1, + const MeshKernel& k2) +{ + // Contains bounding boxes for every facet of 'k1' + std::vector boxes1; + MeshFacetIterator cMFI1(k1); + for (cMFI1.Begin(); cMFI1.More(); cMFI1.Next()) { + boxes1.push_back((*cMFI1).GetBoundBox()); + } + + // Contains bounding boxes for every facet of 'k2' + std::vector boxes2; + MeshFacetIterator cMFI2(k2); + for (cMFI2.Begin(); cMFI2.More(); cMFI2.Next()) { + boxes2.push_back((*cMFI2).GetBoundBox()); + } + + // Splits the mesh using grid for speeding up the calculation + MeshFacetGrid cMeshFacetGrid(k1); + + const MeshFacetArray& rFaces2 = k2.GetFacets(); + Base::SequencerLauncher seq("Checking for intersections...", rFaces2.size()); + int index = 0; + MeshGeomFacet facet1, facet2; + Base::Vector3f pt1, pt2; + + // Iterate over the facets of the 2nd mesh and find the grid elements of the 1st mesh + for (MeshFacetArray::_TConstIterator it = rFaces2.begin(); it != rFaces2.end(); ++it, index++) { + seq.next(); + std::vector elements; + cMeshFacetGrid.Inside(boxes2[index], elements, true); + + cMFI2.Set(index); + facet2 = *cMFI2; + + for (std::vector::iterator jt = elements.begin(); jt != elements.end(); ++jt) { + if (boxes2[index] && boxes1[*jt]) { + cMFI1.Set(*jt); + facet1 = *cMFI1; + int ret = facet1.IntersectWithFacet(facet2, pt1, pt2); + if (ret == 2) { + // abort after the first detected self-intersection + return true; + } + } + } + } + + return false; +} + +void MeshIntersection::connectLines(bool onlyclosed, const std::list& rdata, + std::list< std::list >& lines) +{ + float fMinEps = minDistance * minDistance; + + std::list data = rdata; + while (!data.empty()) { + std::list::iterator pF; + std::list newPoly; + + // add first line and delete from the list + Triple front, back; + front.f1 = data.begin()->f1; + front.f2 = data.begin()->f2; + front.p = data.begin()->p1; // current start point of the polyline + back.f1 = data.begin()->f1; + back.f2 = data.begin()->f2; + back.p = data.begin()->p2; // current end point of the polyline + newPoly.push_back(front); + newPoly.push_back(back); + data.erase(data.begin()); + + // search for the next line on the begin/end of the polyline and add it + std::list::iterator pFront, pEnd; + bool bFoundLine; + do { + float fFrontMin = fMinEps, fEndMin = fMinEps; + bool bFrontFirst=false, bEndFirst=false; + + pFront = data.end(); + pEnd = data.end(); + bFoundLine = false; + + for (pF = data.begin(); pF != data.end(); ++pF) { + if (Base::DistanceP2(front.p, pF->p1) < fFrontMin) { + fFrontMin = Base::DistanceP2(front.p, pF->p1); + pFront = pF; + bFrontFirst = true; + } + else if (Base::DistanceP2(back.p, pF->p1) < fEndMin) { + fEndMin = Base::DistanceP2(back.p, pF->p1); + pEnd = pF; + bEndFirst = true; + } + else if (Base::DistanceP2(front.p, pF->p2) < fFrontMin) { + fFrontMin = Base::DistanceP2(front.p, pF->p2); + pFront = pF; + bFrontFirst = false; + } + else if (Base::DistanceP2(back.p, pF->p2) < fEndMin) { + fEndMin = Base::DistanceP2(back.p, pF->p2); + pEnd = pF; + bEndFirst = false; + } + + if (fFrontMin == 0.0f || fEndMin == 0.0f) { + break; + } + } + + if (pFront != data.end()) { + bFoundLine = true; + if (bFrontFirst) { + front.f1 = pFront->f1; + front.f2 = pFront->f2; + front.p = pFront->p2; + newPoly.push_front(front); + } + else { + front.f1 = pFront->f1; + front.f2 = pFront->f2; + front.p = pFront->p1; + newPoly.push_front(front); + } + + data.erase(pFront); + } + + if (pEnd != data.end()) { + bFoundLine = true; + if (bEndFirst) { + back.f1 = pEnd->f1; + back.f2 = pEnd->f2; + back.p = pEnd->p2; + newPoly.push_back(back); + } + else { + back.f1 = pEnd->f1; + back.f2 = pEnd->f2; + back.p = pEnd->p1; + newPoly.push_back(back); + } + + data.erase(pEnd); + } + } + while (bFoundLine); + + if (onlyclosed) { + if (newPoly.size() > 2 && Base::DistanceP2(newPoly.front().p, newPoly.back().p) < fMinEps) + lines.push_back(newPoly); + } + else { + lines.push_back(newPoly); + } + } +} diff --git a/src/Mod/Mesh/App/Core/SetOperations.h b/src/Mod/Mesh/App/Core/SetOperations.h index 6ec708f443..d83cc4f362 100644 --- a/src/Mod/Mesh/App/Core/SetOperations.h +++ b/src/Mod/Mesh/App/Core/SetOperations.h @@ -184,6 +184,54 @@ private: }; +/*! + Determine the intersections between two meshes. +*/ +class MeshExport MeshIntersection +{ +public: + struct Tuple { + Base::Vector3f p1, p2; + FacetIndex f1, f2; + }; + struct Triple { + Base::Vector3f p; + FacetIndex f1, f2; + }; + struct Pair { + Base::Vector3f p; + FacetIndex f; + }; + + MeshIntersection(const MeshKernel& m1, + const MeshKernel& m2, + float dist) + : kernel1(m1) + , kernel2(m2) + , minDistance(dist) + { + } + ~MeshIntersection() + { + } + + bool hasIntersection() const; + void getIntersection(std::list&) const; + /*! + From an unsorted list of intersection points make a list of sorted intersection points. If parameter \a onlyclosed + is set to true then only closed intersection curves are taken and all other curves are filtered out. + */ + void connectLines(bool onlyclosed, const std::list&, std::list< std::list >&); + +private: + static bool testIntersection(const MeshKernel& k1, const MeshKernel& k2); + +private: + const MeshKernel& kernel1; + const MeshKernel& kernel2; + float minDistance; +}; + } // namespace MeshCore diff --git a/src/Mod/Mesh/App/Mesh.cpp b/src/Mod/Mesh/App/Mesh.cpp index 5c45b0e641..1ba161800f 100644 --- a/src/Mod/Mesh/App/Mesh.cpp +++ b/src/Mod/Mesh/App/Mesh.cpp @@ -1176,6 +1176,44 @@ MeshObject* MeshObject::outer(const MeshObject& mesh) const return new MeshObject(result); } +std::vector< std::vector > +MeshObject::section(const MeshObject& mesh, bool connectLines, float fMinDist) const +{ + MeshCore::MeshKernel kernel1(this->_kernel); + kernel1.Transform(this->_Mtrx); + MeshCore::MeshKernel kernel2(mesh._kernel); + kernel2.Transform(mesh._Mtrx); + std::vector< std::vector > lines; + + MeshCore::MeshIntersection sec(kernel1, kernel2, fMinDist); + std::list tuple; + sec.getIntersection(tuple); + + if (!connectLines) { + for (const auto& it : tuple) { + std::vector curve; + curve.push_back(it.p1); + curve.push_back(it.p2); + lines.push_back(curve); + } + } + else { + std::list< std::list > triple; + sec.connectLines(false, tuple, triple); + + for (const auto& it : triple) { + std::vector curve; + curve.reserve(it.size()); + + for (const auto& jt : it) + curve.push_back(jt.p); + lines.push_back(curve); + } + } + + return lines; +} + void MeshObject::refine() { unsigned long cnt = _kernel.CountFacets(); diff --git a/src/Mod/Mesh/App/Mesh.h b/src/Mod/Mesh/App/Mesh.h index c8b73515d5..4ca1df4565 100644 --- a/src/Mod/Mesh/App/Mesh.h +++ b/src/Mod/Mesh/App/Mesh.h @@ -252,6 +252,7 @@ public: MeshObject* subtract(const MeshObject&) const; MeshObject* inner(const MeshObject&) const; MeshObject* outer(const MeshObject&) const; + std::vector< std::vector > section(const MeshObject&, bool connectLines, float fMinDist) const; //@} /** @name Topological operations */ diff --git a/src/Mod/Mesh/App/MeshPy.xml b/src/Mod/Mesh/App/MeshPy.xml index fdaad6cf92..4469c29af1 100644 --- a/src/Mod/Mesh/App/MeshPy.xml +++ b/src/Mod/Mesh/App/MeshPy.xml @@ -91,7 +91,14 @@ mesh.write(Stream=file,Format='STL',[Name='Object name',Material=colors])Get the part outside the intersection - + + + Get the section curves of this and the given mesh object. +lines = mesh.section(mesh2, [ConnectLines=True, MinDist=0.0001]) + + + + Coarse the mesh diff --git a/src/Mod/Mesh/App/MeshPyImp.cpp b/src/Mod/Mesh/App/MeshPyImp.cpp index 2df58c6e58..a736502c83 100644 --- a/src/Mod/Mesh/App/MeshPyImp.cpp +++ b/src/Mod/Mesh/App/MeshPyImp.cpp @@ -514,6 +514,32 @@ PyObject* MeshPy::outer(PyObject *args) Py_Return; } +PyObject* MeshPy::section(PyObject *args, PyObject *kwds) +{ + PyObject *pcObj; + PyObject *connectLines = Py_True; + float fMinDist = 0.0001f; + + static char* keywords_section[] = {"Mesh", "ConnectLines", "MinDist", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!f",keywords_section, + &(MeshPy::Type), &pcObj, &PyBool_Type, &connectLines, &fMinDist)) + return nullptr; + + MeshPy* pcObject = static_cast(pcObj); + + std::vector< std::vector > curves = getMeshObjectPtr()->section(*pcObject->getMeshObjectPtr(), PyObject_IsTrue(connectLines), fMinDist); + Py::List outer; + for (const auto& it : curves) { + Py::List inner; + for (const auto& jt : it) { + inner.append(Py::Vector(jt)); + } + outer.append(inner); + } + + return Py::new_reference_to(outer); +} + PyObject* MeshPy::coarsen(PyObject *args) { if (!PyArg_ParseTuple(args, ""))