From c60658f3f9038cec6e5736cf7e4425067f56d438 Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 14 May 2019 15:21:08 +0200 Subject: [PATCH] add method to project shape on mesh --- src/Mod/MeshPart/App/AppMeshPartPy.cpp | 71 ++++++++++---- src/Mod/MeshPart/App/CurveProjector.cpp | 119 ++++++++++++++++++------ src/Mod/MeshPart/App/CurveProjector.h | 15 ++- 3 files changed, 159 insertions(+), 46 deletions(-) diff --git a/src/Mod/MeshPart/App/AppMeshPartPy.cpp b/src/Mod/MeshPart/App/AppMeshPartPy.cpp index fa1f8ecc40..118949d074 100644 --- a/src/Mod/MeshPart/App/AppMeshPartPy.cpp +++ b/src/Mod/MeshPart/App/AppMeshPartPy.cpp @@ -63,7 +63,9 @@ public: ); add_varargs_method("projectShapeOnMesh",&Module::projectShapeOnMesh, "Projects a shape onto a mesh with a given maximum distance\n" - "projectShapeOnMesh(shape, mesh, float) -> polygon" + "projectShapeOnMesh(Shape, Mesh, float) -> polygon\n" + "or projects the shape in a given direction\n" + "projectShapeOnMesh(Shape, Mesh, Vector) -> list of polygons" ); add_varargs_method("wireFromSegment",&Module::wireFromSegment, "Create wire(s) from boundary of segment\n" @@ -205,26 +207,61 @@ private: { PyObject *s, *m; double maxDist; - if (!PyArg_ParseTuple(args.ptr(), "O!O!d", &Part::TopoShapePy::Type, &s, - &Mesh::MeshPy::Type, &m, - &maxDist)) - throw Py::Exception(); - TopoDS_Shape shape = static_cast(s)->getTopoShapePtr()->getShape(); - const Mesh::MeshObject* mesh = static_cast(m)->getMeshObjectPtr(); - MeshCore::MeshKernel kernel(mesh->getKernel()); - kernel.Transform(mesh->getTransform()); + if (PyArg_ParseTuple(args.ptr(), "O!O!d", &Part::TopoShapePy::Type, &s, + &Mesh::MeshPy::Type, &m, + &maxDist)) { + TopoDS_Shape shape = static_cast(s)->getTopoShapePtr()->getShape(); + const Mesh::MeshObject* mesh = static_cast(m)->getMeshObjectPtr(); + MeshCore::MeshKernel kernel(mesh->getKernel()); + kernel.Transform(mesh->getTransform()); - MeshProjection proj(kernel); - std::vector rSplitEdges; - proj.projectToMesh(shape, maxDist, rSplitEdges); + MeshProjection proj(kernel); + std::vector polylines; + proj.projectToMesh(shape, maxDist, polylines); - Py::List list; - for (auto it : rSplitEdges) { - Py::Vector v(it.cPt); - list.append(v); + Py::List list; + for (auto it : polylines) { + Py::List poly; + for (auto jt : it.points) { + Py::Vector v(jt); + poly.append(v); + } + list.append(poly); + } + + return list; } - return list; + PyErr_Clear(); + PyObject *v; + if (PyArg_ParseTuple(args.ptr(), "O!O!O!", &Part::TopoShapePy::Type, &s, + &Mesh::MeshPy::Type, &m, + &Base::VectorPy::Type, &v)) { + TopoDS_Shape shape = static_cast(s)->getTopoShapePtr()->getShape(); + const Mesh::MeshObject* mesh = static_cast(m)->getMeshObjectPtr(); + Base::Vector3d* vec = static_cast(v)->getVectorPtr(); + Base::Vector3f dir = Base::convertTo(*vec); + + MeshCore::MeshKernel kernel(mesh->getKernel()); + kernel.Transform(mesh->getTransform()); + + MeshProjection proj(kernel); + std::vector polylines; + proj.projectParallelToMesh(shape, dir, polylines); + Py::List list; + for (auto it : polylines) { + Py::List poly; + for (auto jt : it.points) { + Py::Vector v(jt); + poly.append(v); + } + list.append(poly); + } + + return list; + } + + throw Py::TypeError("Expected arguments are: Shape, Mesh, float or Vector"); } Py::Object wireFromSegment(const Py::Tuple& args) { diff --git a/src/Mod/MeshPart/App/CurveProjector.cpp b/src/Mod/MeshPart/App/CurveProjector.cpp index bafab2e655..b0c151a44f 100644 --- a/src/Mod/MeshPart/App/CurveProjector.cpp +++ b/src/Mod/MeshPart/App/CurveProjector.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -57,10 +58,12 @@ using namespace MeshPart; -using namespace MeshCore; - - - +using MeshCore::MeshKernel; +using MeshCore::MeshFacetIterator; +using MeshCore::MeshPointIterator; +using MeshCore::MeshAlgorithm; +using MeshCore::MeshFacetGrid; +using MeshCore::MeshFacet; CurveProjector::CurveProjector(const TopoDS_Shape &aShape, const MeshKernel &pMesh) : _Shape(aShape), _Mesh(pMesh) @@ -685,21 +688,39 @@ MeshProjection::~MeshProjection() { } +void MeshProjection::discretize(const TopoDS_Edge& aEdge, std::vector& polyline) const +{ + BRepAdaptor_Curve clCurve(aEdge); + + Standard_Real fFirst = clCurve.FirstParameter(); + Standard_Real fLast = clCurve.LastParameter(); + + GCPnts_UniformDeflection clDefl(clCurve, 0.01f, fFirst, fLast); + if (clDefl.IsDone() == Standard_True) { + Standard_Integer nNbPoints = clDefl.NbPoints(); + for (Standard_Integer i = 1; i <= nNbPoints; i++) { + gp_Pnt gpPt = clCurve.Value(clDefl.Parameter(i)); + polyline.push_back( Base::Vector3f( (float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z() ) ); + } + } +} + void MeshProjection::splitMeshByShape ( const TopoDS_Shape &aShape, float fMaxDist ) const { - std::vector cSplitEdges; - projectToMesh( aShape, fMaxDist, cSplitEdges ); + std::vector rPolyLines; + projectToMesh( aShape, fMaxDist, rPolyLines ); std::ofstream str("output.asc", std::ios::out | std::ios::binary); str.precision(4); str.setf(std::ios::fixed | std::ios::showpoint); - for (std::vector::const_iterator it = cSplitEdges.begin();it!=cSplitEdges.end();++it) { - str << it->cPt.x << " " << it->cPt.y << " " << it->cPt.z << std::endl; + for (std::vector::const_iterator it = rPolyLines.begin();it!=rPolyLines.end();++it) { + for (std::vector::const_iterator jt = it->points.begin();jt != it->points.end();++jt) + str << jt->x << " " << jt->y << " " << jt->z << std::endl; } str.close(); } -void MeshProjection::projectToMesh ( const TopoDS_Shape &aShape, float fMaxDist, std::vector& rSplitEdges ) const +void MeshProjection::projectToMesh (const TopoDS_Shape &aShape, float fMaxDist, std::vector& rPolyLines) const { // calculate the average edge length and create a grid MeshAlgorithm clAlg( _rcMesh ); @@ -707,7 +728,6 @@ void MeshProjection::projectToMesh ( const TopoDS_Shape &aShape, float fMaxDist, MeshFacetGrid cGrid( _rcMesh, 5.0f*fAvgLen ); TopExp_Explorer Ex; - TopoDS_Shape Edge; int iCnt=0; for (Ex.Init(aShape, TopAbs_EDGE); Ex.More(); Ex.Next()) @@ -717,7 +737,65 @@ void MeshProjection::projectToMesh ( const TopoDS_Shape &aShape, float fMaxDist, for (Ex.Init(aShape, TopAbs_EDGE); Ex.More(); Ex.Next()) { const TopoDS_Edge& aEdge = TopoDS::Edge(Ex.Current()); - projectEdgeToEdge( aEdge, fMaxDist, cGrid, rSplitEdges ); + std::vector rSplitEdges; + projectEdgeToEdge(aEdge, fMaxDist, cGrid, rSplitEdges); + PolyLine polyline; + polyline.points.reserve(rSplitEdges.size()); + for (auto it : rSplitEdges) + polyline.points.push_back(it.cPt); + rPolyLines.push_back(polyline); + seq.next(); + } +} + +void MeshProjection::projectParallelToMesh (const TopoDS_Shape &aShape, const Base::Vector3f& dir, std::vector& rPolyLines) const +{ + // calculate the average edge length and create a grid + MeshAlgorithm clAlg(_rcMesh); + float fAvgLen = clAlg.GetAverageEdgeLength(); + MeshFacetGrid cGrid(_rcMesh, 5.0f*fAvgLen); + TopExp_Explorer Ex; + + int iCnt=0; + for (Ex.Init(aShape, TopAbs_EDGE); Ex.More(); Ex.Next()) + iCnt++; + + Base::SequencerLauncher seq( "Project curve on mesh", iCnt ); + + for (Ex.Init(aShape, TopAbs_EDGE); Ex.More(); Ex.Next()) { + const TopoDS_Edge& aEdge = TopoDS::Edge(Ex.Current()); + std::vector points; + discretize(aEdge, points); + + typedef std::pair HitPoint; + std::vector hitPoints; + typedef std::pair HitPoints; + std::vector hitPointPairs; + for (auto it : points) { + Base::Vector3f result; + unsigned long index; + if (clAlg.NearestFacetOnRay(it, dir, cGrid, result, index)) { + hitPoints.push_back(std::make_pair(result, index)); + + if (hitPoints.size() > 1) { + HitPoint p1 = hitPoints[hitPoints.size()-2]; + HitPoint p2 = hitPoints[hitPoints.size()-1]; + hitPointPairs.push_back(std::make_pair(p1, p2)); + } + } + } + + MeshCore::MeshProjection meshProjection(_rcMesh); + PolyLine polyline; + for (auto it : hitPointPairs) { + points.clear(); + if (meshProjection.projectLineOnMesh(cGrid, it.first.first, it.first.second, + it.second.first, it.second.second, dir, points)) { + polyline.points.insert(polyline.points.end(), points.begin(), points.end()); + } + } + rPolyLines.push_back(polyline); + seq.next(); } } @@ -731,20 +809,7 @@ void MeshProjection::projectEdgeToEdge( const TopoDS_Edge &aEdge, float fMaxDist // search the facets in the local area of the curve std::vector acPolyLine; - - BRepAdaptor_Curve clCurve( aEdge ); - - Standard_Real fFirst = clCurve.FirstParameter(); - Standard_Real fLast = clCurve.LastParameter(); - - GCPnts_UniformDeflection clDefl(clCurve, 0.01f, fFirst, fLast); - if (clDefl.IsDone() == Standard_True) { - Standard_Integer nNbPoints = clDefl.NbPoints(); - for (Standard_Integer i = 1; i <= nNbPoints; i++) { - gp_Pnt gpPt = clCurve.Value(clDefl.Parameter(i)); - acPolyLine.push_back( Base::Vector3f( (float)gpPt.X(), (float)gpPt.Y(), (float)gpPt.Z() ) ); - } - } + discretize(aEdge, acPolyLine); MeshAlgorithm(_rcMesh).SearchFacetsFromPolyline( acPolyLine, fMaxDist, rGrid, auFInds); // remove duplicated elements @@ -764,7 +829,9 @@ void MeshProjection::projectEdgeToEdge( const TopoDS_Edge &aEdge, float fMaxDist // sort intersection points by parameter std::map rParamSplitEdges; -// Standard_Real fFirst, fLast; + BRepAdaptor_Curve clCurve(aEdge); + Standard_Real fFirst = clCurve.FirstParameter(); + Standard_Real fLast = clCurve.LastParameter(); Handle(Geom_Curve) hCurve = BRep_Tool::Curve( aEdge,fFirst,fLast ); // bounds of curve diff --git a/src/Mod/MeshPart/App/CurveProjector.h b/src/Mod/MeshPart/App/CurveProjector.h index d88edf4c94..fdc045f023 100644 --- a/src/Mod/MeshPart/App/CurveProjector.h +++ b/src/Mod/MeshPart/App/CurveProjector.h @@ -167,8 +167,12 @@ public: /// Helper class struct SplitEdge { - unsigned long uE0, uE1; /**< start and endpoint of an edge */ - Base::Vector3f cPt; /**< Point on edge (\a uE0, \a uE1) */ + unsigned long uE0, uE1; /**< start and endpoint of an edge */ + Base::Vector3f cPt; /**< Point on edge (\a uE0, \a uE1) */ + }; + struct PolyLine + { + std::vector points; }; /// Construction @@ -176,12 +180,17 @@ public: /// Destruction ~MeshProjection(); + void discretize(const TopoDS_Edge& aEdge, std::vector& polyline) const; /** * Searches all edges that intersect with the projected curve \a aShape. Therefore \a aShape must * contain shapes of type TopoDS_Edge, other shape types are ignored. A possible solution is * taken if the distance between the curve point and the projected point is <= \a fMaxDist. */ - void projectToMesh (const TopoDS_Shape &aShape, float fMaxDist, std::vector& rSplitEdges) const; + void projectToMesh (const TopoDS_Shape &aShape, float fMaxDist, std::vector& rPolyLines) const; + /** + * Project all edges of the shape onto the mesh using parallel projection. + */ + void projectParallelToMesh (const TopoDS_Shape &aShape, const Base::Vector3f& dir, std::vector& rPolyLines) const; /** * Cuts the mesh at the curve defined by \a aShape. This method call @ref projectToMesh() to get the * split the facet at the found points. @see projectToMesh() for more details.