From 143a5ffe838b0e69f4d044fd77fecdcf5c4e5cb9 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 8 Jun 2019 14:19:29 +0200 Subject: [PATCH] extend MeshPart.projectShapeOnMesh to allow list of points for projection, support keywords --- src/Mod/MeshPart/App/AppMeshPartPy.cpp | 84 ++++++++++++++++++++++--- src/Mod/MeshPart/App/CurveProjector.cpp | 45 +++++++++++++ src/Mod/MeshPart/App/CurveProjector.h | 4 ++ 3 files changed, 123 insertions(+), 10 deletions(-) diff --git a/src/Mod/MeshPart/App/AppMeshPartPy.cpp b/src/Mod/MeshPart/App/AppMeshPartPy.cpp index 118949d074..d481e58371 100644 --- a/src/Mod/MeshPart/App/AppMeshPartPy.cpp +++ b/src/Mod/MeshPart/App/AppMeshPartPy.cpp @@ -61,11 +61,16 @@ public: " upVector ((x, y, z) tuple):\n" " MaxSize (float):\n" ); - add_varargs_method("projectShapeOnMesh",&Module::projectShapeOnMesh, + add_keyword_method("projectShapeOnMesh",&Module::projectShapeOnMesh, "Projects a shape onto a mesh with a given maximum distance\n" "projectShapeOnMesh(Shape, Mesh, float) -> polygon\n" "or projects the shape in a given direction\n" - "projectShapeOnMesh(Shape, Mesh, Vector) -> list of polygons" + "\n" + "Multiple signatures are available:\n" + "\n" + "projectShapeOnMesh(Shape, Mesh, float) -> list of polygons\n" + "projectShapeOnMesh(Shape, Mesh, Vector) -> list of polygons\n" + "projectShapeOnMesh(list of polygons, Mesh, Vector) -> list of polygons\n" ); add_varargs_method("wireFromSegment",&Module::wireFromSegment, "Create wire(s) from boundary of segment\n" @@ -203,13 +208,16 @@ private: MeshPart::MeshAlgos::LoftOnCurve(M,aShape,poly,Base::Vector3f(x,y,z),size); return Py::asObject(new Mesh::MeshPy(new Mesh::MeshObject(M))); } - Py::Object projectShapeOnMesh(const Py::Tuple& args) + Py::Object projectShapeOnMesh(const Py::Tuple& args, const Py::Dict& kwds) { + static char* kwds_maxdist[] = {"Shape", "Mesh", "MaxDistance", NULL}; PyObject *s, *m; double maxDist; - if (PyArg_ParseTuple(args.ptr(), "O!O!d", &Part::TopoShapePy::Type, &s, - &Mesh::MeshPy::Type, &m, - &maxDist)) { + if (PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), + "O!O!d", kwds_maxdist, + &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()); @@ -232,11 +240,14 @@ private: return list; } + static char* kwds_dir[] = {"Shape", "Mesh", "Direction", NULL}; PyErr_Clear(); PyObject *v; - if (PyArg_ParseTuple(args.ptr(), "O!O!O!", &Part::TopoShapePy::Type, &s, - &Mesh::MeshPy::Type, &m, - &Base::VectorPy::Type, &v)) { + if (PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), + "O!O!O!", kwds_dir, + &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(); @@ -261,7 +272,60 @@ private: return list; } - throw Py::TypeError("Expected arguments are: Shape, Mesh, float or Vector"); + static char* kwds_poly[] = {"Polygons", "Mesh", "Direction", NULL}; + PyErr_Clear(); + PyObject *seq; + if (PyArg_ParseTupleAndKeywords(args.ptr(), kwds.ptr(), + "OO!O!", kwds_poly, + &seq, + &Mesh::MeshPy::Type, &m, + &Base::VectorPy::Type, &v)) { + std::vector polylinesIn; + Py::Sequence edges(seq); + polylinesIn.reserve(edges.size()); + + // collect list of sampled input edges + for (Py::Sequence::iterator it = edges.begin(); it != edges.end(); ++it) { + Py::Sequence edge(*it); + MeshProjection::PolyLine poly; + poly.points.reserve(edge.size()); + + for (Py::Sequence::iterator jt = edge.begin(); jt != edge.end(); ++jt) { + Py::Vector pnt(*jt); + poly.points.push_back(Base::convertTo(pnt.toVector())); + } + + polylinesIn.push_back(poly); + } + + 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(polylinesIn, 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:\n" + "Shape, Mesh, float or\n" + "Shape, Mesh, Vector or\n" + "Polygons, Mesh, Vector\n"); } Py::Object wireFromSegment(const Py::Tuple& args) { diff --git a/src/Mod/MeshPart/App/CurveProjector.cpp b/src/Mod/MeshPart/App/CurveProjector.cpp index e42760633a..2e58929965 100644 --- a/src/Mod/MeshPart/App/CurveProjector.cpp +++ b/src/Mod/MeshPart/App/CurveProjector.cpp @@ -813,6 +813,51 @@ void MeshProjection::projectParallelToMesh (const TopoDS_Shape &aShape, const Ba } } +void MeshProjection::projectParallelToMesh (const std::vector &aEdges, 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); + + Base::SequencerLauncher seq( "Project curve on mesh", aEdges.size() ); + + for (auto it : aEdges) { + std::vector points = it.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(); + } +} + void MeshProjection::projectEdgeToEdge( const TopoDS_Edge &aEdge, float fMaxDist, const MeshFacetGrid& rGrid, std::vector& rSplitEdges ) const { diff --git a/src/Mod/MeshPart/App/CurveProjector.h b/src/Mod/MeshPart/App/CurveProjector.h index f5f77bd2e9..36ccd8d9f1 100644 --- a/src/Mod/MeshPart/App/CurveProjector.h +++ b/src/Mod/MeshPart/App/CurveProjector.h @@ -191,6 +191,10 @@ public: * 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; + /** + * Project all polylines onto the mesh using parallel projection. + */ + void projectParallelToMesh (const std::vector& aEdges, 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.