From bdaced51d02776609792c11a4bafd287c0d6f052 Mon Sep 17 00:00:00 2001 From: CalaW Date: Sun, 13 Apr 2025 22:35:36 +0800 Subject: [PATCH 01/26] Use pybind11 to replace boost.python --- src/algo/clsurface.hpp | 29 ++- src/pythonlib/adaptivepathdropcutter_py.hpp | 46 ++-- src/pythonlib/adaptivewaterline_py.hpp | 95 ++++---- src/pythonlib/batchdropcutter_py.hpp | 69 +++--- src/pythonlib/batchpushcutter_py.hpp | 140 ++++++------ src/pythonlib/fiber_py.hpp | 55 +++-- src/pythonlib/lineclfilter_py.hpp | 53 ++--- src/pythonlib/millingcutter_py.hpp | 107 +++------ src/pythonlib/ocl.cpp | 81 +++---- src/pythonlib/ocl_algo.cpp | 190 ++++++++-------- src/pythonlib/ocl_cutters.cpp | 119 +++++----- src/pythonlib/ocl_dropcutter.cpp | 60 +++-- src/pythonlib/ocl_geometry.cpp | 230 ++++++++++---------- src/pythonlib/path_py.hpp | 100 ++++----- src/pythonlib/pathdropcutter_py.hpp | 53 ++--- src/pythonlib/pythonlib.cmake | 7 +- src/pythonlib/stlsurf_py.hpp | 85 ++++---- src/pythonlib/triangle_py.hpp | 88 ++++---- src/pythonlib/waterline_py.hpp | 96 ++++---- src/pythonlib/weave_py.h | 102 --------- src/pythonlib/weave_py.hpp | 125 ++++++----- src/pythonlib/zigzag_py.hpp | 45 ++-- 22 files changed, 873 insertions(+), 1102 deletions(-) delete mode 100644 src/pythonlib/weave_py.h diff --git a/src/algo/clsurface.hpp b/src/algo/clsurface.hpp index 603eab86..6a4a9cfa 100644 --- a/src/algo/clsurface.hpp +++ b/src/algo/clsurface.hpp @@ -250,25 +250,24 @@ class CutterLocationSurface : public Operation { } // PYTHON - boost::python::list getVertices() { - boost::python::list plist; - BOOST_FOREACH( CLSVertex v, g.vertices() ) { - plist.append( g[v].position ); + std::vector getVertices() + { + std::vector vertices; + for (CLSVertex v : g.vertices()) { + vertices.push_back(g[v].position); } - return plist; + return vertices; } - boost::python::list getEdges() { - boost::python::list edge_list; - BOOST_FOREACH( CLSEdge edge, g.edges() ) { // loop through each edge - boost::python::list point_list; // the endpoints of each edge - CLSVertex v1 = g.source( edge ); - CLSVertex v2 = g.target( edge ); - point_list.append( g[v1].position ); - point_list.append( g[v2].position ); - edge_list.append(point_list); + std::vector> getEdges() + { + std::vector> edges; + for (CLSEdge edge : g.edges()) { + CLSVertex v1 = g.source(edge); + CLSVertex v2 = g.target(edge); + edges.push_back(std::make_pair(g[v1].position, g[v2].position)); } - return edge_list; + return edges; } /// string repr diff --git a/src/pythonlib/adaptivepathdropcutter_py.hpp b/src/pythonlib/adaptivepathdropcutter_py.hpp index 06068f65..20e2fd7e 100644 --- a/src/pythonlib/adaptivepathdropcutter_py.hpp +++ b/src/pythonlib/adaptivepathdropcutter_py.hpp @@ -1,50 +1,42 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef ADAPTIVEPATHDROPCUTTER_PY_H #define ADAPTIVEPATHDROPCUTTER_PY_H -#include +#include +#include #include "adaptivepathdropcutter.hpp" -namespace ocl -{ - +namespace ocl { + /// Python wrapper for PathDropCutter class AdaptivePathDropCutter_py : public AdaptivePathDropCutter { - public: - AdaptivePathDropCutter_py() : AdaptivePathDropCutter() {} - virtual ~AdaptivePathDropCutter_py() {} - /// return a list of CL-points to python - boost::python::list getCLPoints_py() { - //std::cout << " apdc_py::getCLPoints_py()..."; - boost::python::list plist; - BOOST_FOREACH(CLPoint p, clpoints) { - plist.append(p); - } - //std::cout << " DONE.\n"; - return plist; - } +public: + AdaptivePathDropCutter_py() : AdaptivePathDropCutter() {} + virtual ~AdaptivePathDropCutter_py() {} + /// return a list of CL-points to python + std::vector getCLPoints_py() { return clpoints; } // TODO use auto conversion }; -} // end namespace -#endif -// end file adaptivepathdropcutter_py.h +} // namespace ocl + +#endif // ADAPTIVEPATHDROPCUTTER_PY_H diff --git a/src/pythonlib/adaptivewaterline_py.hpp b/src/pythonlib/adaptivewaterline_py.hpp index fe95bca5..c1566870 100644 --- a/src/pythonlib/adaptivewaterline_py.hpp +++ b/src/pythonlib/adaptivewaterline_py.hpp @@ -1,76 +1,81 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef ADAPTIVEWATERLINE_PY_H #define ADAPTIVEWATERLINE_PY_H #include "adaptivewaterline.hpp" #include "fiber_py.hpp" -namespace ocl -{ +#include +#include +#include + +namespace py = pybind11; + +namespace ocl { /// \brief python wrapper for AdaptiveWaterline class AdaptiveWaterline_py : public AdaptiveWaterline { - public: - AdaptiveWaterline_py() : AdaptiveWaterline() {} - ~AdaptiveWaterline_py() { - std::cout << "~AdaptiveWaterline_py()\n"; - } - - /// return loop as a list of lists to python - boost::python::list py_getLoops() const { - boost::python::list loop_list; - BOOST_FOREACH( std::vector loop, this->loops ) { - boost::python::list point_list; - BOOST_FOREACH( Point p, loop ) { - point_list.append( p ); - } - loop_list.append(point_list); +public: + AdaptiveWaterline_py() : AdaptiveWaterline() {} + ~AdaptiveWaterline_py() { std::cout << "~AdaptiveWaterline_py()\n"; } + + /// return loop as a list of lists to python + py::list py_getLoops() const { + py::list loop_list; + for (const auto& loop : loops) { + py::list point_list; + for (const auto& p : loop) { + point_list.append(p); } - return loop_list; + loop_list.append(point_list); } - /// return a list of xfibers to python - boost::python::list getXFibers() const { - boost::python::list flist; - BOOST_FOREACH( Fiber f, xfibers ) { - if (!f.empty()) { - Fiber_py f2(f); - flist.append(f2); - } + return loop_list; + } + + /// return a list of xfibers to python + py::list getXFibers() const { + py::list flist; + for (const Fiber& f : xfibers) { + if (!f.empty()) { + Fiber_py f2(f); + flist.append(f2); } - return flist; } - /// return a list of yfibers to python - boost::python::list getYFibers() const { - boost::python::list flist; - BOOST_FOREACH( Fiber f, yfibers ) { - if (!f.empty()){ - Fiber_py f2(f); - flist.append(f2); - } + return flist; + } + + /// return a list of yfibers to python + py::list getYFibers() const { + py::list flist; + for (const Fiber& f : yfibers) { + if (!f.empty()) { + Fiber_py f2(f); + flist.append(f2); } - return flist; } + return flist; + } }; -} // end namespace +} // end namespace ocl -#endif +#endif // ADAPTIVEWATERLINE_PY_H diff --git a/src/pythonlib/batchdropcutter_py.hpp b/src/pythonlib/batchdropcutter_py.hpp index 53b89187..036a03e4 100644 --- a/src/pythonlib/batchdropcutter_py.hpp +++ b/src/pythonlib/batchdropcutter_py.hpp @@ -1,60 +1,57 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef BDC_PY_H #define BDC_PY_H -#include -#include +#include +#include #include "batchdropcutter.hpp" -namespace ocl -{ +namespace ocl { -/// Python wrapper for BatchDropCutter +/// Python wrapper for BatchDropCutter using pybind11 class BatchDropCutter_py : public BatchDropCutter { - public: - BatchDropCutter_py() : BatchDropCutter() {}; - /// return CL-points to Python - boost::python::list getCLPoints_py() { - boost::python::list plist; - BOOST_FOREACH(CLPoint p, *clpoints) { - plist.append(p); - } - return plist; - }; - /// return triangles under cutter to Python. Not for CAM-algorithms, - /// more for visualization and demonstration. - boost::python::list getTrianglesUnderCutter(CLPoint& cl, MillingCutter& cutter) { - boost::python::list trilist; - std::list *triangles_under_cutter = new std::list(); - triangles_under_cutter = root->search_cutter_overlap( &cutter , &cl); - BOOST_FOREACH(Triangle t, *triangles_under_cutter) { - trilist.append(t); - } - delete triangles_under_cutter; - return trilist; - }; +public: + BatchDropCutter_py() : BatchDropCutter() {} + + /// Return CL-points to Python as a std::vector (automatically converted to a Python list) + std::vector getCLPoints_py() { + std::vector plist; + for (const auto& p : *clpoints) + plist.push_back(p); + return plist; + } // TODO use auto conversion + + /// Return triangles under cutter to Python. + std::vector getTrianglesUnderCutter(CLPoint& cl, MillingCutter& cutter) { + std::vector trilist; + std::list* triangles_under_cutter = root->search_cutter_overlap(&cutter, &cl); + for (const auto& t : *triangles_under_cutter) + trilist.push_back(t); + delete triangles_under_cutter; + return trilist; + } }; -} // end namespace +} // end namespace ocl -#endif +#endif // BDC_PY_H diff --git a/src/pythonlib/batchpushcutter_py.hpp b/src/pythonlib/batchpushcutter_py.hpp index f2111815..590948d1 100644 --- a/src/pythonlib/batchpushcutter_py.hpp +++ b/src/pythonlib/batchpushcutter_py.hpp @@ -1,98 +1,98 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef BPC_PY_H #define BPC_PY_H -#include +#include +#include -#include "batchpushcutter.hpp" +#include +#include +#include "batchpushcutter.hpp" #include "fiber_py.hpp" -namespace ocl -{ -/// \brief python wrapper for batchpushcutter +namespace py = pybind11; + +namespace ocl { + class BatchPushCutter_py : public BatchPushCutter { - public: - BatchPushCutter_py() : BatchPushCutter() {} - /// return CL-points to Python - boost::python::list getCLPoints_py() const { - boost::python::list plist; - BOOST_FOREACH(Fiber f, *fibers) { - BOOST_FOREACH( Interval i, f.ints ) { - if ( !i.empty() ) { - Point tmp = f.point(i.lower); - CLPoint p1 = CLPoint( tmp.x, tmp.y, tmp.z ); - p1.cc = new CCPoint(i.lower_cc); - tmp = f.point(i.upper); - CLPoint p2 = CLPoint( tmp.x, tmp.y, tmp.z ); - p2.cc = new CCPoint(i.upper_cc); - plist.append(p1); - plist.append(p2); - } +public: + BatchPushCutter_py() : BatchPushCutter() {} + + // return CL-points to Python + py::list getCLPoints_py() const { + py::list plist; + for (const Fiber& f : *fibers) { + for (const Interval& i : f.ints) { + if (!i.empty()) { + Point tmp = f.point(i.lower); + CLPoint p1(tmp.x, tmp.y, tmp.z); + p1.cc = new CCPoint(i.lower_cc); + tmp = f.point(i.upper); + CLPoint p2(tmp.x, tmp.y, tmp.z); + p2.cc = new CCPoint(i.upper_cc); + plist.append(p1); + plist.append(p2); } - } - return plist; - }; - /// return triangles under cutter to Python. Not for CAM-algorithms, - /// more for visualization and demonstration. - boost::python::list getOverlapTriangles(Fiber& f) { - boost::python::list trilist; - std::list *overlap_triangles = new std::list(); - //int plane = 3; // XY-plane - //Bbox bb; //FIXME - //KDNode2::search_kdtree( overlap_triangles, bb, root, plane); - CLPoint cl; - if (x_direction) { - cl.x = 0; - cl.y = f.p1.y; - cl.z = f.p1.z; - } else if (y_direction) { - cl.x = f.p1.x; - cl.y = 0; - cl.z = f.p1.z; - } else { - assert(0); - } - overlap_triangles = root->search_cutter_overlap(cutter, &cl); - - BOOST_FOREACH(Triangle t, *overlap_triangles) { - trilist.append(t); - } - delete overlap_triangles; - return trilist; - }; - /// return list of Fibers to python - boost::python::list getFibers_py() const { - boost::python::list flist; - BOOST_FOREACH(Fiber f, *fibers) { - flist.append( Fiber_py(f) ); - } - return flist; - }; + } + return plist; + } // TODO use auto conversion + + // return triangles under cutter to Python. Not for CAM-algorithms, more for + // visualization and demonstration. + py::list getOverlapTriangles(Fiber& f) { + py::list trilist; + std::list* overlap_triangles = new std::list(); + CLPoint cl; + if (x_direction) { + cl.x = 0; + cl.y = f.p1.y; + cl.z = f.p1.z; + } else if (y_direction) { + cl.x = f.p1.x; + cl.y = 0; + cl.z = f.p1.z; + } else { + assert(0); + } + overlap_triangles = root->search_cutter_overlap(cutter, &cl); + for (const Triangle& t : *overlap_triangles) { + trilist.append(t); + } + delete overlap_triangles; + return trilist; + } + py::list getFibers_py() const { + py::list flist; + for (const Fiber& f : *fibers) { + flist.append(Fiber_py(f)); + } + return flist; + } // TODO use auto conversion }; -} // end namespace +} // namespace ocl -#endif +#endif // BPC_PY_H diff --git a/src/pythonlib/fiber_py.hpp b/src/pythonlib/fiber_py.hpp index 52013ec0..5dfffe61 100644 --- a/src/pythonlib/fiber_py.hpp +++ b/src/pythonlib/fiber_py.hpp @@ -1,52 +1,49 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ + #ifndef FIBER_PY_H #define FIBER_PY_H -#include -#include +#include +#include #include "fiber.hpp" -namespace ocl -{ +namespace ocl { -/// python wrapper for Fiber class Fiber_py : public Fiber { - public: - Fiber_py() : Fiber () {}; - /// construct p1-p2 fiber - Fiber_py(const Point &p1, const Point &p2) : Fiber(p1, p2) {}; - /// copy constructor - Fiber_py(const Fiber& f) : Fiber(f) {}; - /// return a list of intervals to python - boost::python::list getInts() const { - boost::python::list l; - BOOST_FOREACH( Interval i, ints) { - l.append( i ); - } - return l; - }; +public: + Fiber_py() : Fiber() {} + Fiber_py(const Point& p1, const Point& p2) : Fiber(p1, p2) {} + Fiber_py(const Fiber& f) : Fiber(f) {} + + pybind11::list getInts() const { + pybind11::list l; + for (const auto& i : ints) { + l.append(i); + } + return l; + } }; -} // end namespace -#endif -// end file fiber_py.h +} // namespace ocl + +#endif // FIBER_PY_H diff --git a/src/pythonlib/lineclfilter_py.hpp b/src/pythonlib/lineclfilter_py.hpp index 313826a7..83ff68a5 100644 --- a/src/pythonlib/lineclfilter_py.hpp +++ b/src/pythonlib/lineclfilter_py.hpp @@ -1,48 +1,51 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef LINE_CL_FILTER_PY_H #define LINE_CL_FILTER_PY_H -#include +#include +#include #include "lineclfilter.hpp" -namespace ocl -{ -/// python wrapper for lineclfilter +namespace py = pybind11; + +namespace ocl { + +/// python wrapper for LineCLFilter class LineCLFilter_py : public LineCLFilter { - public: - LineCLFilter_py() : LineCLFilter() {}; - /// return a list of CL-points to python - boost::python::list getCLPoints() { - // return points to python - boost::python::list plist; - BOOST_FOREACH(CLPoint p, clpoints) { - plist.append(p); - } - return plist; - }; +public: + LineCLFilter_py() : LineCLFilter() {} + + /// Return a list of CL-points to python + py::list getCLPoints() { + py::list plist; + for (const auto& p : clpoints) { + plist.append(p); + } + return plist; + } }; -} // end namespace -#endif -// end file lineclfilter_py.h +} // namespace ocl + +#endif // LINE_CL_FILTER_PY_H diff --git a/src/pythonlib/millingcutter_py.hpp b/src/pythonlib/millingcutter_py.hpp index 1f411d18..ef278d90 100644 --- a/src/pythonlib/millingcutter_py.hpp +++ b/src/pythonlib/millingcutter_py.hpp @@ -1,97 +1,56 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef MILLING_CUTTER_PY_H #define MILLING_CUTTER_PY_H -#include +#include #include "millingcutter.hpp" -namespace ocl -{ +namespace ocl { -/* required wrapper class for virtual functions in boost-python */ -/// \brief a wrapper required for boost-python -// see documentation: -// http://www.boost.org/doc/libs/1_43_0/libs/python/doc/tutorial/doc/html/python/exposing.html#python.inheritance -class MillingCutter_py : public MillingCutter, public boost::python::wrapper -{ - public: - // vertex - bool vertexDrop(CLPoint &cl, const Triangle &t) const { - if ( boost::python::override ovr_vertexDrop = this->get_override("vertexDrop")) - return ovr_vertexDrop(cl, t); - return MillingCutter::vertexDrop(cl, t); - } - /// python-wrapper boilerplate... - bool default_vertexDrop(CLPoint &cl, const Triangle &t) const { - return this->MillingCutter::vertexDrop(cl,t); - } - - // facet - bool facetDrop(CLPoint &cl, const Triangle &t) const { - if ( boost::python::override ovr_facetDrop = this->get_override("facetDrop")) - return ovr_facetDrop(cl, t); - return MillingCutter::facetDrop(cl, t); - } - /// python-wrapper boilerplate... - bool default_facetDrop(CLPoint &cl, const Triangle &t) const { - return this->MillingCutter::facetDrop(cl,t); - } - - - // edge - bool edgeDrop(CLPoint &cl, const Triangle &t) const { - if ( boost::python::override ovr_edgeDrop = this->get_override("edgeDrop")) - return ovr_edgeDrop(cl, t); - return MillingCutter::edgeDrop(cl, t); - } - /// python-wrapper boilerplate... - bool default_edgeDrop(CLPoint &cl, const Triangle &t) const { - return this->MillingCutter::edgeDrop(cl,t); - } - - MillingCutter* offsetCutter(double d) const { - if ( boost::python::override ovr_offsetCutter = this->get_override("offsetCutter") ) - return ovr_offsetCutter(d); - return MillingCutter::offsetCutter(d); - } - /// python-wrapper boilerplate... - MillingCutter* default_offsetCutter(double d) const { - return this->MillingCutter::offsetCutter(d); - } - - std::string str() const { - if ( boost::python::override ovr_str = this->get_override("str")) { - return ovr_str(); - } - return MillingCutter::str(); - } - /// python-wrapper boilerplate... - std::string default_str() const { - return this->MillingCutter::str(); - } +class MillingCutter_py : public MillingCutter { +public: + using MillingCutter::MillingCutter; // inherit constructors if needed + + bool vertexDrop(CLPoint& cl, const Triangle& t) const { + PYBIND11_OVERRIDE(bool, MillingCutter, vertexDrop, cl, t); + } + + bool facetDrop(CLPoint& cl, const Triangle& t) const override { + PYBIND11_OVERRIDE(bool, MillingCutter, facetDrop, cl, t); + } + + bool edgeDrop(CLPoint& cl, const Triangle& t) const override { + PYBIND11_OVERRIDE(bool, MillingCutter, edgeDrop, cl, t); + } + + MillingCutter* offsetCutter(double d) const override { + PYBIND11_OVERRIDE(MillingCutter*, MillingCutter, offsetCutter, d); + } + + std::string str() const override { PYBIND11_OVERRIDE(std::string, MillingCutter, str); } }; -} // end namespace -#endif -// end file millingcutter_py.h +} // end namespace ocl + +#endif // MILLING_CUTTER_PY_H diff --git a/src/pythonlib/ocl.cpp b/src/pythonlib/ocl.cpp index 72f0efc8..a8de9c4b 100644 --- a/src/pythonlib/ocl.cpp +++ b/src/pythonlib/ocl.cpp @@ -1,81 +1,58 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ -// This is an extra comment. One can never have too many comments. +#include #ifdef _OPENMP - #include +#include #endif -#include -#include - #include "version_string.hpp" // autogenerated by version_string.cmake +#include -std::string ocl_docstring() { - return "OpenCAMLib docstring"; -} +namespace py = pybind11; -std::string ocl_version() { - return VERSION_STRING; -} +std::string ocl_docstring() { return "OpenCAMLib docstring"; } -int ocl_max_threads() -{ - #ifdef _OPENMP +std::string ocl_version() { return VERSION_STRING; } + +int ocl_max_threads() { +#ifdef _OPENMP return omp_get_max_threads(); - #endif +#endif return 1; } -namespace bp = boost::python; +void export_cutters(py::module_& m); +void export_geometry(py::module_& m); +void export_algo(py::module_& m); +void export_dropcutter(py::module_& m); -void export_cutters(); -void export_geometry(); -void export_algo(); -void export_dropcutter(); +PYBIND11_MODULE(ocl, m) { + m.doc() = ocl_docstring(); -// this defines the python ocl module -BOOST_PYTHON_MODULE(ocl) { - bp::docstring_options doc_options; -// these functions set the docstring options - //void disable_user_defined(); - void enable_user_defined(); - //void disable_signatures(); - void enable_signatures(); - //void disable_py_signatures(); - void enable_py_signatures(); - //void disable_cpp_signatures(); - void enable_cpp_signatures(); - //void disable_all(); - //void enable_all(); - - bp::def("__doc__", ocl_docstring); - bp::def("version", ocl_version); - bp::def("max_threads", ocl_max_threads); - export_geometry(); // see ocl_geometry.cpp - export_cutters(); // see ocl_cutters.cpp - export_algo(); // see ocl_algo.cpp - export_dropcutter(); // see ocl_dropcutter.cpp + m.def("version", &ocl_version, "Return the version string of OpenCAMLib"); + m.def("max_threads", &ocl_max_threads, "Return the maximum number of available threads"); + export_geometry(m); // defined in ocl_geometry.cpp + export_cutters(m); // defined in ocl_cutters.cpp + export_algo(m); // defined in ocl_algo.cpp + export_dropcutter(m); // defined in ocl_dropcutter.cpp } - - - diff --git a/src/pythonlib/ocl_algo.cpp b/src/pythonlib/ocl_algo.cpp index 33edb695..ba8d575e 100644 --- a/src/pythonlib/ocl_algo.cpp +++ b/src/pythonlib/ocl_algo.cpp @@ -1,110 +1,103 @@ /* $Id$ - * + * * Copyright (c) 2010-2011 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ - -#include - - -#include "batchpushcutter_py.hpp" -#include "fiber_py.hpp" -#include "weave_py.hpp" -#include "waterline_py.hpp" -#include "adaptivewaterline_py.hpp" -#include "lineclfilter_py.hpp" -#include "numeric.hpp" - -#include "zigzag_py.hpp" + */ +#include +#include "adaptivewaterline_py.hpp" +#include "batchpushcutter_py.hpp" #include "clsurface.hpp" - +#include "fiber_py.hpp" +#include "lineclfilter_py.hpp" +#include "numeric.hpp" #include "tsp.hpp" // fixme: contains python +#include "waterline_py.hpp" +#include "weave_py.hpp" +#include "zigzag_py.hpp" -/* - * Python wrapping of octree and related classes - */ - +namespace py = pybind11; using namespace ocl; -namespace bp = boost::python; - -void export_algo() { - bp::def("eps", eps); // machine epsilon, see numeric.cpp - bp::def("epsF", epsF); - bp::def("epsD", epsD); +void export_algo(py::module& m) { + m.def("eps", eps, "machine epsilon, see numeric.cpp"); + m.def("epsF", epsF); + m.def("epsD", epsD); - bp::class_("ZigZag_base"); + py::class_(m, "ZigZag_base"); - bp::class_>("ZigZag") + py::class_(m, "ZigZag") + .def(py::init<>()) .def("run", &ZigZag::run) .def("setDirection", &ZigZag::setDirection) .def("setOrigin", &ZigZag::setOrigin) .def("setStepOver", &ZigZag::setStepOver) .def("addPoint", &ZigZag::addPoint) .def("getOutput", &ZigZag_py::getOutput) - .def("__str__", &ZigZag::str) - ; + .def("__str__", &ZigZag::str); - bp::class_("BatchPushCutter_base") - ; - bp::class_>("BatchPushCutter") + py::class_(m, "BatchPushCutter_base"); + + py::class_(m, "BatchPushCutter") + .def(py::init<>()) .def("run", &BatchPushCutter_py::run) .def("setSTL", &BatchPushCutter_py::setSTL) .def("setCutter", &BatchPushCutter_py::setCutter) - .def("setThreads", &BatchPushCutter_py::setThreads) + .def("setThreads", (void(BatchPushCutter_py::*)(int)) & BatchPushCutter_py::setThreads) .def("appendFiber", &BatchPushCutter_py::appendFiber) .def("getOverlapTriangles", &BatchPushCutter_py::getOverlapTriangles) .def("getCLPoints", &BatchPushCutter_py::getCLPoints_py) .def("getFibers", &BatchPushCutter_py::getFibers_py) .def("getCalls", &BatchPushCutter_py::getCalls) - .def("setThreads", &BatchPushCutter_py::setThreads) + .def("setThreads", (void(BatchPushCutter_py::*)(int)) & BatchPushCutter_py::setThreads) .def("getThreads", &BatchPushCutter_py::getThreads) .def("setBucketSize", &BatchPushCutter_py::setBucketSize) .def("getBucketSize", &BatchPushCutter_py::getBucketSize) .def("setXDirection", &BatchPushCutter_py::setXDirection) .def("setYDirection", &BatchPushCutter_py::setYDirection); - bp::class_("Interval") - .def(bp::init()) - .def_readonly("upper", &Interval::upper ) - .def_readonly("lower", &Interval::lower ) - .def_readonly("lower_cc", &Interval::lower_cc ) - .def_readonly("upper_cc", &Interval::upper_cc ) - .def("updateUpper", &Interval::updateUpper ) - .def("updateLower", &Interval::updateLower ) - .def("empty", &Interval::empty ) - .def("__str__", &Interval::str ) - ; - bp::class_("Fiber_base") - ; - bp::class_ >("Fiber") - .def(bp::init()) + + py::class_(m, "Interval") + .def(py::init()) + .def_readonly("upper", &Interval::upper) + .def_readonly("lower", &Interval::lower) + .def_readonly("lower_cc", &Interval::lower_cc) + .def_readonly("upper_cc", &Interval::upper_cc) + .def("updateUpper", &Interval::updateUpper) + .def("updateLower", &Interval::updateLower) + .def("empty", &Interval::empty) + .def("__str__", &Interval::str); + + py::class_(m, "Fiber_base"); + + py::class_(m, "Fiber") + .def(py::init()) .def_readonly("p1", &Fiber_py::p1) .def_readonly("p2", &Fiber_py::p2) .def_readonly("dir", &Fiber_py::dir) .def("addInterval", &Fiber_py::addInterval) .def("point", &Fiber_py::point) .def("printInts", &Fiber_py::printInts) - .def("getInts", &Fiber_py::getInts) - ; - bp::class_("Waterline_base") - ; - bp::class_ >("Waterline") + .def("getInts", &Fiber_py::getInts); + + py::class_(m, "Waterline_base"); + + py::class_(m, "Waterline") + .def(py::init<>()) .def("setCutter", &Waterline_py::setCutter) .def("setSTL", &Waterline_py::setSTL) .def("setZ", &Waterline_py::setZ) @@ -116,12 +109,12 @@ void export_algo() { .def("setThreads", &Waterline_py::setThreads) .def("getThreads", &Waterline_py::getThreads) .def("getXFibers", &Waterline_py::py_getXFibers) - .def("getYFibers", &Waterline_py::py_getYFibers) - - ; - bp::class_("AdaptiveWaterline_base") - ; - bp::class_ >("AdaptiveWaterline") + .def("getYFibers", &Waterline_py::py_getYFibers); + + py::class_(m, "AdaptiveWaterline_base"); + + py::class_(m, "AdaptiveWaterline") + .def(py::init<>()) .def("setCutter", &AdaptiveWaterline_py::setCutter) .def("setSTL", &AdaptiveWaterline_py::setSTL) .def("setZ", &AdaptiveWaterline_py::setZ) @@ -130,35 +123,32 @@ void export_algo() { .def("run", &AdaptiveWaterline_py::run) .def("run2", &AdaptiveWaterline_py::run2) .def("reset", &AdaptiveWaterline_py::reset) - //.def("run2", &AdaptiveWaterline_py::run2) // uses Weave::build2() + // .def("run2", &AdaptiveWaterline_py::run2) // uses Weave::build2() .def("getLoops", &AdaptiveWaterline_py::py_getLoops) .def("setThreads", &AdaptiveWaterline_py::setThreads) .def("getThreads", &AdaptiveWaterline_py::getThreads) .def("getXFibers", &AdaptiveWaterline_py::getXFibers) - .def("getYFibers", &AdaptiveWaterline_py::getYFibers) - ; - - bp::enum_("WeaveVertexType") + .def("getYFibers", &AdaptiveWaterline_py::getYFibers); + + py::enum_(m, "WeaveVertexType") .value("CL", weave::CL) - .value("CL_DONE",weave::CL_DONE) - .value("ADJ",weave::ADJ) - .value("TWOADJ",weave::TWOADJ) - .value("INT",weave::INT) - .value("FULLINT",weave::FULLINT) - ; - - + .value("CL_DONE", weave::CL_DONE) + .value("ADJ", weave::ADJ) + .value("TWOADJ", weave::TWOADJ) + .value("INT", weave::INT) + .value("FULLINT", weave::FULLINT); + /* - bp::class_("Weave_base") - ; - bp::class_ >("Weave") + py::class_(m, "Weave_base"); + + py::class_(m, "Weave") .def("addFiber", &weave::Weave_py::addFiber) .def("build", &weave::Weave_py::build) .def("build2", &weave::Weave_py::build2) .def("printGraph", &weave::Weave_py::printGraph) .def("face_traverse", &weave::Weave_py::face_traverse) - //.def("split_components", &weave::Weave_py::split_components) - //.def("get_components", &weave::Weave_py::get_components) + // .def("split_components", &weave::Weave_py::split_components) + // .def("get_components", &weave::Weave_py::get_components) .def("getCLVertices", &weave::Weave_py::getCLVertices) .def("getINTVertices", &weave::Weave_py::getINTVertices) .def("getVertices", &weave::Weave_py::getVertices) @@ -168,19 +158,18 @@ void export_algo() { .def("__str__", &weave::Weave_py::str) ; */ - - bp::class_("LineCLFilter_base") - ; - bp::class_ >("LineCLFilter") - .def("addCLPoint", &LineCLFilter_py::addCLPoint) - .def("setTolerance",&LineCLFilter_py::setTolerance) - .def("run", &LineCLFilter_py::run) - .def("getCLPoints", &LineCLFilter_py::getCLPoints) - ; - // some strange problem with hedi::face_edges()... let's not compile for now.. - bp::class_< clsurf::CutterLocationSurface >("CutterLocationSurface") - .def(bp::init()) + py::class_(m, "LineCLFilter_base"); + + py::class_(m, "LineCLFilter") + .def(py::init<>()) + .def("addCLPoint", &LineCLFilter_py::addCLPoint) + .def("setTolerance", &LineCLFilter_py::setTolerance) + .def("run", &LineCLFilter_py::run) + .def("getCLPoints", &LineCLFilter_py::getCLPoints); + + py::class_(m, "CutterLocationSurface") + .def(py::init()) .def("run", &clsurf::CutterLocationSurface::run) .def("setMinSampling", &clsurf::CutterLocationSurface::setMinSampling) .def("setSampling", &clsurf::CutterLocationSurface::setSampling) @@ -188,10 +177,10 @@ void export_algo() { .def("setCutter", &clsurf::CutterLocationSurface::setCutter) .def("getVertices", &clsurf::CutterLocationSurface::getVertices) .def("getEdges", &clsurf::CutterLocationSurface::getEdges) - .def("__str__", &clsurf::CutterLocationSurface::str) - ; -/* - bp::class_< tsp::TSPSolver >("TSPSolver") + .def("__str__", &clsurf::CutterLocationSurface::str); + + /* + py::class_(m, "TSPSolver") .def("addPoint", &tsp::TSPSolver::addPoint) .def("run", &tsp::TSPSolver::run) .def("getOutput", &tsp::TSPSolver::getOutput) @@ -200,4 +189,3 @@ void export_algo() { ; */ } - diff --git a/src/pythonlib/ocl_cutters.cpp b/src/pythonlib/ocl_cutters.cpp index 714cea9d..1361ab1a 100644 --- a/src/pythonlib/ocl_cutters.cpp +++ b/src/pythonlib/ocl_cutters.cpp @@ -1,91 +1,74 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ - -#include + */ +#include -#include "millingcutter.hpp" -#include "millingcutter_py.hpp" -#include "cylcutter.hpp" #include "ballcutter.hpp" #include "bullcutter.hpp" -#include "conecutter.hpp" #include "compositecutter.hpp" +#include "conecutter.hpp" +#include "cylcutter.hpp" +#include "millingcutter.hpp" +#include "millingcutter_py.hpp" -/* - * wrap cutters - */ - +namespace py = pybind11; using namespace ocl; -namespace bp = boost::python; - -void export_cutters() { -// documentation here: -// http://www.boost.org/doc/libs/1_43_0/libs/python/doc/tutorial/doc/html/python/exposing.html#python.inheritance - - bp::class_("MillingCutter") - .def("vertexDrop", &MillingCutter::vertexDrop, &MillingCutter_py::default_vertexDrop ) - .def("facetDrop", &MillingCutter::facetDrop, &MillingCutter_py::default_facetDrop ) - .def("edgeDrop", &MillingCutter::edgeDrop, &MillingCutter_py::default_edgeDrop ) +void export_cutters(py::module& m) { + py::class_(m, "MillingCutter") + .def("vertexDrop", &MillingCutter::vertexDrop) + .def("facetDrop", &MillingCutter::facetDrop) + .def("edgeDrop", &MillingCutter::edgeDrop) .def("dropCutter", &MillingCutter::dropCutter) .def("pushCutter", &MillingCutter::pushCutter) - .def("offsetCutter", &MillingCutter::offsetCutter, bp::return_value_policy() ) - .def("__str__", &MillingCutter::str, &MillingCutter_py::default_str ) - .def("getRadius", &MillingCutter::getRadius ) - .def("getLength", &MillingCutter::getLength ) - .def("getDiameter", &MillingCutter::getDiameter ) - ; - bp::class_ >("CylCutter") - .def(bp::init()) - .def("dropCutterSTL", &CylCutter::dropCutterSTL) - ; - bp::class_ >("BallCutter") - .def(bp::init()) - .def("dropCutterSTL", &BallCutter::dropCutterSTL) - ; - bp::class_ >("BullCutter") - .def(bp::init()) - ; - bp::class_ >("ConeCutter") - .def(bp::init()) - ; - - bp::class_ >("CompCylCutter") - .def(bp::init()) - ; - bp::class_ >("CompBallCutter") - .def(bp::init()) - ; - - bp::class_ >("CylConeCutter") - .def(bp::init()) - ; - bp::class_ >("BallConeCutter") - .def(bp::init()) - ; - bp::class_ >("BullConeCutter") - .def(bp::init()) - ; - bp::class_ >("ConeConeCutter") - .def(bp::init()) - ; -} + .def("offsetCutter", &MillingCutter::offsetCutter, py::return_value_policy::take_ownership) + .def("__str__", &MillingCutter::str) + .def("getRadius", &MillingCutter::getRadius) + .def("getLength", &MillingCutter::getLength) + .def("getDiameter", &MillingCutter::getDiameter); + + py::class_(m, "CylCutter") + .def(py::init()) + .def("dropCutterSTL", &CylCutter::dropCutterSTL); + + py::class_(m, "BallCutter") + .def(py::init()) + .def("dropCutterSTL", &BallCutter::dropCutterSTL); + + py::class_(m, "BullCutter").def(py::init()); + + py::class_(m, "ConeCutter").def(py::init()); + py::class_(m, "CompCylCutter").def(py::init()); + + py::class_(m, "CompBallCutter").def(py::init()); + + py::class_(m, "CylConeCutter") + .def(py::init()); + + py::class_(m, "BallConeCutter") + .def(py::init()); + + py::class_(m, "BullConeCutter") + .def(py::init()); + + py::class_(m, "ConeConeCutter") + .def(py::init()); +} diff --git a/src/pythonlib/ocl_dropcutter.cpp b/src/pythonlib/ocl_dropcutter.cpp index 2f929d99..c618809c 100644 --- a/src/pythonlib/ocl_dropcutter.cpp +++ b/src/pythonlib/ocl_dropcutter.cpp @@ -1,44 +1,42 @@ /* $Id$ - * + * * Copyright (c) 2010-2011 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ - -#include + */ -#include "batchdropcutter_py.hpp" -#include "pathdropcutter_py.hpp" -#include "adaptivepathdropcutter_py.hpp" +#include +#include "adaptivepathdropcutter_py.hpp" +#include "batchdropcutter_py.hpp" +#include "pathdropcutter_py.hpp" /* * Python wrapping of octree and related classes */ +namespace py = pybind11; using namespace ocl; -namespace bp = boost::python; +void export_dropcutter(py::module_& m) { + py::class_(m, "BatchDropCutter_base"); -void export_dropcutter() { - - bp::class_("BatchDropCutter_base") - ; - bp::class_ >("BatchDropCutter") + py::class_(m, "BatchDropCutter") + .def(py::init<>()) .def("run", &BatchDropCutter_py::run) .def("getCLPoints", &BatchDropCutter_py::getCLPoints_py) .def("setSTL", &BatchDropCutter_py::setSTL) @@ -49,13 +47,12 @@ void export_dropcutter() { .def("getTrianglesUnderCutter", &BatchDropCutter_py::getTrianglesUnderCutter) .def("getCalls", &BatchDropCutter_py::getCalls) .def("getBucketSize", &BatchDropCutter_py::getBucketSize) - .def("setBucketSize", &BatchDropCutter_py::setBucketSize) - ; + .def("setBucketSize", &BatchDropCutter_py::setBucketSize); + py::class_(m, "PathDropCutter_base"); - bp::class_("PathDropCutter_base") - ; - bp::class_ >("PathDropCutter") + py::class_(m, "PathDropCutter") + .def(py::init<>()) .def("run", &PathDropCutter_py::run) .def("getCLPoints", &PathDropCutter_py::getCLPoints_py) .def("setCutter", &PathDropCutter_py::setCutter) @@ -63,11 +60,12 @@ void export_dropcutter() { .def("setSampling", &PathDropCutter_py::setSampling) .def("setPath", &PathDropCutter_py::setPath) .def("getZ", &PathDropCutter_py::getZ) - .def("setZ", &PathDropCutter_py::setZ) - ; - bp::class_("AdaptivePathDropCutter_base") - ; - bp::class_ >("AdaptivePathDropCutter") + .def("setZ", &PathDropCutter_py::setZ); + + py::class_(m, "AdaptivePathDropCutter_base"); + + py::class_(m, "AdaptivePathDropCutter") + .def(py::init<>()) .def("run", &AdaptivePathDropCutter_py::run) .def("getCLPoints", &AdaptivePathDropCutter_py::getCLPoints_py) .def("setCutter", &AdaptivePathDropCutter_py::setCutter) @@ -78,9 +76,5 @@ void export_dropcutter() { .def("getSampling", &AdaptivePathDropCutter_py::getSampling) .def("setPath", &AdaptivePathDropCutter_py::setPath) .def("getZ", &AdaptivePathDropCutter_py::getZ) - .def("setZ", &AdaptivePathDropCutter_py::setZ) - ; - - + .def("setZ", &AdaptivePathDropCutter_py::setZ); } - diff --git a/src/pythonlib/ocl_geometry.cpp b/src/pythonlib/ocl_geometry.cpp index 81151a14..375534bb 100644 --- a/src/pythonlib/ocl_geometry.cpp +++ b/src/pythonlib/ocl_geometry.cpp @@ -1,56 +1,52 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ -#include - -#include "point.hpp" // contains no python-specific code -#include "ccpoint.hpp" // no python -#include "clpoint.hpp" // no python -#include "triangle_py.hpp" // new-style python wrapper-class -#include "stlsurf_py.hpp" // new-style wrapper -#include "ellipse.hpp" // no python -#include "ellipseposition.hpp" -#include "bbox.hpp" // no python -#include "path_py.hpp" // new-style wrapper -#include "stlreader.hpp" // no python - -/* - * Python wrapping */ +#include +#include +#include -using namespace ocl; - -namespace bp = boost::python; +#include "bbox.hpp" // no python +#include "ccpoint.hpp" // no python +#include "clpoint.hpp" // no python +#include "ellipse.hpp" // no python +#include "ellipseposition.hpp" +#include "path_py.hpp" // new-style wrapper +#include "point.hpp" // contains no python-specific code +#include "stlreader.hpp" // no python +#include "stlsurf_py.hpp" // new-style wrapper +#include "triangle_py.hpp" // new-style python wrapper-class +namespace py = pybind11; +using namespace ocl; -void export_geometry() { - bp::class_("Point") - .def(bp::init()) - .def(bp::init()) - .def(bp::init()) - .def(bp::other() * bp::self) - .def(bp::self * bp::other()) - .def(bp::self -= bp::other()) - .def(bp::self - bp::other()) - .def(bp::self += bp::other()) - .def(bp::self + bp::other()) +void export_geometry(py::module_& m) { + py::class_(m, "Point") + .def(py::init()) + .def(py::init()) + .def(py::init()) + .def(py::self * double()) + .def(double() * py::self) + .def(py::self - py::self) + .def(py::self -= py::self) + .def(py::self + py::self) + .def(py::self += py::self) .def("norm", &Point::norm) .def("xyNorm", &Point::xyNorm) .def("normalize", &Point::normalize) @@ -60,66 +56,70 @@ void export_geometry() { .def("yRotate", &Point::yRotate) .def("zRotate", &Point::zRotate) .def("isRight", &Point::isRight) - //.def("isInside", &Point::isInside) - //.def("isInsidePoints", &Point::isInside) + // .def("isInside", &Point::isInside) + // .def("isInsidePoints", &Point::isInside) .def("xyDistance", &Point::xyDistance) .def("__str__", &Point::str) .def_readwrite("x", &Point::x) .def_readwrite("y", &Point::y) - .def_readwrite("z", &Point::z) - ; - bp::class_("CLPoint") // FIXME: should inherit from Point - .def(bp::init()) - .def(bp::init()) - .def(bp::init()) + .def_readwrite("z", &Point::z); + + py::class_(m, "CLPoint") // FIXME: should inherit from Point + .def(py::init()) + .def(py::init()) + .def(py::init()) .def("__str__", &CLPoint::str) .def_readwrite("x", &CLPoint::x) .def_readwrite("y", &CLPoint::y) .def_readwrite("z", &CLPoint::z) .def("cc", &CLPoint::getCC) - .def("getCC", &CLPoint::getCC) - ; - bp::class_("CCPoint") // FIXME: CCPoint should inherit from Point - .def(bp::init()) - .def(bp::init()) + .def("getCC", &CLPoint::getCC); + + py::class_(m, "CCPoint") // FIXME: CCPoint should inherit from Point + .def(py::init()) + .def(py::init()) .def("__str__", &CCPoint::str) .def_readwrite("type", &CCPoint::type) .def_readwrite("x", &CCPoint::x) .def_readwrite("y", &CCPoint::y) - .def_readwrite("z", &CCPoint::z) - ; - bp::enum_("CCType") + .def_readwrite("z", &CCPoint::z); + + py::enum_(m, "CCType") .value("NONE", NONE) - .value("VERTEX",VERTEX) - .value("VERTEX_CYL",VERTEX_CYL) - .value("EDGE",EDGE) - .value("EDGE_SHAFT",EDGE_SHAFT) - .value("EDGE_HORIZ",EDGE_HORIZ) - .value("EDGE_CYL",EDGE_CYL) - .value("EDGE_BALL",EDGE_BALL) - .value("EDGE_CONE",EDGE_CONE) - .value("EDGE_CONE_BASE",EDGE_CONE_BASE) - .value("EDGE_HORIZ_CYL",EDGE_HORIZ_CYL) - .value("EDGE_HORIZ_TOR",EDGE_HORIZ_TOR) - .value("EDGE_POS",EDGE_POS) - .value("EDGE_NEG",EDGE_NEG) + .value("VERTEX", VERTEX) + .value("VERTEX_CYL", VERTEX_CYL) + .value("EDGE", EDGE) + .value("EDGE_SHAFT", EDGE_SHAFT) + .value("EDGE_HORIZ", EDGE_HORIZ) + .value("EDGE_CYL", EDGE_CYL) + .value("EDGE_BALL", EDGE_BALL) + .value("EDGE_CONE", EDGE_CONE) + .value("EDGE_CONE_BASE", EDGE_CONE_BASE) + .value("EDGE_HORIZ_CYL", EDGE_HORIZ_CYL) + .value("EDGE_HORIZ_TOR", EDGE_HORIZ_TOR) + .value("EDGE_POS", EDGE_POS) + .value("EDGE_NEG", EDGE_NEG) .value("FACET", FACET) .value("FACET_TIP", FACET_TIP) .value("FACET_CYL", FACET_CYL) .value("ERROR", ERROR) - ; - bp::class_("Triangle_base") // needed by Triangle_py as a base-class - ; - bp::class_ >("Triangle") - .def(bp::init()) + .export_values(); + + // Base class for Triangle_py + py::class_(m, "Triangle_base"); + + py::class_(m, "Triangle") + .def(py::init()) .def("getPoints", &Triangle_py::getPoints) - .def("__str__", &Triangle_py::str) + .def("__str__", &Triangle_py::str) .def_readonly("p", &Triangle_py::p) - .def_readonly("n", &Triangle_py::n) - ; - bp::class_("STLSurf_base") // needed by STLSurf_py below - ; - bp::class_ >("STLSurf") + .def_readonly("n", &Triangle_py::n); + + // Base class for STLSurf_py + py::class_(m, "STLSurf_base").def(py::init<>()); + + py::class_(m, "STLSurf") + .def(py::init<>()) .def("addTriangle", &STLSurf_py::addTriangle) .def("__str__", &STLSurf_py::str) .def("size", &STLSurf_py::size) @@ -127,57 +127,55 @@ void export_geometry() { .def("getBounds", &STLSurf_py::getBounds) .def("getTriangles", &STLSurf_py::getTriangles) .def_readonly("tris", &STLSurf_py::tris) - .def_readonly("bb", &STLSurf_py::bb) - ; - bp::class_("STLReader") - .def(bp::init()) - ; - bp::class_("Bbox") - .def("isInside", &Bbox::isInside ) + .def_readonly("bb", &STLSurf_py::bb); + + py::class_(m, "STLReader").def(py::init()); + + py::class_(m, "Bbox") + .def("isInside", &Bbox::isInside) .def_readonly("maxpt", &Bbox::maxpt) - .def_readonly("minpt", &Bbox::minpt) - ; - // Epos and the Ellipse are used for the toroidal tool edge-tests - bp::class_("EllipsePosition") + .def_readonly("minpt", &Bbox::minpt); + + // EllipsePosition and Ellipse for toroidal tool edge-tests + py::class_(m, "EllipsePosition") .def_readwrite("s", &EllipsePosition::s) .def_readwrite("t", &EllipsePosition::t) .def("setDiangle", &EllipsePosition::setDiangle) - .def("__str__", &EllipsePosition::str) - ; - bp::class_("Ellipse") - .def(bp::init()) + .def("__str__", &EllipsePosition::str); + + py::class_(m, "Ellipse") + .def(py::init()) .def("ePoint", &Ellipse::ePoint) .def("oePoint", &Ellipse::oePoint) - .def("normal", &Ellipse::normal) - ; - bp::class_("Line") - .def(bp::init()) - .def(bp::init()) + .def("normal", &Ellipse::normal); + + py::class_(m, "Line") + .def(py::init()) + .def(py::init()) .def_readwrite("p1", &Line::p1) - .def_readwrite("p2", &Line::p2) - ; - bp::class_("Arc") - .def(bp::init()) - .def(bp::init()) + .def_readwrite("p2", &Line::p2); + + py::class_(m, "Arc") + .def(py::init()) + .def(py::init()) .def_readwrite("p1", &Arc::p1) .def_readwrite("p2", &Arc::p2) - .def_readwrite("c", &Arc::c) - .def_readwrite("dir", &Arc::dir) - ; - bp::enum_("SpanType") + .def_readwrite("c", &Arc::c) + .def_readwrite("dir", &Arc::dir); + + py::enum_(m, "SpanType") .value("LineSpanType", LineSpanType) .value("ArcSpanType", ArcSpanType) - .export_values() - ; - bp::class_("Path_base") - ; - bp::class_ >("Path") - .def(bp::init<>()) - .def(bp::init()) + .export_values(); + + // Base class for Path_py + py::class_(m, "Path_base"); + + py::class_(m, "Path") + .def(py::init<>()) + .def(py::init()) .def("getSpans", &Path_py::getSpans) .def("getTypeSpanPairs", &Path_py::getTypeSpanPairs) - .def("append",static_cast< void (Path_py::*)(const Line &l)>(&Path_py::append)) - .def("append",static_cast< void (Path_py::*)(const Arc &a)>(&Path_py::append)) - ; + .def("append", (void(Path_py::*)(const Line&)) & Path_py::append) + .def("append", (void(Path_py::*)(const Arc&)) & Path_py::append); } - diff --git a/src/pythonlib/path_py.hpp b/src/pythonlib/path_py.hpp index c8ff0cda..51ff28ae 100644 --- a/src/pythonlib/path_py.hpp +++ b/src/pythonlib/path_py.hpp @@ -1,80 +1,72 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef PATH_PY_H #define PATH_PY_H -#include - -#include -#include +#include #include "path.hpp" - - -namespace ocl -{ +namespace ocl { +namespace py = pybind11; /// Python wrapper for Path class Path_py : public Path { - public: - Path_py() : Path () {}; - /// copy constructor - Path_py(const Path &p) : Path(p) {}; - - /// return the span-list to python - boost::python::list getSpans() { - boost::python::list slist; - BOOST_FOREACH(Span* span, span_list) { - if(span->type() == LineSpanType)slist.append(((LineSpan*)span)->line); - else if(span->type() == ArcSpanType)slist.append(((ArcSpan*)span)->arc); - } - return slist; - }; +public: + Path_py() : Path() {} + /// copy constructor + Path_py(const Path& p) : Path(p) {} + + /// return the span-list to python + py::list getSpans() { + py::list slist; + for (auto span : span_list) { + if (span->type() == LineSpanType) + slist.append(static_cast(span)->line); + else if (span->type() == ArcSpanType) + slist.append(static_cast(span)->arc); + } + return slist; + } - /// return a list of type/span pairs - boost::python::list getTypeSpanPairs() { - boost::python::list slist; - BOOST_FOREACH(Span* span, span_list) { - if(span->type() == LineSpanType) - { - boost::python::list tuple; - tuple.append(span->type()); - tuple.append(((LineSpan*)span)->line); - slist.append(tuple); - } - else if(span->type() == ArcSpanType) - { - boost::python::list tuple; - tuple.append(span->type()); - tuple.append(((ArcSpan*)span)->arc); - slist.append(tuple); - } + /// return a list of type/span pairs + py::list getTypeSpanPairs() { + py::list slist; + for (auto span : span_list) { + if (span->type() == LineSpanType) { + py::list tuple; + tuple.append(span->type()); + tuple.append(static_cast(span)->line); + slist.append(tuple); + } else if (span->type() == ArcSpanType) { + py::list tuple; + tuple.append(span->type()); + tuple.append(static_cast(span)->arc); + slist.append(tuple); } - return slist; - }; - - + } + return slist; + } }; -} // end namespace -#endif -// end file path.h +} // namespace ocl + +#endif // PATH_PY_H diff --git a/src/pythonlib/pathdropcutter_py.hpp b/src/pythonlib/pathdropcutter_py.hpp index 915a77f3..37da85fb 100644 --- a/src/pythonlib/pathdropcutter_py.hpp +++ b/src/pythonlib/pathdropcutter_py.hpp @@ -1,49 +1,50 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ - + */ #ifndef PATHDROPCUTTER_PY_H #define PATHDROPCUTTER_PY_H -#include -#include +#include +#include #include "pathdropcutter.hpp" -namespace ocl -{ +namespace py = pybind11; + +namespace ocl { -/// Python wrapper for PathDropCutter +// Python wrapper for PathDropCutter class PathDropCutter_py : public PathDropCutter { - public: - PathDropCutter_py() : PathDropCutter() {}; - /// return a list of CL-points to python - boost::python::list getCLPoints_py() { - boost::python::list plist; - BOOST_FOREACH(CLPoint p, clpoints) { - plist.append(p); - } - return plist; - }; +public: + PathDropCutter_py() : PathDropCutter() {} + + // return a list of CL-points to python + py::list getCLPoints_py() { + pybind11::list plist; + for (const auto& p : clpoints) { + plist.append(p); + } + return plist; + } }; -} // end namespace -#endif -// end file pathdropcutter_py.h +} // end namespace ocl + +#endif // PATHDROPCUTTER_PY_H diff --git a/src/pythonlib/pythonlib.cmake b/src/pythonlib/pythonlib.cmake index 5b5c8c74..a2f09b1f 100644 --- a/src/pythonlib/pythonlib.cmake +++ b/src/pythonlib/pythonlib.cmake @@ -5,7 +5,8 @@ if(Python3_FOUND) message(STATUS "Python executable: " ${Python3_EXECUTABLE}) message(STATUS "Python (arch-dependant) module destination: " ${Python3_SITEARCH}) endif() -find_package(Boost COMPONENTS python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR} REQUIRED) + +find_package(pybind11 REQUIRED) # include dirs include_directories(${PROJECT_SOURCE_DIR}/cutters) @@ -16,7 +17,7 @@ include_directories(${PROJECT_SOURCE_DIR}/common) include_directories(${PROJECT_SOURCE_DIR}) # this makes the ocl Python module -Python3_add_library( +pybind11_add_module( ocl MODULE pythonlib/ocl_cutters.cpp @@ -34,8 +35,6 @@ PRIVATE ocl_cutters ocl_geo ocl_algo - Boost::python${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR} - Python3::Module ) if(USE_OPENMP) diff --git a/src/pythonlib/stlsurf_py.hpp b/src/pythonlib/stlsurf_py.hpp index 9b74aa0d..f561e705 100644 --- a/src/pythonlib/stlsurf_py.hpp +++ b/src/pythonlib/stlsurf_py.hpp @@ -1,68 +1,63 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef STLSURF_PY_H #define STLSURF_PY_H -#include -#include +#include +#include +#include #include "stlsurf.hpp" +#include "triangle_py.hpp" + +namespace ocl { -namespace ocl -{ - /// STLSurf python wrapper class STLSurf_py : public STLSurf { - public: - /// default constructor - STLSurf_py() : STLSurf() {}; - /// return list of all triangles to python - boost::python::list getTriangles() const { - boost::python::list tlist; - BOOST_FOREACH(Triangle t, tris) { - tlist.append(Triangle_py(t)); - } - return tlist; - }; - - /// return bounds in a list to python - boost::python::list getBounds() const { - boost::python::list bounds; - bounds.append( bb.minpt.x ); - bounds.append( bb.maxpt.x ); - bounds.append( bb.minpt.y ); - bounds.append( bb.maxpt.y ); - bounds.append( bb.minpt.z ); - bounds.append( bb.maxpt.z ); - return bounds; - }; - - /// string output - std::string str() const { - std::ostringstream o; - o << *this; - return o.str(); - }; +public: + /// default constructor + STLSurf_py() : STLSurf() {} + + /// return list of all triangles to python + std::vector getTriangles() const { + std::vector tlist; + for (const auto& t : tris) { + tlist.push_back(Triangle_py(t)); + } + return tlist; + } + + /// return bounds in a list to python + std::vector getBounds() const { + return {bb.minpt.x, bb.maxpt.x, bb.minpt.y, bb.maxpt.y, bb.minpt.z, bb.maxpt.z}; + } + + /// string output + std::string str() const { + std::ostringstream o; + o << *this; + return o.str(); + } }; -} // end namespace -#endif -// end file stlsurf_py.h +} // end namespace ocl + +#endif // STLSURF_PY_H diff --git a/src/pythonlib/triangle_py.hpp b/src/pythonlib/triangle_py.hpp index 1ba28f93..c09bdc2a 100644 --- a/src/pythonlib/triangle_py.hpp +++ b/src/pythonlib/triangle_py.hpp @@ -1,70 +1,68 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef TRIANGLE_PY_H #define TRIANGLE_PY_H -#include +#include -#include -#include +#include #include "triangle.hpp" -namespace ocl -{ +namespace py = pybind11; + +namespace ocl { -/// /// \brief python wrapper for Triangle -/// class Triangle_py : public Triangle { - public: - /// default constructor - Triangle_py() : Triangle() {}; - /// construct from three points - Triangle_py( const Point& p0, - const Point& p1, - const Point& p2) : Triangle(p0,p1,p2) {}; - /// copy constructor - Triangle_py( const Triangle_py& t) : Triangle(t) {}; - /// cast-down constructor - Triangle_py( const Triangle& t) : Triangle(t) {}; - - /// string repr - std::string str() const { - std::ostringstream o; - o << *this; - return o.str(); - }; - - /// Returns a list of the vertices to Python - boost::python::list getPoints() const { - boost::python::list plist; - BOOST_FOREACH(Point vertex, p) { - plist.append(vertex); - } - return plist; - }; - +public: + // Default constructor + Triangle_py() : Triangle() {} + + // Construct from three points + Triangle_py(const Point& p0, const Point& p1, const Point& p2) : Triangle(p0, p1, p2) {} + + // Copy constructor + Triangle_py(const Triangle_py& t) : Triangle(t) {} + + // Cast-down constructor + Triangle_py(const Triangle& t) : Triangle(t) {} + + // String representation + std::string str() const { + std::ostringstream o; + o << *this; + return o.str(); + } + + // Returns a list of the vertices to Python + py::list getPoints() const { + py::list plist; + for (const auto& vertex : p) { + plist.append(vertex); + } + return plist; + } }; -} // end namespace -#endif -// end file triangle_py.h +} // namespace ocl + +#endif // TRIANGLE_PY_H diff --git a/src/pythonlib/waterline_py.hpp b/src/pythonlib/waterline_py.hpp index 0e679429..36c1539d 100644 --- a/src/pythonlib/waterline_py.hpp +++ b/src/pythonlib/waterline_py.hpp @@ -1,77 +1,77 @@ /* $Id$ - * + * * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ - + */ #ifndef WATERLINE_PY_H #define WATERLINE_PY_H -#include -#include +#include +#include + +#include +#include "fiber_py.hpp" #include "waterline.hpp" -namespace ocl -{ +namespace py = pybind11; + +namespace ocl { /// Python wrapper for Waterline class Waterline_py : public Waterline { - public: - Waterline_py() : Waterline() {} - ~Waterline_py() { - std::cout << "~Waterline_py()\n"; - } - /// return loop as a list of lists to python - boost::python::list py_getLoops() const { - boost::python::list loop_list; - BOOST_FOREACH( std::vector loop, this->loops ) { - boost::python::list point_list; - BOOST_FOREACH( Point p, loop ) { - point_list.append( p ); - } - loop_list.append(point_list); +public: + Waterline_py() : Waterline() {} + ~Waterline_py() { std::cout << "~Waterline_py()\n"; } + /// return loop as a list of lists to Python + py::list py_getLoops() const { + py::list loop_list; + for (const auto& loop : this->loops) { + py::list point_list; + for (const auto& p : loop) { + point_list.append(p); } - return loop_list; + loop_list.append(point_list); } - /// return a list of yfibers to python - boost::python::list py_getXFibers() const { - boost::python::list flist; - std::vector xfibers = *( subOp[0]->getFibers() ); - BOOST_FOREACH( Fiber f, xfibers ) { - Fiber_py f2(f); - flist.append(f2); - } - return flist; + return loop_list; + } + /// return a list of xfibers to Python + py::list py_getXFibers() const { + py::list flist; + const std::vector& xfibers = *(subOp[0]->getFibers()); + for (const auto& f : xfibers) { + Fiber_py f2(f); + flist.append(f2); } - /// return a list of yfibers to python - boost::python::list py_getYFibers() const { - boost::python::list flist; - std::vector yfibers = *( subOp[1]->getFibers() ); - BOOST_FOREACH( Fiber f, yfibers ) { - Fiber_py f2(f); - flist.append(f2); - } - return flist; + return flist; + } + /// return a list of yfibers to Python + py::list py_getYFibers() const { + py::list flist; + const std::vector& yfibers = *(subOp[1]->getFibers()); + for (const auto& f : yfibers) { + Fiber_py f2(f); + flist.append(f2); } - + return flist; + } }; -} // end namespace +} // end namespace ocl -#endif +#endif // WATERLINE_PY_H diff --git a/src/pythonlib/weave_py.h b/src/pythonlib/weave_py.h deleted file mode 100644 index 75999c38..00000000 --- a/src/pythonlib/weave_py.h +++ /dev/null @@ -1,102 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . -*/ -#ifndef WEAVE_PY_H -#define WEAVE_PY_H - -#include // for py -#include // for py - -#include "weave.h" - -namespace ocl -{ - -/// Python wrapper for Weave -class Weave_py : public Weave { - public: - Weave_py() : Weave() {}; - // PYTHON - /// return graph components to python - boost::python::list get_components() { - boost::python::list wlist; - std::vector weaves = split_components(); - BOOST_FOREACH( Weave w, weaves ) { - wlist.append( w ); - } - return wlist; - }; - /// return CL-points to python - boost::python::list getCLPoints() const { - boost::python::list plist; - VertexIterator it_begin, it_end, itr; - boost::tie( it_begin, it_end ) = boost::vertices( g ); - for ( itr=it_begin ; itr != it_end ; ++itr ) { - if ( g[*itr].type == CL ) - plist.append( g[*itr].position ); - } - return plist; - }; - /// return internal points to python - boost::python::list getIPoints() const { - boost::python::list plist; - VertexIterator it_begin, it_end, itr; - boost::tie( it_begin, it_end ) = boost::vertices( g ); - for ( itr=it_begin ; itr != it_end ; ++itr ) { - if ( g[*itr].type == INT ) - plist.append( g[*itr].position ); - } - return plist; - }; - /// return edges to python - /// format is [ [p1,p2] , [p3,p4] , ... ] - boost::python::list getEdges() const { - boost::python::list edge_list; - EdgeIterator it_begin, it_end, itr; - boost::tie( it_begin, it_end ) = boost::edges( g ); - for ( itr=it_begin ; itr != it_end ; ++itr ) { // loop through each edge - if ( ! boost::get( boost::edge_color, g, *itr ) ) { - boost::python::list point_list; // the endpoints of each edge - WeaveVertex v1 = boost::source( *itr, g ); - WeaveVertex v2 = boost::target( *itr, g ); - point_list.append(g[v1].position); - point_list.append(g[v2].position); - edge_list.append(point_list); - } - } - return edge_list; - }; - /// return loops to python - boost::python::list py_getLoops() const { - boost::python::list loop_list; - BOOST_FOREACH( std::vector loop, loops ) { - boost::python::list point_list; - BOOST_FOREACH( WeaveVertex v, loop ) { - point_list.append( g[v].position ); - } - loop_list.append(point_list); - } - return loop_list; - }; -}; - -} // end namespace -#endif -// end file weave_py.h diff --git a/src/pythonlib/weave_py.hpp b/src/pythonlib/weave_py.hpp index 8480eb7d..7563b425 100644 --- a/src/pythonlib/weave_py.hpp +++ b/src/pythonlib/weave_py.hpp @@ -1,90 +1,87 @@ /* $Id$ - * + * * Copyright (c) 2010-2011 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef WEAVE_PY_H #define WEAVE_PY_H +#include +#include + #include "weave.hpp" -namespace ocl -{ +namespace py = pybind11; +namespace ocl { namespace weave { - -/// \brief python wrapper for VoronoiDiagram -/// + class Weave_py : public Weave { - public: - Weave_py() : Weave() {}; +public: + Weave_py() : Weave() {} - int numVertices() const { - return g.num_vertices(); - }; - boost::python::list getVertices(VertexType t) { - boost::python::list plist; - BOOST_FOREACH( Vertex v, g.vertices() ) { - if ( g[v].type == t ) - plist.append( g[v].position ); - } - return plist; - }; - - /// return CL-points to python - boost::python::list getCLVertices() { - return getVertices( CL ); - }; - /// return internal points to python - boost::python::list getINTVertices() { - return getVertices( INT ); - }; - /// return edges to python - /// format is [ [p1,p2] , [p3,p4] , ... ] - boost::python::list getEdges() { - boost::python::list edge_list; - BOOST_FOREACH(Edge e, g.edges() ) { - boost::python::list point_list; // the endpoints of each edge - Vertex v1 = g.source( e ); - Vertex v2 = g.target( e ); - point_list.append(g[v1].position); - point_list.append(g[v2].position); - edge_list.append(point_list); - } - return edge_list; - }; - /// return loops to python - boost::python::list py_getLoops() { - boost::python::list loop_list; - BOOST_FOREACH( std::vector loop, loops ) { - boost::python::list point_list; - BOOST_FOREACH( Vertex v, loop ) { - point_list.append( g[v].position ); - } - loop_list.append(point_list); - } - return loop_list; - }; + int numVertices() const { return g.num_vertices(); } + py::list getVertices(VertexType t) { + py::list plist; + for (auto v : g.vertices()) { + if (g[v].type == t) + plist.append(g[v].position); + } + return plist; + } + + // return CL-points to python + py::list getCLVertices() { return getVertices(CL); } + + // return internal points to python + py::list getINTVertices() { return getVertices(INT); } + + // return edges to python + // format is [ [p1,p2] , [p3,p4] , ... ] + py::list getEdges() { + py::list edge_list; + for (auto e : g.edges()) { + py::list point_list; + Vertex v1 = g.source(e); + Vertex v2 = g.target(e); + point_list.append(g[v1].position); + point_list.append(g[v2].position); + edge_list.append(point_list); + } + return edge_list; + } + + // return loops to python + py::list getLoops() { + py::list loop_list; + for (const auto& loop : loops) { + py::list point_list; + for (auto v : loop) { + point_list.append(g[v].position); + } + loop_list.append(point_list); + } + return loop_list; + } }; -} // end weave namespace +} // end namespace weave +} // end namespace ocl -} // end ocl namespace -#endif -// end weave_py.h +#endif // WEAVE_PY_H diff --git a/src/pythonlib/zigzag_py.hpp b/src/pythonlib/zigzag_py.hpp index 5825956f..3c78ada4 100644 --- a/src/pythonlib/zigzag_py.hpp +++ b/src/pythonlib/zigzag_py.hpp @@ -22,28 +22,27 @@ #ifndef ZIGZAG_PY_H #define ZIGZAG_PY_H +#include + #include "zigzag.hpp" -#include - -namespace ocl -{ - /// \brief python wrapper for VoronoiDiagram - /// - class ZigZag_py : public ZigZag - { - public: - ZigZag_py() : ZigZag(){}; - - boost::python::list getOutput() const - { - boost::python::list o; - BOOST_FOREACH (Point p, out) - { - o.append(p); - } - return o; + +namespace py = pybind11; + +namespace ocl { +/// Python wrapper for ZigZag +class ZigZag_py : public ZigZag { +public: + ZigZag_py() : ZigZag() {}; + + py::list getOutput() const { + py::list o; + for (const auto& p : out) { + o.append(p); + } + return o; } - }; -} // end ocl namespace -#endif -// end zigzag_py.hpp +}; + +} // namespace ocl + +#endif // ZIGZAG_PY_H From f683608b2d1fa46733cfc01cdd7bf168c34fdf2c Mon Sep 17 00:00:00 2001 From: CalaW Date: Mon, 14 Apr 2025 02:18:22 +0800 Subject: [PATCH 02/26] Simplify ocl_dropcutter. Note: Moved BatchDropCutter::getTrianglesUnderCutter to pure cpp implementation --- pyproject.toml | 2 +- src/dropcutter/batchdropcutter.hpp | 8 ++- src/pythonlib/adaptivepathdropcutter_py.hpp | 42 ----------- src/pythonlib/batchdropcutter_py.hpp | 57 --------------- src/pythonlib/ocl_dropcutter.cpp | 79 ++++++++++----------- src/pythonlib/pathdropcutter_py.hpp | 50 ------------- 6 files changed, 45 insertions(+), 193 deletions(-) delete mode 100644 src/pythonlib/adaptivepathdropcutter_py.hpp delete mode 100644 src/pythonlib/batchdropcutter_py.hpp delete mode 100644 src/pythonlib/pathdropcutter_py.hpp diff --git a/pyproject.toml b/pyproject.toml index 409539c8..667568ec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ documentation = "https://github.com/aewallin/opencamlib" repository = "https://github.com/aewallin/opencamlib" [build-system] -requires = ["scikit-build-core"] +requires = ["scikit-build-core", "pybind11"] build-backend = "scikit_build_core.build" [tool.scikit-build] diff --git a/src/dropcutter/batchdropcutter.hpp b/src/dropcutter/batchdropcutter.hpp index 9db01ce5..fee75c07 100644 --- a/src/dropcutter/batchdropcutter.hpp +++ b/src/dropcutter/batchdropcutter.hpp @@ -60,7 +60,13 @@ class BatchDropCutter : public Operation { std::vector getCLPoints() {return *clpoints;} /// clears the vector of CLPoints void clearCLPoints() {clpoints->clear();} - + + /// Return triangles under cutter, Not for CAM-algorithms, more for visualization and demonstration. + std::list getTrianglesUnderCutter(CLPoint& cl, MillingCutter& cutter) + { + return *root->search_cutter_overlap(&cutter, &cl); + } + protected: /// unoptimized drop-cutter, tests against all triangles of surface void dropCutter1(); diff --git a/src/pythonlib/adaptivepathdropcutter_py.hpp b/src/pythonlib/adaptivepathdropcutter_py.hpp deleted file mode 100644 index 20e2fd7e..00000000 --- a/src/pythonlib/adaptivepathdropcutter_py.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -#ifndef ADAPTIVEPATHDROPCUTTER_PY_H -#define ADAPTIVEPATHDROPCUTTER_PY_H - -#include -#include - -#include "adaptivepathdropcutter.hpp" - -namespace ocl { - -/// Python wrapper for PathDropCutter -class AdaptivePathDropCutter_py : public AdaptivePathDropCutter { -public: - AdaptivePathDropCutter_py() : AdaptivePathDropCutter() {} - virtual ~AdaptivePathDropCutter_py() {} - /// return a list of CL-points to python - std::vector getCLPoints_py() { return clpoints; } // TODO use auto conversion -}; - -} // namespace ocl - -#endif // ADAPTIVEPATHDROPCUTTER_PY_H diff --git a/src/pythonlib/batchdropcutter_py.hpp b/src/pythonlib/batchdropcutter_py.hpp deleted file mode 100644 index 036a03e4..00000000 --- a/src/pythonlib/batchdropcutter_py.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -#ifndef BDC_PY_H -#define BDC_PY_H - -#include -#include - -#include "batchdropcutter.hpp" - -namespace ocl { - -/// Python wrapper for BatchDropCutter using pybind11 -class BatchDropCutter_py : public BatchDropCutter { -public: - BatchDropCutter_py() : BatchDropCutter() {} - - /// Return CL-points to Python as a std::vector (automatically converted to a Python list) - std::vector getCLPoints_py() { - std::vector plist; - for (const auto& p : *clpoints) - plist.push_back(p); - return plist; - } // TODO use auto conversion - - /// Return triangles under cutter to Python. - std::vector getTrianglesUnderCutter(CLPoint& cl, MillingCutter& cutter) { - std::vector trilist; - std::list* triangles_under_cutter = root->search_cutter_overlap(&cutter, &cl); - for (const auto& t : *triangles_under_cutter) - trilist.push_back(t); - delete triangles_under_cutter; - return trilist; - } -}; - -} // end namespace ocl - -#endif // BDC_PY_H diff --git a/src/pythonlib/ocl_dropcutter.cpp b/src/pythonlib/ocl_dropcutter.cpp index c618809c..02c39a13 100644 --- a/src/pythonlib/ocl_dropcutter.cpp +++ b/src/pythonlib/ocl_dropcutter.cpp @@ -20,10 +20,11 @@ */ #include +#include -#include "adaptivepathdropcutter_py.hpp" -#include "batchdropcutter_py.hpp" -#include "pathdropcutter_py.hpp" +#include "adaptivepathdropcutter.hpp" +#include "batchdropcutter.hpp" +#include "pathdropcutter.hpp" /* * Python wrapping of octree and related classes @@ -33,48 +34,42 @@ namespace py = pybind11; using namespace ocl; void export_dropcutter(py::module_& m) { - py::class_(m, "BatchDropCutter_base"); - - py::class_(m, "BatchDropCutter") + py::class_(m, "BatchDropCutter") .def(py::init<>()) - .def("run", &BatchDropCutter_py::run) - .def("getCLPoints", &BatchDropCutter_py::getCLPoints_py) - .def("setSTL", &BatchDropCutter_py::setSTL) - .def("setCutter", &BatchDropCutter_py::setCutter) - .def("setThreads", &BatchDropCutter_py::setThreads) - .def("getThreads", &BatchDropCutter_py::getThreads) - .def("appendPoint", &BatchDropCutter_py::appendPoint) - .def("getTrianglesUnderCutter", &BatchDropCutter_py::getTrianglesUnderCutter) - .def("getCalls", &BatchDropCutter_py::getCalls) - .def("getBucketSize", &BatchDropCutter_py::getBucketSize) - .def("setBucketSize", &BatchDropCutter_py::setBucketSize); - - py::class_(m, "PathDropCutter_base"); + .def("run", &BatchDropCutter::run) + .def("getCLPoints", &BatchDropCutter::getCLPoints) + .def("setSTL", &BatchDropCutter::setSTL) + .def("setCutter", &BatchDropCutter::setCutter) + .def("setThreads", &BatchDropCutter::setThreads) + .def("getThreads", &BatchDropCutter::getThreads) + .def("appendPoint", &BatchDropCutter::appendPoint) + .def("getTrianglesUnderCutter", &BatchDropCutter::getTrianglesUnderCutter) + .def("getCalls", &BatchDropCutter::getCalls) + .def("getBucketSize", &BatchDropCutter::getBucketSize) + .def("setBucketSize", &BatchDropCutter::setBucketSize); - py::class_(m, "PathDropCutter") + py::class_(m, "PathDropCutter") .def(py::init<>()) - .def("run", &PathDropCutter_py::run) - .def("getCLPoints", &PathDropCutter_py::getCLPoints_py) - .def("setCutter", &PathDropCutter_py::setCutter) - .def("setSTL", &PathDropCutter_py::setSTL) - .def("setSampling", &PathDropCutter_py::setSampling) - .def("setPath", &PathDropCutter_py::setPath) - .def("getZ", &PathDropCutter_py::getZ) - .def("setZ", &PathDropCutter_py::setZ); - - py::class_(m, "AdaptivePathDropCutter_base"); + .def("run", &PathDropCutter::run) + .def("getCLPoints", &PathDropCutter::getCLPoints) + .def("setCutter", &PathDropCutter::setCutter) + .def("setSTL", &PathDropCutter::setSTL) + .def("setSampling", &PathDropCutter::setSampling) + .def("setPath", &PathDropCutter::setPath) + .def("getZ", &PathDropCutter::getZ) + .def("setZ", &PathDropCutter::setZ); - py::class_(m, "AdaptivePathDropCutter") + py::class_(m, "AdaptivePathDropCutter") .def(py::init<>()) - .def("run", &AdaptivePathDropCutter_py::run) - .def("getCLPoints", &AdaptivePathDropCutter_py::getCLPoints_py) - .def("setCutter", &AdaptivePathDropCutter_py::setCutter) - .def("setSTL", &AdaptivePathDropCutter_py::setSTL) - .def("setSampling", &AdaptivePathDropCutter_py::setSampling) - .def("setMinSampling", &AdaptivePathDropCutter_py::setMinSampling) - .def("setCosLimit", &AdaptivePathDropCutter_py::setCosLimit) - .def("getSampling", &AdaptivePathDropCutter_py::getSampling) - .def("setPath", &AdaptivePathDropCutter_py::setPath) - .def("getZ", &AdaptivePathDropCutter_py::getZ) - .def("setZ", &AdaptivePathDropCutter_py::setZ); + .def("run", &AdaptivePathDropCutter::run) + .def("getCLPoints", &AdaptivePathDropCutter::getCLPoints) + .def("setCutter", &AdaptivePathDropCutter::setCutter) + .def("setSTL", &AdaptivePathDropCutter::setSTL) + .def("setSampling", &AdaptivePathDropCutter::setSampling) + .def("setMinSampling", &AdaptivePathDropCutter::setMinSampling) + .def("setCosLimit", &AdaptivePathDropCutter::setCosLimit) + .def("getSampling", &AdaptivePathDropCutter::getSampling) + .def("setPath", &AdaptivePathDropCutter::setPath) + .def("getZ", &AdaptivePathDropCutter::getZ) + .def("setZ", &AdaptivePathDropCutter::setZ); } diff --git a/src/pythonlib/pathdropcutter_py.hpp b/src/pythonlib/pathdropcutter_py.hpp deleted file mode 100644 index 37da85fb..00000000 --- a/src/pythonlib/pathdropcutter_py.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -#ifndef PATHDROPCUTTER_PY_H -#define PATHDROPCUTTER_PY_H - -#include -#include - -#include "pathdropcutter.hpp" - -namespace py = pybind11; - -namespace ocl { - -// Python wrapper for PathDropCutter -class PathDropCutter_py : public PathDropCutter { -public: - PathDropCutter_py() : PathDropCutter() {} - - // return a list of CL-points to python - py::list getCLPoints_py() { - pybind11::list plist; - for (const auto& p : clpoints) { - plist.append(p); - } - return plist; - } -}; - -} // end namespace ocl - -#endif // PATHDROPCUTTER_PY_H From dded9f1c2536960b28fd7d68148fe9feacd22a90 Mon Sep 17 00:00:00 2001 From: CalaW Date: Tue, 15 Apr 2025 01:25:42 +0800 Subject: [PATCH 03/26] fix pip .so installation --- src/pythonlib/pythonlib.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pythonlib/pythonlib.cmake b/src/pythonlib/pythonlib.cmake index a2f09b1f..66ab714c 100644 --- a/src/pythonlib/pythonlib.cmake +++ b/src/pythonlib/pythonlib.cmake @@ -41,8 +41,10 @@ if(USE_OPENMP) target_link_libraries(ocl PRIVATE OpenMP::OpenMP_CXX) endif() -install(TARGETS ocl LIBRARY DESTINATION "${Python3_SITEARCH}/opencamlib") -if(NOT SKBUILD) +if(SKBUILD) + install(TARGETS ocl LIBRARY DESTINATION "opencamlib") +else() + install(TARGETS ocl LIBRARY DESTINATION "${Python3_SITEARCH}/opencamlib") install( DIRECTORY pythonlib/opencamlib/ DESTINATION "${Python3_SITEARCH}/opencamlib" From 51c42fd44250763d4a02c9ed647b917b13697096 Mon Sep 17 00:00:00 2001 From: CalaW Date: Tue, 15 Apr 2025 21:18:00 +0800 Subject: [PATCH 04/26] Cleanup ocl_geometry python binding --- src/pythonlib/ocl_geometry.cpp | 102 ++++++++++++++++++++------------- src/pythonlib/ostream_str.hpp | 26 +++++++++ src/pythonlib/path_py.hpp | 72 ----------------------- src/pythonlib/pythonlib.cmake | 2 + src/pythonlib/stlsurf_py.hpp | 63 -------------------- src/pythonlib/triangle_py.hpp | 68 ---------------------- 6 files changed, 90 insertions(+), 243 deletions(-) create mode 100644 src/pythonlib/ostream_str.hpp delete mode 100644 src/pythonlib/path_py.hpp delete mode 100644 src/pythonlib/stlsurf_py.hpp delete mode 100644 src/pythonlib/triangle_py.hpp diff --git a/src/pythonlib/ocl_geometry.cpp b/src/pythonlib/ocl_geometry.cpp index 375534bb..5ea85f86 100644 --- a/src/pythonlib/ocl_geometry.cpp +++ b/src/pythonlib/ocl_geometry.cpp @@ -22,16 +22,17 @@ #include #include -#include "bbox.hpp" // no python -#include "ccpoint.hpp" // no python -#include "clpoint.hpp" // no python -#include "ellipse.hpp" // no python +#include "bbox.hpp" +#include "ccpoint.hpp" +#include "clpoint.hpp" +#include "ellipse.hpp" #include "ellipseposition.hpp" -#include "path_py.hpp" // new-style wrapper -#include "point.hpp" // contains no python-specific code -#include "stlreader.hpp" // no python -#include "stlsurf_py.hpp" // new-style wrapper -#include "triangle_py.hpp" // new-style python wrapper-class +#include "ostream_str.hpp" +#include "path.hpp" +#include "point.hpp" +#include "stlreader.hpp" +#include "stlsurf.hpp" +#include "triangle.hpp" namespace py = pybind11; using namespace ocl; @@ -56,10 +57,11 @@ void export_geometry(py::module_& m) { .def("yRotate", &Point::yRotate) .def("zRotate", &Point::zRotate) .def("isRight", &Point::isRight) - // .def("isInside", &Point::isInside) - // .def("isInsidePoints", &Point::isInside) + .def("isInside", py::overload_cast(&Point::isInside, py::const_)) + .def("isInside", + py::overload_cast(&Point::isInside, py::const_)) .def("xyDistance", &Point::xyDistance) - .def("__str__", &Point::str) + .def("__str__", &ostream_str) .def_readwrite("x", &Point::x) .def_readwrite("y", &Point::y) .def_readwrite("z", &Point::z); @@ -105,29 +107,27 @@ void export_geometry(py::module_& m) { .value("ERROR", ERROR) .export_values(); - // Base class for Triangle_py - py::class_(m, "Triangle_base"); - - py::class_(m, "Triangle") + py::class_(m, "Triangle") .def(py::init()) - .def("getPoints", &Triangle_py::getPoints) - .def("__str__", &Triangle_py::str) - .def_readonly("p", &Triangle_py::p) - .def_readonly("n", &Triangle_py::n); - - // Base class for STLSurf_py - py::class_(m, "STLSurf_base").def(py::init<>()); + .def("getPoints", [](const Triangle& t) { return std::to_array(t.p); }) + .def("__str__", &ostream_str) + .def_property_readonly("p", [](const Triangle& t) { return std::to_array(t.p); }) + .def_readonly("n", &Triangle::n); - py::class_(m, "STLSurf") + py::class_(m, "STLSurf") .def(py::init<>()) - .def("addTriangle", &STLSurf_py::addTriangle) - .def("__str__", &STLSurf_py::str) - .def("size", &STLSurf_py::size) - .def("rotate", &STLSurf_py::rotate) - .def("getBounds", &STLSurf_py::getBounds) - .def("getTriangles", &STLSurf_py::getTriangles) - .def_readonly("tris", &STLSurf_py::tris) - .def_readonly("bb", &STLSurf_py::bb); + .def("addTriangle", &STLSurf::addTriangle) + .def("__str__", &ostream_str) + .def("size", &STLSurf::size) + .def("rotate", &STLSurf::rotate) + .def("getBounds", + [](const STLSurf& stl) { + return std::array{stl.bb.minpt.x, stl.bb.maxpt.x, stl.bb.minpt.y, + stl.bb.maxpt.y, stl.bb.minpt.z, stl.bb.maxpt.z}; + }) + .def("getTriangles", [](const STLSurf& stl) { return stl.tris; }) + .def_readonly("tris", &STLSurf::tris) + .def_readonly("bb", &STLSurf::bb); py::class_(m, "STLReader").def(py::init()); @@ -168,14 +168,36 @@ void export_geometry(py::module_& m) { .value("ArcSpanType", ArcSpanType) .export_values(); - // Base class for Path_py - py::class_(m, "Path_base"); - - py::class_(m, "Path") + py::class_(m, "Path") .def(py::init<>()) .def(py::init()) - .def("getSpans", &Path_py::getSpans) - .def("getTypeSpanPairs", &Path_py::getTypeSpanPairs) - .def("append", (void(Path_py::*)(const Line&)) & Path_py::append) - .def("append", (void(Path_py::*)(const Arc&)) & Path_py::append); + .def("getSpans", + [](const Path& p) { + py::list spans; + for (auto span : p.span_list) { + if (span->type() == LineSpanType) + spans.append(static_cast(span)->line); + else if (span->type() == ArcSpanType) + spans.append(static_cast(span)->arc); + } + return spans; + }) + .def("getTypeSpanPairs", + [](const Path& p) { + py::list slist; + for (auto span : p.span_list) { + if (span->type() == LineSpanType) { + auto tuple = + py::make_tuple(span->type(), static_cast(span)->line); + slist.append(tuple); + } else if (span->type() == ArcSpanType) { + auto tuple = + py::make_tuple(span->type(), static_cast(span)->arc); + slist.append(tuple); + } + } + return slist; + }) + .def("append", py::overload_cast(&Path::append)) + .def("append", py::overload_cast(&Path::append)); } diff --git a/src/pythonlib/ostream_str.hpp b/src/pythonlib/ostream_str.hpp new file mode 100644 index 00000000..27eb2a4f --- /dev/null +++ b/src/pythonlib/ostream_str.hpp @@ -0,0 +1,26 @@ +/** + * Converts an object to its string representation using stream insertion. + * + * This function creates a std::ostringstream, inserts the object into the stream, + * and returns the accumulated string. It requires that the type T implements the + * stream insertion operator (<<). Used for pybind11 helper. + * + */ + +#ifndef OCL_OSTREAM_STR_HPP +#define OCL_OSTREAM_STR_HPP + +#include +#include + +namespace ocl { + +template std::string ostream_str(const T& obj) { + std::ostringstream oss; + oss << obj; + return oss.str(); +} + +} // namespace ocl + +#endif // OCL_OSTREAM_STR_HPP diff --git a/src/pythonlib/path_py.hpp b/src/pythonlib/path_py.hpp deleted file mode 100644 index 51ff28ae..00000000 --- a/src/pythonlib/path_py.hpp +++ /dev/null @@ -1,72 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -#ifndef PATH_PY_H -#define PATH_PY_H - -#include - -#include "path.hpp" - -namespace ocl { -namespace py = pybind11; - -/// Python wrapper for Path -class Path_py : public Path { -public: - Path_py() : Path() {} - /// copy constructor - Path_py(const Path& p) : Path(p) {} - - /// return the span-list to python - py::list getSpans() { - py::list slist; - for (auto span : span_list) { - if (span->type() == LineSpanType) - slist.append(static_cast(span)->line); - else if (span->type() == ArcSpanType) - slist.append(static_cast(span)->arc); - } - return slist; - } - - /// return a list of type/span pairs - py::list getTypeSpanPairs() { - py::list slist; - for (auto span : span_list) { - if (span->type() == LineSpanType) { - py::list tuple; - tuple.append(span->type()); - tuple.append(static_cast(span)->line); - slist.append(tuple); - } else if (span->type() == ArcSpanType) { - py::list tuple; - tuple.append(span->type()); - tuple.append(static_cast(span)->arc); - slist.append(tuple); - } - } - return slist; - } -}; - -} // namespace ocl - -#endif // PATH_PY_H diff --git a/src/pythonlib/pythonlib.cmake b/src/pythonlib/pythonlib.cmake index 66ab714c..efffd9e5 100644 --- a/src/pythonlib/pythonlib.cmake +++ b/src/pythonlib/pythonlib.cmake @@ -1,3 +1,5 @@ +set(CMAKE_CXX_STANDARD 20) + find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED) if(Python3_FOUND) message(STATUS "Found Python: " ${Python3_VERSION}) diff --git a/src/pythonlib/stlsurf_py.hpp b/src/pythonlib/stlsurf_py.hpp deleted file mode 100644 index f561e705..00000000 --- a/src/pythonlib/stlsurf_py.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -#ifndef STLSURF_PY_H -#define STLSURF_PY_H - -#include -#include -#include - -#include "stlsurf.hpp" -#include "triangle_py.hpp" - -namespace ocl { - -/// STLSurf python wrapper -class STLSurf_py : public STLSurf { -public: - /// default constructor - STLSurf_py() : STLSurf() {} - - /// return list of all triangles to python - std::vector getTriangles() const { - std::vector tlist; - for (const auto& t : tris) { - tlist.push_back(Triangle_py(t)); - } - return tlist; - } - - /// return bounds in a list to python - std::vector getBounds() const { - return {bb.minpt.x, bb.maxpt.x, bb.minpt.y, bb.maxpt.y, bb.minpt.z, bb.maxpt.z}; - } - - /// string output - std::string str() const { - std::ostringstream o; - o << *this; - return o.str(); - } -}; - -} // end namespace ocl - -#endif // STLSURF_PY_H diff --git a/src/pythonlib/triangle_py.hpp b/src/pythonlib/triangle_py.hpp deleted file mode 100644 index c09bdc2a..00000000 --- a/src/pythonlib/triangle_py.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -#ifndef TRIANGLE_PY_H -#define TRIANGLE_PY_H - -#include - -#include - -#include "triangle.hpp" - -namespace py = pybind11; - -namespace ocl { - -/// \brief python wrapper for Triangle -class Triangle_py : public Triangle { -public: - // Default constructor - Triangle_py() : Triangle() {} - - // Construct from three points - Triangle_py(const Point& p0, const Point& p1, const Point& p2) : Triangle(p0, p1, p2) {} - - // Copy constructor - Triangle_py(const Triangle_py& t) : Triangle(t) {} - - // Cast-down constructor - Triangle_py(const Triangle& t) : Triangle(t) {} - - // String representation - std::string str() const { - std::ostringstream o; - o << *this; - return o.str(); - } - - // Returns a list of the vertices to Python - py::list getPoints() const { - py::list plist; - for (const auto& vertex : p) { - plist.append(vertex); - } - return plist; - } -}; - -} // namespace ocl - -#endif // TRIANGLE_PY_H From 98862f6585e9535c58bbe02b83fc8bd1bc47be07 Mon Sep 17 00:00:00 2001 From: CalaW Date: Wed, 16 Apr 2025 01:54:06 +0800 Subject: [PATCH 05/26] Fix macos test, default to arm64 if not specified in install.sh args. --- .github/workflows/test.yml | 14 +++++++++----- install.sh | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7273375a..aa0fe1fe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,6 +38,10 @@ jobs: if [ "${{ matrix.os_short }}" == "linux" ]; then export OCL_SUDO_INSTALL="1" fi + if [ "${{ matrix.os_short }}" == "macos" ]; then + export OCL_SUDO_INSTALL="1" + export OCL_MACOS_ARCHITECTURE="$(arch)" + fi ./install.sh \ --install-ci-deps \ --build-library cxx \ @@ -57,13 +61,10 @@ jobs: include: - os: "windows-2022" os_short: "windows" - libdir: windows-nodejs-x64 - os: "macos-15" os_short: "macos" - libdir: macos-nodejs-x64 - os: "ubuntu-22.04" os_short: "linux" - libdir: linux-nodejs-x64 steps: - uses: actions/checkout@v3 with: @@ -74,15 +75,17 @@ jobs: if [ "${{ matrix.os_short }}" == "linux" ]; then export OCL_SUDO_INSTALL="1" fi + if [ "${{ matrix.os_short }}" == "macos" ]; then + export OCL_MACOS_ARCHITECTURE="$(arch)" + fi ./install.sh \ --install-ci-deps \ --build-library nodejs \ --build-type release \ - --node-architecture x64 \ + --node-architecture $(node -p "require('os').arch()") \ --install-boost \ --boost-prefix $(pwd) \ --install \ - --install-prefix $(pwd)/src/npmpackage/build/Release/${{ matrix.libdir }} \ --test python: name: ${{ matrix.os_short }} python @@ -99,6 +102,7 @@ jobs: - os: "macos-15" os_short: "macos" python_version: "3.11" + cmake_generator: "Unix Makefiles" - os: "ubuntu-22.04" os_short: "linux" python_version: "3.10" diff --git a/install.sh b/install.sh index 6707fb76..556f703a 100755 --- a/install.sh +++ b/install.sh @@ -37,7 +37,7 @@ Options: --platform Set the platform, for when auto-detection doesn't work (one of: windows, macos, linux) - --macos-architecture Set the macOS architecture to compile for (one of: arm64, x86_64), useful for cross compiling. + --macos-architecture Set the macOS architecture to compile for (one of: arm64, x86_64), useful for cross compiling. Default is arm64. --docker-image Set the docker image to forward this install command to, useful for cross compiling --docker-before-install Run given commands in the docker container before running ./install.sh, (only valid when using --docker-image) --cmake-generator Set the CMake Generator option @@ -241,6 +241,7 @@ install_ci_dependencies() { ${maybe_sudo} yum install curl fi elif [ "${determined_os}" = "macos" ]; then + OCL_MACOS_ARCHITECTURE="${OCL_MACOS_ARCHITECTURE:-arm64}" # default to arm64 prettyprint "Downloading libomp for: " "${OCL_MACOS_ARCHITECTURE}" if [ "${OCL_MACOS_ARCHITECTURE}" = "arm64" ]; then libomp_tar_loc=$(brew fetch --bottle-tag=arm64_sonoma libomp | grep -i downloaded | grep tar.gz | cut -f2 -d ":" | xargs echo) From 362969a882605cc242364a5f1b972434ac361528 Mon Sep 17 00:00:00 2001 From: CalaW Date: Wed, 16 Apr 2025 02:17:46 +0800 Subject: [PATCH 06/26] cleanup install script, remove boost-python --- .github/workflows/test.yml | 6 +-- install.sh | 108 +++---------------------------------- 2 files changed, 9 insertions(+), 105 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index aa0fe1fe..f531fbe4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -98,14 +98,11 @@ jobs: include: - os: "windows-2022" os_short: "windows" - python_version: "3.10" - os: "macos-15" os_short: "macos" - python_version: "3.11" cmake_generator: "Unix Makefiles" - os: "ubuntu-22.04" os_short: "linux" - python_version: "3.10" cmake_generator: "Unix Makefiles" steps: - uses: actions/checkout@v3 @@ -113,13 +110,12 @@ jobs: fetch-depth: 0 - uses: actions/setup-python@v4 with: - python-version: ${{ matrix.python_version }} + python-version: "3.13" - name: Install shell: bash run: | if [ "${{ matrix.os_short }}" == "linux" ]; then export OCL_INSTALL_BOOST="1" - export OCL_BOOST_WITH_PYTHON="1" export OCL_BOOST_PREFIX="$(pwd)" else export OCL_INSTALL_BOOST_FROM_REPO="1" diff --git a/install.sh b/install.sh index 556f703a..e4a77b1e 100755 --- a/install.sh +++ b/install.sh @@ -26,10 +26,6 @@ Options: --install-prefix Set the install prefix location for CMake installs (only valid when using --install) --boost-prefix Set a custom path where to look for Boost - --boost-with-python Compile Boost.Python (only valid when using --install-boost) - --boost-address-model Set the address model for Boost (one of: 32, 64) (only valid when using --install-boost and --boost-with-python) - --boost-architecture Set the architecture for Boost (one of: x86, ia64, sparc, power, loongarch, mips, mips1, mips2, mips3, mips4, mips32, mips32r2, mips64, parisc, arm, riscv, s390x, arm+x86) (only valid when using --install-boost and --boost-with-python) - --boost-python-version Set the python version to look for when compiling Boost (only valid when using --install-boost and --boost-with-python) --python-executable Set a custom path (or name of) the Python executable (only valid when using --build-library python) --python-prefix Set the python prefix, this will be passed to CMake as Python3_ROOT_DIR, to make sure CMake is using the correct Python installation. (only valid when using --build-library python) @@ -67,10 +63,6 @@ while [[ "$#" -gt 0 ]]; do --install-boost) OCL_INSTALL_BOOST="1"; ;; --install-boost-from-repo) OCL_INSTALL_BOOST_FROM_REPO="1"; ;; --boost-prefix) OCL_BOOST_PREFIX="$2"; shift ;; - --boost-address-model) OCL_BOOST_ADDRESS_MODEL="$2"; shift ;; - --boost-architecture) OCL_BOOST_ARCHITECTURE="$2"; shift ;; - --boost-with-python) OCL_BOOST_WITH_PYTHON="1"; ;; - --boost-python-version) OCL_BOOST_PYTHON_VERSION="$2"; shift ;; --macos-architecture) OCL_MACOS_ARCHITECTURE="$2"; shift ;; --docker-image) OCL_DOCKER_IMAGE="$2"; shift ;; --docker-before-install) OCL_DOCKER_IMAGE_BEFORE_INSTALL="$2"; shift ;; @@ -104,16 +96,6 @@ verify_args() { exit 1 elif [ -n "${OCL_INSTALL_PREFIX}" ] && [ -z "${OCL_INSTALL}" ] && [ -z "${OCL_SUDO_INSTALL}" ]; then echo "WARN: Settings --install-prefix without setting --install or --sudo-install. add --install or --sudo-install option or remove the --install-prefix option" - elif [ -n "${OCL_BOOST_WITH_PYTHON}" ] && [ -z "${OCL_INSTALL_BOOST}" ]; then - echo "WARN: Setting --boost-with-python without setting --install-boost. add --install-boost or remove the --boost-with-python option" - elif [ -n "${OCL_BOOST_WITH_PYTHON}" ] && [ -z "${OCL_BOOST_ARCHITECTURE}" ]; then - echo "WARN: Setting --boost-with-python without setting --boost-architecture. add --boost-architecture or remove the --boost-with-python option" - elif [ -n "${OCL_BOOST_ADDRESS_MODEL}" ] && [ -z "${OCL_INSTALL_BOOST}" ]; then - echo "WARN: Setting --boost-address-model without setting --install-boost. add --install-boost or remove the --boost-address-model option" - elif [ -n "${OCL_BOOST_ARCHITECTURE}" ] && [ -z "${OCL_INSTALL_BOOST}" ]; then - echo "WARN: Setting --boost-architecture without setting --install-boost. add --install-boost or remove the --boost-address-model option" - elif [ -n "${OCL_BOOST_PYTHON_VERSION}" ] && [ -z "${OCL_INSTALL_BOOST}" ]; then - echo "WARN: Setting --boost-python-version without setting --install-boost. add --install-boost or remove the --boost-python-version option" fi } verify_args @@ -179,9 +161,6 @@ install_system_dependencies() { if [ -z "${OCL_PYTHON_EXECUTABLE}" ]; then sudo apt install -y --no-install-recommends python3 fi - if [ -n "${OCL_INSTALL_BOOST_FROM_REPO}" ]; then - sudo apt install -y --no-install-recommends libboost-python-dev - fi fi if [ "${OCL_BUILD_LIBRARY}" = "nodejs" ]; then sudo apt install -y --no-install-recommends nodejs npm @@ -193,10 +172,7 @@ install_system_dependencies() { fi if [ "${OCL_BUILD_LIBRARY}" = "python" ]; then if [ -z "${OCL_PYTHON_EXECUTABLE}" ]; then - brew install python@3.11 - fi - if [ -n "${OCL_INSTALL_BOOST_FROM_REPO}" ]; then - brew install boost-python3 + brew install python fi fi if [ "${OCL_BUILD_LIBRARY}" = "nodejs" ]; then @@ -258,8 +234,12 @@ install_ci_dependencies() { fi } -download_boost() { - if [ ! -f "${TMPDIR:-"/tmp"}/boost.tar.gz" ]; then +install_boost() { + cd "${project_dir}" + if [ -d "${boost_dir}" ]; then + # boost folder already exists, re-using + prettyprint "Boost already found, re-using..." + elif [ ! -f "${TMPDIR:-"/tmp"}/boost.tar.gz" ]; then prettyprint "Downloading boost.tar.gz" curl "${boost_url}" --output "${TMPDIR:-"/tmp"}/boost.tar.gz" --silent --location else @@ -269,78 +249,6 @@ download_boost() { tar -zxf "${TMPDIR:-"/tmp"}/boost.tar.gz" -C . } -compile_boost_python() { - boost_variant="${build_type_lower}" - cd "${project_dir}/${boost_dir}" - if [ -n "${OCL_BOOST_WITH_PYTHON}" ]; then - if [ -n "${OCL_PYTHON_EXECUTABLE}" ]; then - python_version=$(${OCL_PYTHON_EXECUTABLE} -c 'import sys; version=sys.version_info[:3]; print("{0}.{1}".format(*version))') - python_include_dir=$(${OCL_PYTHON_EXECUTABLE} -c 'from sysconfig import get_paths as gp; print(gp()["include"])') - if [ "${determined_os}" = "windows" ]; then - python_include_dir=$(cygpath -w "${python_include_dir}") - fi - echo "using python : ${python_version} : ${OCL_PYTHON_EXECUTABLE//\\/\\\\} : ${python_include_dir//\\/\\\\} ;" > user-config.jam - elif [ -n "${OCL_BOOST_PYTHON_VERSION}" ]; then - echo "using python : ${OCL_BOOST_PYTHON_VERSION} ;" > user-config.jam - else - echo "using python ;" > user-config.jam - fi - cat user-config.jam - prettyprint "Bootstrapping boost" - if [ "${determined_os}" = "windows" ]; then - ./bootstrap.bat - else - ./bootstrap.sh - fi - prettyprint "Compiling boost " "${OCL_BOOST_ADDRESS_MODEL:-"64"}-bit ${OCL_BOOST_ARCHITECTURE}" - ./b2 \ - ${OCL_CLEAN:+"-a"} \ - -j2 \ - --layout="system" \ - --with-python \ - --user-config="user-config.jam" \ - threading="multi" \ - variant="${boost_variant}" \ - link="static" \ - cxxflags="-fPIC" \ - address-model="${OCL_BOOST_ADDRESS_MODEL:-"64"}" \ - ${OCL_BOOST_ARCHITECTURE:+"architecture=${OCL_BOOST_ARCHITECTURE}"} \ - stage - fi -} - -install_boost () { - cd "${project_dir}" - if [ -d "${boost_dir}" ]; then - # boost folder already exists, re-using - prettyprint "Boost already found, re-using..." - elif [ -f boost-precompiled.tar.gz ]; then - # boost-precompiled.tar.gz found, re-using - prettyprint "Found cached precompiled boost, installing..." - tar -zxf boost-precompiled.tar.gz -C . - elif [ -n "${OCL_BOOST_ARCHITECTURE}" ] && [ -n "${OCL_BOOST_WITH_PYTHON}" ]; then - # got enough information to try and download a pre-compiled boost with python - boost_precompiled_url="https://github.com/vespakoen/boost-python-precompiled/releases/download/1.80.0/boost-python-precompiled-${determined_os}-${OCL_BOOST_ARCHITECTURE}-${OCL_BOOST_ADDRESS_MODEL:-"64"}-bit.tar.gz" - if curl --output /dev/null --silent --head --fail "$boost_precompiled_url"; then - prettyprint "Downloading boost-precompiled.tar.gz for ${OCL_BOOST_ARCHITECTURE} ${OCL_BOOST_ADDRESS_MODEL:-"64"}-bit..." - curl "${boost_precompiled_url}" --output "${TMPDIR:-"/tmp"}/boost-precompiled.tar.gz" --silent --location - prettyprint "Extracting boost-precompiled.tar.gz..." - tar -zxf "${TMPDIR:-"/tmp"}/boost-precompiled.tar.gz" -C . - else - # precompiled boost python not available for given architecture and address model, installing from source - download_boost - if [ -n "${OCL_BOOST_WITH_PYTHON}" ]; then - compile_boost_python - fi - fi - else - download_boost - if [ -n "${OCL_BOOST_WITH_PYTHON}" ]; then - compile_boost_python - fi - fi -} - if [ -n "${OCL_DOCKER_IMAGE}" ]; then prettyprint "Running the docker image with the following environment variables" # collect all the options to check which ones are set and should be forwarded to the container @@ -641,7 +549,7 @@ if [ "${OCL_BUILD_LIBRARY}" = "nodejs" ]; then fi if [ "${OCL_BUILD_LIBRARY}" = "python" ]; then - prettyprint "Building Python library " "${OCL_BOOST_PYTHON_VERSION}" + prettyprint "Building Python library" build_pythonlib if [ -n "${OCL_TEST}" ]; then prettyprint "Testing Python library" From 21022dcb1411fb6f95cc03f50d4ceff2d7034c6b Mon Sep 17 00:00:00 2001 From: CalaW Date: Sat, 19 Apr 2025 02:43:37 +0800 Subject: [PATCH 07/26] Cleanup ocl_algo python binding --- src/algo/batchpushcutter.cpp | 63 ++++++-- src/algo/batchpushcutter.hpp | 7 +- src/algo/clsurface.hpp | 26 ++-- src/algo/tsp.hpp | 20 +-- src/algo/waterline.hpp | 12 +- src/algo/weave.cpp | 28 +++- src/algo/weave.hpp | 47 +++--- src/algo/zigzag.hpp | 6 +- src/common/halfedgediagram.hpp | 12 +- src/pythonlib/adaptivewaterline_py.hpp | 81 ---------- src/pythonlib/batchpushcutter_py.hpp | 98 ------------ src/pythonlib/fiber_py.hpp | 49 ------ src/pythonlib/lineclfilter_py.hpp | 51 ------- src/pythonlib/ocl_algo.cpp | 197 ++++++++++++------------- src/pythonlib/ocl_cutters.cpp | 3 +- src/pythonlib/waterline_py.hpp | 77 ---------- src/pythonlib/weave_py.hpp | 87 ----------- src/pythonlib/zigzag_py.hpp | 48 ------ 18 files changed, 233 insertions(+), 679 deletions(-) delete mode 100644 src/pythonlib/adaptivewaterline_py.hpp delete mode 100644 src/pythonlib/batchpushcutter_py.hpp delete mode 100644 src/pythonlib/fiber_py.hpp delete mode 100644 src/pythonlib/lineclfilter_py.hpp delete mode 100644 src/pythonlib/waterline_py.hpp delete mode 100644 src/pythonlib/weave_py.hpp delete mode 100644 src/pythonlib/zigzag_py.hpp diff --git a/src/algo/batchpushcutter.cpp b/src/algo/batchpushcutter.cpp index e6b17026..7af5dd06 100644 --- a/src/algo/batchpushcutter.cpp +++ b/src/algo/batchpushcutter.cpp @@ -19,16 +19,14 @@ * along with this program. If not, see . */ -#include - -#ifdef _OPENMP - #include +#ifdef _OPENMP +#include #endif +#include "batchpushcutter.hpp" #include "millingcutter.hpp" #include "point.hpp" #include "triangle.hpp" -#include "batchpushcutter.hpp" namespace ocl { @@ -83,8 +81,8 @@ void BatchPushCutter::pushCutter1() { // std::cout << "BatchPushCutter1 with " << fibers->size() << // " fibers and " << surf->tris.size() << " triangles..." << std::endl; nCalls = 0; - BOOST_FOREACH(Fiber& f, *fibers) { - BOOST_FOREACH( const Triangle& t, surf->tris) {// test against all triangles in s + for (Fiber& f : *fibers) { + for (const Triangle& t : surf->tris) { // test against all triangles in s Interval i; cutter->pushCutter(f,i,t); f.addInterval(i); @@ -102,7 +100,7 @@ void BatchPushCutter::pushCutter2() { // " fibers and " << surf->tris.size() << " triangles..." << std::endl; nCalls = 0; std::list* overlap_triangles; - BOOST_FOREACH(Fiber& f, *fibers) { + for (Fiber& f : *fibers) { CLPoint cl; if (x_direction) { cl.x = 0; @@ -116,8 +114,8 @@ void BatchPushCutter::pushCutter2() { assert(0); } overlap_triangles = root->search_cutter_overlap(cutter, &cl); - assert( overlap_triangles->size() <= surf->size() ); // can't possibly find more triangles than in the STLSurf - BOOST_FOREACH( const Triangle& t, *overlap_triangles) { + assert( overlap_triangles->size() <= surf->size() ); // can't possibly find more triangles than in the STLSurf + for (const Triangle& t : *overlap_triangles) { //if ( bb->overlaps( t.bb ) ) { Interval i; cutter->pushCutter(f,i,t); @@ -187,5 +185,50 @@ void BatchPushCutter::pushCutter3() { return; } +std::vector BatchPushCutter::getCLPoints() { + std::vector clPoints; + clPoints.reserve(2 * fibers->size()); + + for (const auto& f : *fibers) { + for (const auto& i : f.ints) { + if (i.empty()) + continue; + + // Get lower point. + const Point lower = f.point(i.lower); + CLPoint p1(lower.x, lower.y, lower.z); + p1.cc = new CCPoint(i.lower_cc); + clPoints.emplace_back(p1); + + // Get upper point. + const Point upper = f.point(i.upper); + CLPoint p2(upper.x, upper.y, upper.z); + p2.cc = new CCPoint(i.upper_cc); + clPoints.emplace_back(p2); + } + } + return clPoints; +} + +std::list BatchPushCutter::getOverlapTriangles(Fiber& f) { + CLPoint cl; + if (x_direction) { + cl.x = 0; + cl.y = f.p1.y; + cl.z = f.p1.z; + } else if (y_direction) { + cl.x = f.p1.x; + cl.y = 0; + cl.z = f.p1.z; + } else { + assert(false); + } + + std::list* overlapTriangles = root->search_cutter_overlap(cutter, &cl); + std::list ret = *overlapTriangles; + delete overlapTriangles; + return ret; +} + }// end namespace // end file batchpushcutter.cpp diff --git a/src/algo/batchpushcutter.hpp b/src/algo/batchpushcutter.hpp index 943bb0d7..924bf5bf 100644 --- a/src/algo/batchpushcutter.hpp +++ b/src/algo/batchpushcutter.hpp @@ -22,8 +22,6 @@ #ifndef BPC_H #define BPC_H -#include -#include #include #include "point.hpp" @@ -65,6 +63,11 @@ class BatchPushCutter : public Operation { std::vector* getFibers() const {return fibers;} void reset(); + + std::vector getCLPoints(); + + std::list getOverlapTriangles(Fiber& f); + protected: /// 1st version of algorithm void pushCutter1(); diff --git a/src/algo/clsurface.hpp b/src/algo/clsurface.hpp index 6a4a9cfa..069d63e6 100644 --- a/src/algo/clsurface.hpp +++ b/src/algo/clsurface.hpp @@ -22,13 +22,10 @@ #define CLSURFACE_H #include -#include -#include -#include -#include "point.hpp" #include "halfedgediagram.hpp" - +#include "operation.hpp" +#include "point.hpp" namespace ocl { @@ -225,7 +222,7 @@ class CutterLocationSurface : public Operation { CLSEdgeVector f_edges = g.face_edges(f); assert( f_edges.size() == 4 ); CLSVertex center = g.add_vertex(); - BOOST_FOREACH( CLSEdge e, f_edges ) { + for (CLSEdge e : f_edges) { CLSVertex src = g.source(e); CLSVertex trg = g.target(e); // new vertex at mid-point of each edge @@ -238,7 +235,7 @@ class CutterLocationSurface : public Operation { // now loop through edges again: f_edges = g.face_edges(f); assert( f_edges.size() == 8 ); - // BOOST_FOREACH( CLSEdge e, f_edges ) { + // for (CLSEdge e : f_edges) { // std::cout << e << "\n"; // } } @@ -254,26 +251,27 @@ class CutterLocationSurface : public Operation { { std::vector vertices; for (CLSVertex v : g.vertices()) { - vertices.push_back(g[v].position); + vertices.push_back(g[v].position); } return vertices; } - + std::vector> getEdges() { std::vector> edges; for (CLSEdge edge : g.edges()) { - CLSVertex v1 = g.source(edge); - CLSVertex v2 = g.target(edge); - edges.push_back(std::make_pair(g[v1].position, g[v2].position)); + CLSVertex v1 = g.source(edge); + CLSVertex v2 = g.target(edge); + edges.emplace_back(std::make_pair(g[v1].position, g[v2].position)); } return edges; } - + /// string repr std::string str() const { std::ostringstream o; - o << "CutterLocationSurface (nVerts="<< g.num_vertices() << " , nEdges="<< g.num_edges() <<"\n"; + o << "CutterLocationSurface (nVerts=" << g.num_vertices() + << " , nEdges=" << g.num_edges() << "\n"; return o.str(); } diff --git a/src/algo/tsp.hpp b/src/algo/tsp.hpp index 5c1e2b3c..1b6c86be 100644 --- a/src/algo/tsp.hpp +++ b/src/algo/tsp.hpp @@ -21,18 +21,14 @@ #ifndef TSP_H #define TSP_H +#include #include #include -#include -#include -#include #include #include -#include #include - -#include +#include namespace ocl { @@ -119,21 +115,15 @@ class TSPSolver { } void printOutput() const { int n=0; - BOOST_FOREACH( Vertex v, output ) { + for (Vertex v : output) { std::cout << n++ << " : " << v << "\n" ; } } double getLength() const { return length; } - boost::python::list getOutput() const { - boost::python::list plist; - BOOST_FOREACH(Vertex v, output) { - plist.append( v ); - } - return plist; - } - + auto getOutput() const { return output; } + protected: Container output; PointSet points; diff --git a/src/algo/waterline.hpp b/src/algo/waterline.hpp index 912260b7..78bf82af 100644 --- a/src/algo/waterline.hpp +++ b/src/algo/waterline.hpp @@ -22,15 +22,11 @@ #ifndef WATERLINE_H #define WATERLINE_H -#include -#include #include -#include "point.hpp" #include "fiber.hpp" -#include "batchpushcutter.hpp" #include "operation.hpp" - +#include "point.hpp" namespace ocl { @@ -57,9 +53,9 @@ class Waterline : public Operation { virtual void run2(); /// returns a vector< vector< Point > > with the resulting waterline loops - std::vector< std::vector > getLoops() const { - return loops; - } + auto getLoops() const { return loops; } + auto getXFibers() const { return xfibers; } + auto getYFibers() const { return yfibers; } void reset(); protected: diff --git a/src/algo/weave.cpp b/src/algo/weave.cpp index ab41c8a5..42c23c4a 100644 --- a/src/algo/weave.cpp +++ b/src/algo/weave.cpp @@ -115,7 +115,33 @@ std::string Weave::str() { o << " " << yfibers.size() << " Y-fibers\n"; return o.str(); } - + +std::vector Weave::getVertices() const { + std::vector vertices; + for (const auto& v : g.vertices()) { + vertices.emplace_back(g[v].position); + } + return vertices; +} + +std::vector Weave::getVerticesByType(VertexType t) const { + std::vector vertices; + for (const auto& v : g.vertices()) { + if (g[v].type == t) + vertices.emplace_back(g[v].position); + } + return vertices; +} + +std::vector> Weave::getEdges() const { + std::vector> edge_list; + for (const auto& e : g.edges()) { + Vertex v1 = g.source(e); + Vertex v2 = g.target(e); + edge_list.emplace_back(g[v1].position, g[v2].position); + } + return edge_list; +} } // end weave namespace diff --git a/src/algo/weave.hpp b/src/algo/weave.hpp index acf4c740..3902fa20 100644 --- a/src/algo/weave.hpp +++ b/src/algo/weave.hpp @@ -1,39 +1,37 @@ /* $Id$ - * + * * Copyright (c) 2010-2011 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib + * + * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . -*/ + */ #ifndef WEAVE_HPP #define WEAVE_HPP #include - #include "fiber.hpp" #include "weave_typedef.hpp" -#include "halfedgediagram.hpp" namespace ocl { namespace weave { -// Abstract base-class for weave-implementations. build() must be implemented in sub-class! -class Weave { + // Abstract base-class for weave-implementations. build() must be implemented in sub-class! + class Weave { public: Weave() {} virtual ~Weave() {} @@ -46,18 +44,23 @@ class Weave { /// run planar_face_traversal to get the waterline loops void face_traverse(); /// return list of loops - std::vector< std::vector > getLoops() const; + std::vector> getLoops() const; /// string representation - std::string str() ; - void printGraph() ; - - protected: - WeaveGraph g; ///< the weave-graph - std::vector< std::vector > loops; ///< output: list of loops in this weave - std::vector xfibers; ///< the X-fibers - std::vector yfibers; ///< the Y-fibers - std::set clVertexSet; ///< set of CL-points -}; + std::string str(); + void printGraph(); + + int numVertices() const { return g.num_vertices(); } + std::vector getVertices() const; + std::vector getVerticesByType(VertexType t) const; + std::vector> getEdges() const; + + protected: + WeaveGraph g; ///< the weave-graph + std::vector> loops; ///< output: list of loops in this weave + std::vector xfibers; ///< the X-fibers + std::vector yfibers; ///< the Y-fibers + std::set clVertexSet; ///< set of CL-points + }; } // end weave namespace diff --git a/src/algo/zigzag.hpp b/src/algo/zigzag.hpp index 10a87bf7..c63235b6 100644 --- a/src/algo/zigzag.hpp +++ b/src/algo/zigzag.hpp @@ -23,16 +23,18 @@ #define ZIGZAG_H #include +#include #include #include #include +#include "bbox.hpp" #include "point.hpp" namespace ocl { -/// zgizag 2D operation +/// zigzag 2D operation class ZigZag { public: ZigZag() { } @@ -86,6 +88,8 @@ class ZigZag { o << "ZigZag: pocket.size()=" << pocket.size() << std::endl; return o.str(); } + auto getOutput() const { return out; } + protected: /// the step over double stepOver; diff --git a/src/common/halfedgediagram.hpp b/src/common/halfedgediagram.hpp index 092708cd..a85589f9 100644 --- a/src/common/halfedgediagram.hpp +++ b/src/common/halfedgediagram.hpp @@ -171,17 +171,13 @@ Face add_face() { /// return the target vertex of the given edge -Vertex target( Edge e ) { - return boost::target( e, g); -} +Vertex target(Edge e) const { return boost::target(e, g); } /// return the source vertex of the given edge -Vertex source( Edge e ) { - return boost::source( e, g); -} +Vertex source(Edge e) const { return boost::source(e, g); } /// return all vertices in a vector of vertex descriptors -VertexVector vertices() { +VertexVector vertices() const { typedef typename boost::graph_traits< BGLGraph >::vertex_descriptor HEVertex; typedef std::vector VertexVector; typedef typename boost::graph_traits< BGLGraph >::vertex_iterator HEVertexItr; @@ -256,7 +252,7 @@ EdgeVector out_edges( Vertex v) { } /// return all edges -EdgeVector edges() { +EdgeVector edges() const { typedef typename boost::graph_traits< BGLGraph >::edge_iterator HEEdgeItr; EdgeVector ev; HEEdgeItr it, it_end; diff --git a/src/pythonlib/adaptivewaterline_py.hpp b/src/pythonlib/adaptivewaterline_py.hpp deleted file mode 100644 index c1566870..00000000 --- a/src/pythonlib/adaptivewaterline_py.hpp +++ /dev/null @@ -1,81 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -#ifndef ADAPTIVEWATERLINE_PY_H -#define ADAPTIVEWATERLINE_PY_H - -#include "adaptivewaterline.hpp" -#include "fiber_py.hpp" - -#include -#include -#include - -namespace py = pybind11; - -namespace ocl { - -/// \brief python wrapper for AdaptiveWaterline -class AdaptiveWaterline_py : public AdaptiveWaterline { -public: - AdaptiveWaterline_py() : AdaptiveWaterline() {} - ~AdaptiveWaterline_py() { std::cout << "~AdaptiveWaterline_py()\n"; } - - /// return loop as a list of lists to python - py::list py_getLoops() const { - py::list loop_list; - for (const auto& loop : loops) { - py::list point_list; - for (const auto& p : loop) { - point_list.append(p); - } - loop_list.append(point_list); - } - return loop_list; - } - - /// return a list of xfibers to python - py::list getXFibers() const { - py::list flist; - for (const Fiber& f : xfibers) { - if (!f.empty()) { - Fiber_py f2(f); - flist.append(f2); - } - } - return flist; - } - - /// return a list of yfibers to python - py::list getYFibers() const { - py::list flist; - for (const Fiber& f : yfibers) { - if (!f.empty()) { - Fiber_py f2(f); - flist.append(f2); - } - } - return flist; - } -}; - -} // end namespace ocl - -#endif // ADAPTIVEWATERLINE_PY_H diff --git a/src/pythonlib/batchpushcutter_py.hpp b/src/pythonlib/batchpushcutter_py.hpp deleted file mode 100644 index 590948d1..00000000 --- a/src/pythonlib/batchpushcutter_py.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef BPC_PY_H -#define BPC_PY_H - -#include -#include - -#include -#include - -#include "batchpushcutter.hpp" -#include "fiber_py.hpp" - -namespace py = pybind11; - -namespace ocl { - -class BatchPushCutter_py : public BatchPushCutter { -public: - BatchPushCutter_py() : BatchPushCutter() {} - - // return CL-points to Python - py::list getCLPoints_py() const { - py::list plist; - for (const Fiber& f : *fibers) { - for (const Interval& i : f.ints) { - if (!i.empty()) { - Point tmp = f.point(i.lower); - CLPoint p1(tmp.x, tmp.y, tmp.z); - p1.cc = new CCPoint(i.lower_cc); - tmp = f.point(i.upper); - CLPoint p2(tmp.x, tmp.y, tmp.z); - p2.cc = new CCPoint(i.upper_cc); - plist.append(p1); - plist.append(p2); - } - } - } - return plist; - } // TODO use auto conversion - - // return triangles under cutter to Python. Not for CAM-algorithms, more for - // visualization and demonstration. - py::list getOverlapTriangles(Fiber& f) { - py::list trilist; - std::list* overlap_triangles = new std::list(); - CLPoint cl; - if (x_direction) { - cl.x = 0; - cl.y = f.p1.y; - cl.z = f.p1.z; - } else if (y_direction) { - cl.x = f.p1.x; - cl.y = 0; - cl.z = f.p1.z; - } else { - assert(0); - } - overlap_triangles = root->search_cutter_overlap(cutter, &cl); - for (const Triangle& t : *overlap_triangles) { - trilist.append(t); - } - delete overlap_triangles; - return trilist; - } - - py::list getFibers_py() const { - py::list flist; - for (const Fiber& f : *fibers) { - flist.append(Fiber_py(f)); - } - return flist; - } // TODO use auto conversion -}; - -} // namespace ocl - -#endif // BPC_PY_H diff --git a/src/pythonlib/fiber_py.hpp b/src/pythonlib/fiber_py.hpp deleted file mode 100644 index 5dfffe61..00000000 --- a/src/pythonlib/fiber_py.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef FIBER_PY_H -#define FIBER_PY_H - -#include -#include - -#include "fiber.hpp" - -namespace ocl { - -class Fiber_py : public Fiber { -public: - Fiber_py() : Fiber() {} - Fiber_py(const Point& p1, const Point& p2) : Fiber(p1, p2) {} - Fiber_py(const Fiber& f) : Fiber(f) {} - - pybind11::list getInts() const { - pybind11::list l; - for (const auto& i : ints) { - l.append(i); - } - return l; - } -}; - -} // namespace ocl - -#endif // FIBER_PY_H diff --git a/src/pythonlib/lineclfilter_py.hpp b/src/pythonlib/lineclfilter_py.hpp deleted file mode 100644 index 83ff68a5..00000000 --- a/src/pythonlib/lineclfilter_py.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef LINE_CL_FILTER_PY_H -#define LINE_CL_FILTER_PY_H - -#include -#include - -#include "lineclfilter.hpp" - -namespace py = pybind11; - -namespace ocl { - -/// python wrapper for LineCLFilter -class LineCLFilter_py : public LineCLFilter { -public: - LineCLFilter_py() : LineCLFilter() {} - - /// Return a list of CL-points to python - py::list getCLPoints() { - py::list plist; - for (const auto& p : clpoints) { - plist.append(p); - } - return plist; - } -}; - -} // namespace ocl - -#endif // LINE_CL_FILTER_PY_H diff --git a/src/pythonlib/ocl_algo.cpp b/src/pythonlib/ocl_algo.cpp index ba8d575e..ab156f11 100644 --- a/src/pythonlib/ocl_algo.cpp +++ b/src/pythonlib/ocl_algo.cpp @@ -19,17 +19,19 @@ * along with this program. If not, see . */ #include +#include -#include "adaptivewaterline_py.hpp" -#include "batchpushcutter_py.hpp" +#include "adaptivewaterline.hpp" +#include "batchpushcutter.hpp" #include "clsurface.hpp" -#include "fiber_py.hpp" -#include "lineclfilter_py.hpp" +#include "lineclfilter.hpp" #include "numeric.hpp" -#include "tsp.hpp" // fixme: contains python -#include "waterline_py.hpp" -#include "weave_py.hpp" -#include "zigzag_py.hpp" +#include "simple_weave.hpp" +#include "smart_weave.hpp" +#include "tsp.hpp" +#include "waterline.hpp" +#include "weave.hpp" +#include "zigzag.hpp" namespace py = pybind11; using namespace ocl; @@ -39,39 +41,35 @@ void export_algo(py::module& m) { m.def("epsF", epsF); m.def("epsD", epsD); - py::class_(m, "ZigZag_base"); - - py::class_(m, "ZigZag") + py::class_(m, "ZigZag") .def(py::init<>()) .def("run", &ZigZag::run) .def("setDirection", &ZigZag::setDirection) .def("setOrigin", &ZigZag::setOrigin) .def("setStepOver", &ZigZag::setStepOver) .def("addPoint", &ZigZag::addPoint) - .def("getOutput", &ZigZag_py::getOutput) + .def("getOutput", &ZigZag::getOutput) .def("__str__", &ZigZag::str); - py::class_(m, "BatchPushCutter_base"); - - py::class_(m, "BatchPushCutter") + py::class_(m, "BatchPushCutter") .def(py::init<>()) - .def("run", &BatchPushCutter_py::run) - .def("setSTL", &BatchPushCutter_py::setSTL) - .def("setCutter", &BatchPushCutter_py::setCutter) - .def("setThreads", (void(BatchPushCutter_py::*)(int)) & BatchPushCutter_py::setThreads) - .def("appendFiber", &BatchPushCutter_py::appendFiber) - .def("getOverlapTriangles", &BatchPushCutter_py::getOverlapTriangles) - .def("getCLPoints", &BatchPushCutter_py::getCLPoints_py) - .def("getFibers", &BatchPushCutter_py::getFibers_py) - .def("getCalls", &BatchPushCutter_py::getCalls) - .def("setThreads", (void(BatchPushCutter_py::*)(int)) & BatchPushCutter_py::setThreads) - .def("getThreads", &BatchPushCutter_py::getThreads) - .def("setBucketSize", &BatchPushCutter_py::setBucketSize) - .def("getBucketSize", &BatchPushCutter_py::getBucketSize) - .def("setXDirection", &BatchPushCutter_py::setXDirection) - .def("setYDirection", &BatchPushCutter_py::setYDirection); + .def("run", &BatchPushCutter::run) + .def("setSTL", &BatchPushCutter::setSTL) + .def("setCutter", &BatchPushCutter::setCutter) + .def("setThreads", &BatchPushCutter::setThreads) + .def("appendFiber", &BatchPushCutter::appendFiber) + .def("getOverlapTriangles", &BatchPushCutter::getOverlapTriangles) + .def("getCLPoints", &BatchPushCutter::getCLPoints) + .def("getFibers", &BatchPushCutter::getFibers, py::return_value_policy::reference_internal) + .def("getCalls", &BatchPushCutter::getCalls) + .def("getThreads", &BatchPushCutter::getThreads) + .def("setBucketSize", &BatchPushCutter::setBucketSize) + .def("getBucketSize", &BatchPushCutter::getBucketSize) + .def("setXDirection", &BatchPushCutter::setXDirection) + .def("setYDirection", &BatchPushCutter::setYDirection); py::class_(m, "Interval") + .def(py::init<>()) .def(py::init()) .def_readonly("upper", &Interval::upper) .def_readonly("lower", &Interval::lower) @@ -82,53 +80,46 @@ void export_algo(py::module& m) { .def("empty", &Interval::empty) .def("__str__", &Interval::str); - py::class_(m, "Fiber_base"); - - py::class_(m, "Fiber") + py::class_(m, "Fiber") .def(py::init()) - .def_readonly("p1", &Fiber_py::p1) - .def_readonly("p2", &Fiber_py::p2) - .def_readonly("dir", &Fiber_py::dir) - .def("addInterval", &Fiber_py::addInterval) - .def("point", &Fiber_py::point) - .def("printInts", &Fiber_py::printInts) - .def("getInts", &Fiber_py::getInts); - - py::class_(m, "Waterline_base"); - - py::class_(m, "Waterline") + .def_readonly("p1", &Fiber::p1) + .def_readonly("p2", &Fiber::p2) + .def_readonly("dir", &Fiber::dir) + .def("addInterval", &Fiber::addInterval) + .def("point", &Fiber::point) + .def("printInts", &Fiber::printInts) + .def("getInts", [](const Fiber& f) { return f.ints; }); + + py::class_(m, "Waterline") .def(py::init<>()) - .def("setCutter", &Waterline_py::setCutter) - .def("setSTL", &Waterline_py::setSTL) - .def("setZ", &Waterline_py::setZ) - .def("setSampling", &Waterline_py::setSampling) - .def("run", &Waterline_py::run) - .def("run2", &Waterline_py::run2) - .def("reset", &Waterline_py::reset) - .def("getLoops", &Waterline_py::py_getLoops) - .def("setThreads", &Waterline_py::setThreads) - .def("getThreads", &Waterline_py::getThreads) - .def("getXFibers", &Waterline_py::py_getXFibers) - .def("getYFibers", &Waterline_py::py_getYFibers); - - py::class_(m, "AdaptiveWaterline_base"); - - py::class_(m, "AdaptiveWaterline") + .def("setCutter", &Waterline::setCutter) + .def("setSTL", &Waterline::setSTL) + .def("setZ", &Waterline::setZ) + .def("setSampling", &Waterline::setSampling) + .def("run", &Waterline::run) + .def("run2", &Waterline::run2) + .def("reset", &Waterline::reset) + .def("getLoops", &Waterline::getLoops) + .def("setThreads", &Waterline::setThreads) + .def("getThreads", &Waterline::getThreads) + .def("getXFibers", &Waterline::getXFibers) + .def("getYFibers", &Waterline::getYFibers); + + py::class_(m, "AdaptiveWaterline") .def(py::init<>()) - .def("setCutter", &AdaptiveWaterline_py::setCutter) - .def("setSTL", &AdaptiveWaterline_py::setSTL) - .def("setZ", &AdaptiveWaterline_py::setZ) - .def("setSampling", &AdaptiveWaterline_py::setSampling) - .def("setMinSampling", &AdaptiveWaterline_py::setMinSampling) - .def("run", &AdaptiveWaterline_py::run) - .def("run2", &AdaptiveWaterline_py::run2) - .def("reset", &AdaptiveWaterline_py::reset) - // .def("run2", &AdaptiveWaterline_py::run2) // uses Weave::build2() - .def("getLoops", &AdaptiveWaterline_py::py_getLoops) - .def("setThreads", &AdaptiveWaterline_py::setThreads) - .def("getThreads", &AdaptiveWaterline_py::getThreads) - .def("getXFibers", &AdaptiveWaterline_py::getXFibers) - .def("getYFibers", &AdaptiveWaterline_py::getYFibers); + .def("setCutter", &AdaptiveWaterline::setCutter) + .def("setSTL", &AdaptiveWaterline::setSTL) + .def("setZ", &AdaptiveWaterline::setZ) + .def("setSampling", &AdaptiveWaterline::setSampling) + .def("setMinSampling", &AdaptiveWaterline::setMinSampling) + .def("run", &AdaptiveWaterline::run) + .def("run2", &AdaptiveWaterline::run2) + .def("reset", &AdaptiveWaterline::reset) + .def("getLoops", &AdaptiveWaterline::getLoops) + .def("setThreads", &AdaptiveWaterline::setThreads) + .def("getThreads", &AdaptiveWaterline::getThreads) + .def("getXFibers", &AdaptiveWaterline::getXFibers) + .def("getYFibers", &AdaptiveWaterline::getYFibers); py::enum_(m, "WeaveVertexType") .value("CL", weave::CL) @@ -138,35 +129,31 @@ void export_algo(py::module& m) { .value("INT", weave::INT) .value("FULLINT", weave::FULLINT); - /* - py::class_(m, "Weave_base"); - - py::class_(m, "Weave") - .def("addFiber", &weave::Weave_py::addFiber) - .def("build", &weave::Weave_py::build) - .def("build2", &weave::Weave_py::build2) - .def("printGraph", &weave::Weave_py::printGraph) - .def("face_traverse", &weave::Weave_py::face_traverse) - // .def("split_components", &weave::Weave_py::split_components) - // .def("get_components", &weave::Weave_py::get_components) - .def("getCLVertices", &weave::Weave_py::getCLVertices) - .def("getINTVertices", &weave::Weave_py::getINTVertices) - .def("getVertices", &weave::Weave_py::getVertices) - .def("numVertices", &weave::Weave_py::numVertices) - .def("getEdges", &weave::Weave_py::getEdges) - .def("getLoops", &weave::Weave_py::py_getLoops) - .def("__str__", &weave::Weave_py::str) - ; - */ - - py::class_(m, "LineCLFilter_base"); - - py::class_(m, "LineCLFilter") + py::class_(m, "Weave") + .def("addFiber", &weave::Weave::addFiber) + .def("build", &weave::Weave::build) + .def("printGraph", &weave::Weave::printGraph) + .def("face_traverse", &weave::Weave::face_traverse) + .def("getVertices", &weave::Weave::getVertices) + .def("getVerticesByType", &weave::Weave::getVerticesByType) + .def("getCLVertices", [](const weave::Weave& w) { return w.getVerticesByType(weave::CL); }) + .def("getINTVertices", + [](const weave::Weave& w) { return w.getVerticesByType(weave::INT); }) + .def("numVertices", &weave::Weave::numVertices) + .def("getEdges", &weave::Weave::getEdges) + .def("getLoops", &weave::Weave::getLoops) + .def("__str__", &weave::Weave::str); + + py::class_(m, "SimpleWeave").def(py::init<>()); + + py::class_(m, "SmartWeave").def(py::init<>()); + + py::class_(m, "LineCLFilter") .def(py::init<>()) - .def("addCLPoint", &LineCLFilter_py::addCLPoint) - .def("setTolerance", &LineCLFilter_py::setTolerance) - .def("run", &LineCLFilter_py::run) - .def("getCLPoints", &LineCLFilter_py::getCLPoints); + .def("addCLPoint", &LineCLFilter::addCLPoint) + .def("setTolerance", &LineCLFilter::setTolerance) + .def("run", &LineCLFilter::run) + .def("getCLPoints", [](const LineCLFilter& f) { return f.clpoints; }); py::class_(m, "CutterLocationSurface") .def(py::init()) @@ -179,13 +166,11 @@ void export_algo(py::module& m) { .def("getEdges", &clsurf::CutterLocationSurface::getEdges) .def("__str__", &clsurf::CutterLocationSurface::str); - /* py::class_(m, "TSPSolver") + .def(py::init<>()) .def("addPoint", &tsp::TSPSolver::addPoint) .def("run", &tsp::TSPSolver::run) .def("getOutput", &tsp::TSPSolver::getOutput) .def("getLength", &tsp::TSPSolver::getLength) - .def("reset", &tsp::TSPSolver::reset) - ; - */ + .def("reset", &tsp::TSPSolver::reset); } diff --git a/src/pythonlib/ocl_cutters.cpp b/src/pythonlib/ocl_cutters.cpp index 1361ab1a..9d557a64 100644 --- a/src/pythonlib/ocl_cutters.cpp +++ b/src/pythonlib/ocl_cutters.cpp @@ -33,12 +33,13 @@ using namespace ocl; void export_cutters(py::module& m) { py::class_(m, "MillingCutter") + .def(py::init<>()) .def("vertexDrop", &MillingCutter::vertexDrop) .def("facetDrop", &MillingCutter::facetDrop) .def("edgeDrop", &MillingCutter::edgeDrop) .def("dropCutter", &MillingCutter::dropCutter) .def("pushCutter", &MillingCutter::pushCutter) - .def("offsetCutter", &MillingCutter::offsetCutter, py::return_value_policy::take_ownership) + .def("offsetCutter", &MillingCutter::offsetCutter) .def("__str__", &MillingCutter::str) .def("getRadius", &MillingCutter::getRadius) .def("getLength", &MillingCutter::getLength) diff --git a/src/pythonlib/waterline_py.hpp b/src/pythonlib/waterline_py.hpp deleted file mode 100644 index 36c1539d..00000000 --- a/src/pythonlib/waterline_py.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -#ifndef WATERLINE_PY_H -#define WATERLINE_PY_H - -#include -#include - -#include - -#include "fiber_py.hpp" -#include "waterline.hpp" - -namespace py = pybind11; - -namespace ocl { - -/// Python wrapper for Waterline -class Waterline_py : public Waterline { -public: - Waterline_py() : Waterline() {} - ~Waterline_py() { std::cout << "~Waterline_py()\n"; } - /// return loop as a list of lists to Python - py::list py_getLoops() const { - py::list loop_list; - for (const auto& loop : this->loops) { - py::list point_list; - for (const auto& p : loop) { - point_list.append(p); - } - loop_list.append(point_list); - } - return loop_list; - } - /// return a list of xfibers to Python - py::list py_getXFibers() const { - py::list flist; - const std::vector& xfibers = *(subOp[0]->getFibers()); - for (const auto& f : xfibers) { - Fiber_py f2(f); - flist.append(f2); - } - return flist; - } - /// return a list of yfibers to Python - py::list py_getYFibers() const { - py::list flist; - const std::vector& yfibers = *(subOp[1]->getFibers()); - for (const auto& f : yfibers) { - Fiber_py f2(f); - flist.append(f2); - } - return flist; - } -}; - -} // end namespace ocl - -#endif // WATERLINE_PY_H diff --git a/src/pythonlib/weave_py.hpp b/src/pythonlib/weave_py.hpp deleted file mode 100644 index 7563b425..00000000 --- a/src/pythonlib/weave_py.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010-2011 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ -#ifndef WEAVE_PY_H -#define WEAVE_PY_H - -#include -#include - -#include "weave.hpp" - -namespace py = pybind11; - -namespace ocl { -namespace weave { - -class Weave_py : public Weave { -public: - Weave_py() : Weave() {} - - int numVertices() const { return g.num_vertices(); } - - py::list getVertices(VertexType t) { - py::list plist; - for (auto v : g.vertices()) { - if (g[v].type == t) - plist.append(g[v].position); - } - return plist; - } - - // return CL-points to python - py::list getCLVertices() { return getVertices(CL); } - - // return internal points to python - py::list getINTVertices() { return getVertices(INT); } - - // return edges to python - // format is [ [p1,p2] , [p3,p4] , ... ] - py::list getEdges() { - py::list edge_list; - for (auto e : g.edges()) { - py::list point_list; - Vertex v1 = g.source(e); - Vertex v2 = g.target(e); - point_list.append(g[v1].position); - point_list.append(g[v2].position); - edge_list.append(point_list); - } - return edge_list; - } - - // return loops to python - py::list getLoops() { - py::list loop_list; - for (const auto& loop : loops) { - py::list point_list; - for (auto v : loop) { - point_list.append(g[v].position); - } - loop_list.append(point_list); - } - return loop_list; - } -}; - -} // end namespace weave -} // end namespace ocl - -#endif // WEAVE_PY_H diff --git a/src/pythonlib/zigzag_py.hpp b/src/pythonlib/zigzag_py.hpp deleted file mode 100644 index 3c78ada4..00000000 --- a/src/pythonlib/zigzag_py.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef ZIGZAG_PY_H -#define ZIGZAG_PY_H - -#include - -#include "zigzag.hpp" - -namespace py = pybind11; - -namespace ocl { -/// Python wrapper for ZigZag -class ZigZag_py : public ZigZag { -public: - ZigZag_py() : ZigZag() {}; - - py::list getOutput() const { - py::list o; - for (const auto& p : out) { - o.append(p); - } - return o; - } -}; - -} // namespace ocl - -#endif // ZIGZAG_PY_H From 646ca4e94e48438f56a4bd5cfa4a48166eaabed5 Mon Sep 17 00:00:00 2001 From: CalaW Date: Sat, 19 Apr 2025 03:07:43 +0800 Subject: [PATCH 08/26] fix dropcutter get cl points --- src/dropcutter/adaptivepathdropcutter.hpp | 8 +++----- src/dropcutter/batchdropcutter.hpp | 6 +++--- src/dropcutter/pathdropcutter.hpp | 4 +++- src/pythonlib/ocl_dropcutter.cpp | 6 ++++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/dropcutter/adaptivepathdropcutter.hpp b/src/dropcutter/adaptivepathdropcutter.hpp index 15baf723..1365f6eb 100644 --- a/src/dropcutter/adaptivepathdropcutter.hpp +++ b/src/dropcutter/adaptivepathdropcutter.hpp @@ -70,12 +70,10 @@ class AdaptivePathDropCutter : public Operation { subOp[0]->clearCLPoints(); } - std::vector getPoints() const - { - return clpoints; - } + std::vector getCLPoints() { return clpoints; } + std::vector getPoints() { return clpoints; } // strange naming - protected: + protected: /// run adaptive sample on the given Span between t-values of start_t and stop_t void adaptive_sample(const Span* span, double start_t, double stop_t, CLPoint start_cl, CLPoint stop_cl); /// flatness predicate for adaptive sampling diff --git a/src/dropcutter/batchdropcutter.hpp b/src/dropcutter/batchdropcutter.hpp index fee75c07..7e145ae9 100644 --- a/src/dropcutter/batchdropcutter.hpp +++ b/src/dropcutter/batchdropcutter.hpp @@ -57,9 +57,9 @@ class BatchDropCutter : public Operation { void run() {this->dropCutter5();}; // getters and setters /// return a vector of CLPoints, the result of this operation - std::vector getCLPoints() {return *clpoints;} - /// clears the vector of CLPoints - void clearCLPoints() {clpoints->clear();} + std::vector getCLPoints() { return *clpoints; } + /// clears the vector of CLPoints + void clearCLPoints() { clpoints->clear(); } /// Return triangles under cutter, Not for CAM-algorithms, more for visualization and demonstration. std::list getTrianglesUnderCutter(CLPoint& cl, MillingCutter& cutter) diff --git a/src/dropcutter/pathdropcutter.hpp b/src/dropcutter/pathdropcutter.hpp index 0fd0bcbb..1b606026 100644 --- a/src/dropcutter/pathdropcutter.hpp +++ b/src/dropcutter/pathdropcutter.hpp @@ -62,7 +62,9 @@ class PathDropCutter : public Operation { /// run drop-cutter on the whole Path virtual void run(); - protected: + std::vector getCLPoints() { return clpoints; } + + protected: /// the path to follow const Path* path; /// the lowest z height, used when no triangles are touched, default is minimumZ = 0.0 diff --git a/src/pythonlib/ocl_dropcutter.cpp b/src/pythonlib/ocl_dropcutter.cpp index 02c39a13..ce13305a 100644 --- a/src/pythonlib/ocl_dropcutter.cpp +++ b/src/pythonlib/ocl_dropcutter.cpp @@ -57,7 +57,8 @@ void export_dropcutter(py::module_& m) { .def("setSampling", &PathDropCutter::setSampling) .def("setPath", &PathDropCutter::setPath) .def("getZ", &PathDropCutter::getZ) - .def("setZ", &PathDropCutter::setZ); + .def("setZ", &PathDropCutter::setZ) + .def_property("minimumZ", &PathDropCutter::getZ, &PathDropCutter::setZ); py::class_(m, "AdaptivePathDropCutter") .def(py::init<>()) @@ -71,5 +72,6 @@ void export_dropcutter(py::module_& m) { .def("getSampling", &AdaptivePathDropCutter::getSampling) .def("setPath", &AdaptivePathDropCutter::setPath) .def("getZ", &AdaptivePathDropCutter::getZ) - .def("setZ", &AdaptivePathDropCutter::setZ); + .def("setZ", &AdaptivePathDropCutter::setZ) + .def_property("minimumZ", &AdaptivePathDropCutter::getZ, &AdaptivePathDropCutter::setZ); } From 9125966d216f1834c7a9363ac10847379612582a Mon Sep 17 00:00:00 2001 From: CalaW Date: Sat, 19 Apr 2025 03:07:48 +0800 Subject: [PATCH 09/26] Point inherit in python --- src/pythonlib/ocl_geometry.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/pythonlib/ocl_geometry.cpp b/src/pythonlib/ocl_geometry.cpp index 5ea85f86..71c2fe63 100644 --- a/src/pythonlib/ocl_geometry.cpp +++ b/src/pythonlib/ocl_geometry.cpp @@ -39,6 +39,7 @@ using namespace ocl; void export_geometry(py::module_& m) { py::class_(m, "Point") + .def(py::init<>()) .def(py::init()) .def(py::init()) .def(py::init()) @@ -66,25 +67,21 @@ void export_geometry(py::module_& m) { .def_readwrite("y", &Point::y) .def_readwrite("z", &Point::z); - py::class_(m, "CLPoint") // FIXME: should inherit from Point + py::class_(m, "CLPoint") + .def(py::init<>()) .def(py::init()) .def(py::init()) .def(py::init()) .def("__str__", &CLPoint::str) - .def_readwrite("x", &CLPoint::x) - .def_readwrite("y", &CLPoint::y) - .def_readwrite("z", &CLPoint::z) .def("cc", &CLPoint::getCC) .def("getCC", &CLPoint::getCC); - py::class_(m, "CCPoint") // FIXME: CCPoint should inherit from Point + py::class_(m, "CCPoint") + .def(py::init<>()) .def(py::init()) .def(py::init()) .def("__str__", &CCPoint::str) - .def_readwrite("type", &CCPoint::type) - .def_readwrite("x", &CCPoint::x) - .def_readwrite("y", &CCPoint::y) - .def_readwrite("z", &CCPoint::z); + .def_readwrite("type", &CCPoint::type); py::enum_(m, "CCType") .value("NONE", NONE) From c8530dc42d6295e71c4b2ff54ee8efd566f9489b Mon Sep 17 00:00:00 2001 From: CalaW Date: Sat, 19 Apr 2025 23:00:15 +0800 Subject: [PATCH 10/26] add stub file, reorder python export to avoid c++ type in docstrings https://pybind11.readthedocs.io/en/latest/advanced/misc.html#avoiding-cpp-types-in-docstrings --- src/pythonlib/ocl_algo.cpp | 22 - src/pythonlib/ocl_geometry.cpp | 71 ++- src/pythonlib/opencamlib/ocl.pyi | 754 ++++++++++++++++++++++++++++++ src/pythonlib/opencamlib/py.typed | 0 4 files changed, 802 insertions(+), 45 deletions(-) create mode 100644 src/pythonlib/opencamlib/ocl.pyi create mode 100644 src/pythonlib/opencamlib/py.typed diff --git a/src/pythonlib/ocl_algo.cpp b/src/pythonlib/ocl_algo.cpp index ab156f11..a8a0f93a 100644 --- a/src/pythonlib/ocl_algo.cpp +++ b/src/pythonlib/ocl_algo.cpp @@ -68,28 +68,6 @@ void export_algo(py::module& m) { .def("setXDirection", &BatchPushCutter::setXDirection) .def("setYDirection", &BatchPushCutter::setYDirection); - py::class_(m, "Interval") - .def(py::init<>()) - .def(py::init()) - .def_readonly("upper", &Interval::upper) - .def_readonly("lower", &Interval::lower) - .def_readonly("lower_cc", &Interval::lower_cc) - .def_readonly("upper_cc", &Interval::upper_cc) - .def("updateUpper", &Interval::updateUpper) - .def("updateLower", &Interval::updateLower) - .def("empty", &Interval::empty) - .def("__str__", &Interval::str); - - py::class_(m, "Fiber") - .def(py::init()) - .def_readonly("p1", &Fiber::p1) - .def_readonly("p2", &Fiber::p2) - .def_readonly("dir", &Fiber::dir) - .def("addInterval", &Fiber::addInterval) - .def("point", &Fiber::point) - .def("printInts", &Fiber::printInts) - .def("getInts", [](const Fiber& f) { return f.ints; }); - py::class_(m, "Waterline") .def(py::init<>()) .def("setCutter", &Waterline::setCutter) diff --git a/src/pythonlib/ocl_geometry.cpp b/src/pythonlib/ocl_geometry.cpp index 71c2fe63..b0da1aa1 100644 --- a/src/pythonlib/ocl_geometry.cpp +++ b/src/pythonlib/ocl_geometry.cpp @@ -27,6 +27,8 @@ #include "clpoint.hpp" #include "ellipse.hpp" #include "ellipseposition.hpp" +#include "fiber.hpp" +#include "interval.hpp" #include "ostream_str.hpp" #include "path.hpp" #include "point.hpp" @@ -38,6 +40,8 @@ namespace py = pybind11; using namespace ocl; void export_geometry(py::module_& m) { + auto pyTriangle = py::class_(m, "Triangle"); // for stub generation + py::class_(m, "Point") .def(py::init<>()) .def(py::init()) @@ -67,22 +71,6 @@ void export_geometry(py::module_& m) { .def_readwrite("y", &Point::y) .def_readwrite("z", &Point::z); - py::class_(m, "CLPoint") - .def(py::init<>()) - .def(py::init()) - .def(py::init()) - .def(py::init()) - .def("__str__", &CLPoint::str) - .def("cc", &CLPoint::getCC) - .def("getCC", &CLPoint::getCC); - - py::class_(m, "CCPoint") - .def(py::init<>()) - .def(py::init()) - .def(py::init()) - .def("__str__", &CCPoint::str) - .def_readwrite("type", &CCPoint::type); - py::enum_(m, "CCType") .value("NONE", NONE) .value("VERTEX", VERTEX) @@ -104,13 +92,33 @@ void export_geometry(py::module_& m) { .value("ERROR", ERROR) .export_values(); - py::class_(m, "Triangle") - .def(py::init()) + py::class_(m, "CCPoint") + .def(py::init<>()) + .def(py::init()) + .def(py::init()) + .def("__str__", &CCPoint::str) + .def_readwrite("type", &CCPoint::type); + + py::class_(m, "CLPoint") + .def(py::init<>()) + .def(py::init()) + .def(py::init()) + .def(py::init()) + .def("__str__", &CLPoint::str) + .def("cc", &CLPoint::getCC) + .def("getCC", &CLPoint::getCC); + + pyTriangle.def(py::init()) .def("getPoints", [](const Triangle& t) { return std::to_array(t.p); }) .def("__str__", &ostream_str) .def_property_readonly("p", [](const Triangle& t) { return std::to_array(t.p); }) .def_readonly("n", &Triangle::n); + py::class_(m, "Bbox") + .def("isInside", &Bbox::isInside) + .def_readonly("maxpt", &Bbox::maxpt) + .def_readonly("minpt", &Bbox::minpt); + py::class_(m, "STLSurf") .def(py::init<>()) .def("addTriangle", &STLSurf::addTriangle) @@ -128,11 +136,6 @@ void export_geometry(py::module_& m) { py::class_(m, "STLReader").def(py::init()); - py::class_(m, "Bbox") - .def("isInside", &Bbox::isInside) - .def_readonly("maxpt", &Bbox::maxpt) - .def_readonly("minpt", &Bbox::minpt); - // EllipsePosition and Ellipse for toroidal tool edge-tests py::class_(m, "EllipsePosition") .def_readwrite("s", &EllipsePosition::s) @@ -197,4 +200,26 @@ void export_geometry(py::module_& m) { }) .def("append", py::overload_cast(&Path::append)) .def("append", py::overload_cast(&Path::append)); + + py::class_(m, "Interval") + .def(py::init<>()) + .def(py::init()) + .def_readonly("upper", &Interval::upper) + .def_readonly("lower", &Interval::lower) + .def_readonly("lower_cc", &Interval::lower_cc) + .def_readonly("upper_cc", &Interval::upper_cc) + .def("updateUpper", &Interval::updateUpper) + .def("updateLower", &Interval::updateLower) + .def("empty", &Interval::empty) + .def("__str__", &Interval::str); + + py::class_(m, "Fiber") + .def(py::init()) + .def_readonly("p1", &Fiber::p1) + .def_readonly("p2", &Fiber::p2) + .def_readonly("dir", &Fiber::dir) + .def("addInterval", &Fiber::addInterval) + .def("point", &Fiber::point) + .def("printInts", &Fiber::printInts) + .def("getInts", [](const Fiber& f) { return f.ints; }); } diff --git a/src/pythonlib/opencamlib/ocl.pyi b/src/pythonlib/opencamlib/ocl.pyi new file mode 100644 index 00000000..4ae5a46f --- /dev/null +++ b/src/pythonlib/opencamlib/ocl.pyi @@ -0,0 +1,754 @@ +""" +OpenCAMLib docstring +""" +from __future__ import annotations +import pybind11_stubgen.typing_ext +import typing +__all__ = ['AdaptivePathDropCutter', 'AdaptiveWaterline', 'Arc', 'ArcSpanType', 'BallConeCutter', 'BallCutter', 'BatchDropCutter', 'BatchPushCutter', 'Bbox', 'BullConeCutter', 'BullCutter', 'CCPoint', 'CCType', 'CLPoint', 'CompBallCutter', 'CompCylCutter', 'ConeConeCutter', 'ConeCutter', 'CutterLocationSurface', 'CylConeCutter', 'CylCutter', 'EDGE', 'EDGE_BALL', 'EDGE_CONE', 'EDGE_CONE_BASE', 'EDGE_CYL', 'EDGE_HORIZ', 'EDGE_HORIZ_CYL', 'EDGE_HORIZ_TOR', 'EDGE_NEG', 'EDGE_POS', 'EDGE_SHAFT', 'ERROR', 'Ellipse', 'EllipsePosition', 'FACET', 'FACET_CYL', 'FACET_TIP', 'Fiber', 'Interval', 'Line', 'LineCLFilter', 'LineSpanType', 'MillingCutter', 'NONE', 'Path', 'PathDropCutter', 'Point', 'STLReader', 'STLSurf', 'SimpleWeave', 'SmartWeave', 'SpanType', 'TSPSolver', 'Triangle', 'VERTEX', 'VERTEX_CYL', 'Waterline', 'Weave', 'WeaveVertexType', 'ZigZag', 'eps', 'epsD', 'epsF', 'max_threads', 'version'] +class AdaptivePathDropCutter: + minimumZ: float + def __init__(self) -> None: + ... + def getCLPoints(self) -> list[CLPoint]: + ... + def getSampling(self) -> float: + ... + def getZ(self) -> float: + ... + def run(self) -> None: + ... + def setCosLimit(self, arg0: float) -> None: + ... + def setCutter(self, arg0: MillingCutter) -> None: + ... + def setMinSampling(self, arg0: float) -> None: + ... + def setPath(self, arg0: Path) -> None: + ... + def setSTL(self, arg0: STLSurf) -> None: + ... + def setSampling(self, arg0: float) -> None: + ... + def setZ(self, arg0: float) -> None: + ... +class AdaptiveWaterline: + def __init__(self) -> None: + ... + def getLoops(self) -> list[list[Point]]: + ... + def getThreads(self) -> int: + ... + def getXFibers(self) -> list[Fiber]: + ... + def getYFibers(self) -> list[Fiber]: + ... + def reset(self) -> None: + ... + def run(self) -> None: + ... + def run2(self) -> None: + ... + def setCutter(self, arg0: MillingCutter) -> None: + ... + def setMinSampling(self, arg0: float) -> None: + ... + def setSTL(self, arg0: STLSurf) -> None: + ... + def setSampling(self, arg0: float) -> None: + ... + def setThreads(self, arg0: int) -> None: + ... + def setZ(self, arg0: float) -> None: + ... +class Arc: + c: Point + dir: bool + p1: Point + p2: Point + @typing.overload + def __init__(self, arg0: Point, arg1: Point, arg2: Point, arg3: bool) -> None: + ... + @typing.overload + def __init__(self, arg0: Arc) -> None: + ... +class BallConeCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float, arg2: float) -> None: + ... +class BallCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float) -> None: + ... + def dropCutterSTL(self, arg0: CLPoint, arg1: STLSurf) -> bool: + ... +class BatchDropCutter: + def __init__(self) -> None: + ... + def appendPoint(self, arg0: CLPoint) -> None: + ... + def getBucketSize(self) -> int: + ... + def getCLPoints(self) -> list[CLPoint]: + ... + def getCalls(self) -> int: + ... + def getThreads(self) -> int: + ... + def getTrianglesUnderCutter(self, arg0: CLPoint, arg1: MillingCutter) -> list[Triangle]: + ... + def run(self) -> None: + ... + def setBucketSize(self, arg0: int) -> None: + ... + def setCutter(self, arg0: MillingCutter) -> None: + ... + def setSTL(self, arg0: STLSurf) -> None: + ... + def setThreads(self, arg0: int) -> None: + ... +class BatchPushCutter: + def __init__(self) -> None: + ... + def appendFiber(self, arg0: Fiber) -> None: + ... + def getBucketSize(self) -> int: + ... + def getCLPoints(self) -> list[CLPoint]: + ... + def getCalls(self) -> int: + ... + def getFibers(self) -> list[Fiber]: + ... + def getOverlapTriangles(self, arg0: Fiber) -> list[Triangle]: + ... + def getThreads(self) -> int: + ... + def run(self) -> None: + ... + def setBucketSize(self, arg0: int) -> None: + ... + def setCutter(self, arg0: MillingCutter) -> None: + ... + def setSTL(self, arg0: STLSurf) -> None: + ... + def setThreads(self, arg0: int) -> None: + ... + def setXDirection(self) -> None: + ... + def setYDirection(self) -> None: + ... +class Bbox: + def isInside(self, arg0: Point) -> bool: + ... + @property + def maxpt(self) -> Point: + ... + @property + def minpt(self) -> Point: + ... +class BullConeCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float, arg2: float, arg3: float) -> None: + ... +class BullCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float, arg2: float) -> None: + ... +class CCPoint(Point): + type: CCType + @typing.overload + def __init__(self) -> None: + ... + @typing.overload + def __init__(self, arg0: CCPoint) -> None: + ... + @typing.overload + def __init__(self, arg0: float, arg1: float, arg2: float) -> None: + ... + def __str__(self) -> str: + ... +class CCType: + """ + Members: + + NONE + + VERTEX + + VERTEX_CYL + + EDGE + + EDGE_SHAFT + + EDGE_HORIZ + + EDGE_CYL + + EDGE_BALL + + EDGE_CONE + + EDGE_CONE_BASE + + EDGE_HORIZ_CYL + + EDGE_HORIZ_TOR + + EDGE_POS + + EDGE_NEG + + FACET + + FACET_TIP + + FACET_CYL + + ERROR + """ + EDGE: typing.ClassVar[CCType] # value = + EDGE_BALL: typing.ClassVar[CCType] # value = + EDGE_CONE: typing.ClassVar[CCType] # value = + EDGE_CONE_BASE: typing.ClassVar[CCType] # value = + EDGE_CYL: typing.ClassVar[CCType] # value = + EDGE_HORIZ: typing.ClassVar[CCType] # value = + EDGE_HORIZ_CYL: typing.ClassVar[CCType] # value = + EDGE_HORIZ_TOR: typing.ClassVar[CCType] # value = + EDGE_NEG: typing.ClassVar[CCType] # value = + EDGE_POS: typing.ClassVar[CCType] # value = + EDGE_SHAFT: typing.ClassVar[CCType] # value = + ERROR: typing.ClassVar[CCType] # value = + FACET: typing.ClassVar[CCType] # value = + FACET_CYL: typing.ClassVar[CCType] # value = + FACET_TIP: typing.ClassVar[CCType] # value = + NONE: typing.ClassVar[CCType] # value = + VERTEX: typing.ClassVar[CCType] # value = + VERTEX_CYL: typing.ClassVar[CCType] # value = + __members__: typing.ClassVar[dict[str, CCType]] # value = {'NONE': , 'VERTEX': , 'VERTEX_CYL': , 'EDGE': , 'EDGE_SHAFT': , 'EDGE_HORIZ': , 'EDGE_CYL': , 'EDGE_BALL': , 'EDGE_CONE': , 'EDGE_CONE_BASE': , 'EDGE_HORIZ_CYL': , 'EDGE_HORIZ_TOR': , 'EDGE_POS': , 'EDGE_NEG': , 'FACET': , 'FACET_TIP': , 'FACET_CYL': , 'ERROR': } + def __eq__(self, other: typing.Any) -> bool: + ... + def __getstate__(self) -> int: + ... + def __hash__(self) -> int: + ... + def __index__(self) -> int: + ... + def __init__(self, value: int) -> None: + ... + def __int__(self) -> int: + ... + def __ne__(self, other: typing.Any) -> bool: + ... + def __repr__(self) -> str: + ... + def __setstate__(self, state: int) -> None: + ... + def __str__(self) -> str: + ... + @property + def name(self) -> str: + ... + @property + def value(self) -> int: + ... +class CLPoint(Point): + @typing.overload + def __init__(self) -> None: + ... + @typing.overload + def __init__(self, arg0: CLPoint) -> None: + ... + @typing.overload + def __init__(self, arg0: float, arg1: float, arg2: float) -> None: + ... + @typing.overload + def __init__(self, arg0: float, arg1: float, arg2: float, arg3: CCPoint) -> None: + ... + def __str__(self) -> str: + ... + def cc(self) -> CCPoint: + ... + def getCC(self) -> CCPoint: + ... +class CompBallCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float) -> None: + ... +class CompCylCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float) -> None: + ... +class ConeConeCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float, arg2: float, arg3: float) -> None: + ... +class ConeCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float, arg2: float) -> None: + ... +class CutterLocationSurface: + def __init__(self, arg0: float) -> None: + ... + def __str__(self) -> str: + ... + def getEdges(self) -> list[tuple[Point, Point]]: + ... + def getVertices(self) -> list[Point]: + ... + def run(self) -> None: + ... + def setCutter(self, arg0: MillingCutter) -> None: + ... + def setMinSampling(self, arg0: float) -> None: + ... + def setSTL(self, arg0: STLSurf) -> None: + ... + def setSampling(self, arg0: float) -> None: + ... +class CylConeCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float, arg2: float) -> None: + ... +class CylCutter(MillingCutter): + def __init__(self, arg0: float, arg1: float) -> None: + ... + def dropCutterSTL(self, arg0: CLPoint, arg1: STLSurf) -> bool: + ... +class Ellipse: + def __init__(self, arg0: Point, arg1: float, arg2: float, arg3: float) -> None: + ... + def ePoint(self, arg0: EllipsePosition) -> Point: + ... + def normal(self, arg0: EllipsePosition) -> Point: + ... + def oePoint(self, arg0: EllipsePosition) -> Point: + ... +class EllipsePosition: + s: float + t: float + def __str__(self) -> str: + ... + def setDiangle(self, arg0: float) -> None: + ... +class Fiber: + def __init__(self, arg0: Point, arg1: Point) -> None: + ... + def addInterval(self, arg0: Interval) -> None: + ... + def getInts(self) -> list[Interval]: + ... + def point(self, arg0: float) -> Point: + ... + def printInts(self) -> None: + ... + @property + def dir(self) -> Point: + ... + @property + def p1(self) -> Point: + ... + @property + def p2(self) -> Point: + ... +class Interval: + @typing.overload + def __init__(self) -> None: + ... + @typing.overload + def __init__(self, arg0: float, arg1: float) -> None: + ... + def __str__(self) -> str: + ... + def empty(self) -> bool: + ... + def updateLower(self, arg0: float, arg1: CCPoint) -> None: + ... + def updateUpper(self, arg0: float, arg1: CCPoint) -> None: + ... + @property + def lower(self) -> float: + ... + @property + def lower_cc(self) -> CCPoint: + ... + @property + def upper(self) -> float: + ... + @property + def upper_cc(self) -> CCPoint: + ... +class Line: + p1: Point + p2: Point + @typing.overload + def __init__(self, arg0: Point, arg1: Point) -> None: + ... + @typing.overload + def __init__(self, arg0: Line) -> None: + ... +class LineCLFilter: + def __init__(self) -> None: + ... + def addCLPoint(self, arg0: CLPoint) -> None: + ... + def getCLPoints(self) -> list[CLPoint]: + ... + def run(self) -> None: + ... + def setTolerance(self, arg0: float) -> None: + ... +class MillingCutter: + def __init__(self) -> None: + ... + def __str__(self) -> str: + ... + def dropCutter(self, arg0: CLPoint, arg1: Triangle) -> bool: + ... + def edgeDrop(self, arg0: CLPoint, arg1: Triangle) -> bool: + ... + def facetDrop(self, arg0: CLPoint, arg1: Triangle) -> bool: + ... + def getDiameter(self) -> float: + ... + def getLength(self) -> float: + ... + def getRadius(self) -> float: + ... + def offsetCutter(self, arg0: float) -> MillingCutter: + ... + def pushCutter(self, arg0: Fiber, arg1: Interval, arg2: Triangle) -> bool: + ... + def vertexDrop(self, arg0: CLPoint, arg1: Triangle) -> bool: + ... +class Path: + @typing.overload + def __init__(self) -> None: + ... + @typing.overload + def __init__(self, arg0: Path) -> None: + ... + @typing.overload + def append(self, arg0: Line) -> None: + ... + @typing.overload + def append(self, arg0: Arc) -> None: + ... + def getSpans(self) -> list: + ... + def getTypeSpanPairs(self) -> list: + ... +class PathDropCutter: + minimumZ: float + def __init__(self) -> None: + ... + def getCLPoints(self) -> list[CLPoint]: + ... + def getZ(self) -> float: + ... + def run(self) -> None: + ... + def setCutter(self, arg0: MillingCutter) -> None: + ... + def setPath(self, arg0: Path) -> None: + ... + def setSTL(self, arg0: STLSurf) -> None: + ... + def setSampling(self, arg0: float) -> None: + ... + def setZ(self, arg0: float) -> None: + ... +class Point: + x: float + y: float + z: float + def __add__(self, arg0: Point) -> Point: + ... + def __iadd__(self, arg0: Point) -> Point: + ... + @typing.overload + def __init__(self) -> None: + ... + @typing.overload + def __init__(self, arg0: float, arg1: float, arg2: float) -> None: + ... + @typing.overload + def __init__(self, arg0: float, arg1: float) -> None: + ... + @typing.overload + def __init__(self, arg0: Point) -> None: + ... + def __isub__(self, arg0: Point) -> Point: + ... + def __mul__(self, arg0: float) -> Point: + ... + def __rmul__(self, arg0: float) -> Point: + ... + def __str__(self) -> str: + ... + def __sub__(self, arg0: Point) -> Point: + ... + def cross(self, arg0: Point) -> Point: + ... + def dot(self, arg0: Point) -> float: + ... + @typing.overload + def isInside(self, arg0: Triangle) -> bool: + ... + @typing.overload + def isInside(self, arg0: Point, arg1: Point) -> bool: + ... + def isRight(self, arg0: Point, arg1: Point) -> bool: + ... + def norm(self) -> float: + ... + def normalize(self) -> None: + ... + def xRotate(self, arg0: float) -> None: + ... + def xyDistance(self, arg0: Point) -> float: + ... + def xyNorm(self) -> float: + ... + def yRotate(self, arg0: float) -> None: + ... + def zRotate(self, arg0: float) -> None: + ... +class STLReader: + def __init__(self, arg0: str, arg1: STLSurf) -> None: + ... +class STLSurf: + def __init__(self) -> None: + ... + def __str__(self) -> str: + ... + def addTriangle(self, arg0: Triangle) -> None: + ... + def getBounds(self) -> typing.Annotated[list[float], pybind11_stubgen.typing_ext.FixedSize(6)]: + ... + def getTriangles(self) -> list[Triangle]: + ... + def rotate(self, arg0: float, arg1: float, arg2: float) -> None: + ... + def size(self) -> int: + ... + @property + def bb(self) -> Bbox: + ... + @property + def tris(self) -> list[Triangle]: + ... +class SimpleWeave(Weave): + def __init__(self) -> None: + ... +class SmartWeave(Weave): + def __init__(self) -> None: + ... +class SpanType: + """ + Members: + + LineSpanType + + ArcSpanType + """ + ArcSpanType: typing.ClassVar[SpanType] # value = + LineSpanType: typing.ClassVar[SpanType] # value = + __members__: typing.ClassVar[dict[str, SpanType]] # value = {'LineSpanType': , 'ArcSpanType': } + def __eq__(self, other: typing.Any) -> bool: + ... + def __getstate__(self) -> int: + ... + def __hash__(self) -> int: + ... + def __index__(self) -> int: + ... + def __init__(self, value: int) -> None: + ... + def __int__(self) -> int: + ... + def __ne__(self, other: typing.Any) -> bool: + ... + def __repr__(self) -> str: + ... + def __setstate__(self, state: int) -> None: + ... + def __str__(self) -> str: + ... + @property + def name(self) -> str: + ... + @property + def value(self) -> int: + ... +class TSPSolver: + def __init__(self) -> None: + ... + def addPoint(self, arg0: float, arg1: float) -> None: + ... + def getLength(self) -> float: + ... + def getOutput(self) -> list[int]: + ... + def reset(self) -> None: + ... + def run(self) -> None: + ... +class Triangle: + def __init__(self, arg0: Point, arg1: Point, arg2: Point) -> None: + ... + def __str__(self) -> str: + ... + def getPoints(self) -> typing.Annotated[list[Point], pybind11_stubgen.typing_ext.FixedSize(3)]: + ... + @property + def n(self) -> Point: + ... + @property + def p(self) -> typing.Annotated[list[Point], pybind11_stubgen.typing_ext.FixedSize(3)]: + ... +class Waterline: + def __init__(self) -> None: + ... + def getLoops(self) -> list[list[Point]]: + ... + def getThreads(self) -> int: + ... + def getXFibers(self) -> list[Fiber]: + ... + def getYFibers(self) -> list[Fiber]: + ... + def reset(self) -> None: + ... + def run(self) -> None: + ... + def run2(self) -> None: + ... + def setCutter(self, arg0: MillingCutter) -> None: + ... + def setSTL(self, arg0: STLSurf) -> None: + ... + def setSampling(self, arg0: float) -> None: + ... + def setThreads(self, arg0: int) -> None: + ... + def setZ(self, arg0: float) -> None: + ... +class Weave: + def __str__(self) -> str: + ... + def addFiber(self, arg0: Fiber) -> None: + ... + def build(self) -> None: + ... + def face_traverse(self) -> None: + ... + def getCLVertices(self) -> list[Point]: + ... + def getEdges(self) -> list[tuple[Point, Point]]: + ... + def getINTVertices(self) -> list[Point]: + ... + def getLoops(self) -> list[list[Point]]: + ... + def getVertices(self) -> list[Point]: + ... + def getVerticesByType(self, arg0: WeaveVertexType) -> list[Point]: + ... + def numVertices(self) -> int: + ... + def printGraph(self) -> None: + ... +class WeaveVertexType: + """ + Members: + + CL + + CL_DONE + + ADJ + + TWOADJ + + INT + + FULLINT + """ + ADJ: typing.ClassVar[WeaveVertexType] # value = + CL: typing.ClassVar[WeaveVertexType] # value = + CL_DONE: typing.ClassVar[WeaveVertexType] # value = + FULLINT: typing.ClassVar[WeaveVertexType] # value = + INT: typing.ClassVar[WeaveVertexType] # value = + TWOADJ: typing.ClassVar[WeaveVertexType] # value = + __members__: typing.ClassVar[dict[str, WeaveVertexType]] # value = {'CL': , 'CL_DONE': , 'ADJ': , 'TWOADJ': , 'INT': , 'FULLINT': } + def __eq__(self, other: typing.Any) -> bool: + ... + def __getstate__(self) -> int: + ... + def __hash__(self) -> int: + ... + def __index__(self) -> int: + ... + def __init__(self, value: int) -> None: + ... + def __int__(self) -> int: + ... + def __ne__(self, other: typing.Any) -> bool: + ... + def __repr__(self) -> str: + ... + def __setstate__(self, state: int) -> None: + ... + def __str__(self) -> str: + ... + @property + def name(self) -> str: + ... + @property + def value(self) -> int: + ... +class ZigZag: + def __init__(self) -> None: + ... + def __str__(self) -> str: + ... + def addPoint(self, arg0: Point) -> None: + ... + def getOutput(self) -> list[Point]: + ... + def run(self) -> None: + ... + def setDirection(self, arg0: Point) -> None: + ... + def setOrigin(self, arg0: Point) -> None: + ... + def setStepOver(self, arg0: float) -> None: + ... +def eps() -> float: + """ + machine epsilon, see numeric.cpp + """ +def epsD(arg0: float) -> float: + ... +def epsF(arg0: float) -> float: + ... +def max_threads() -> int: + """ + Return the maximum number of available threads + """ +def version() -> str: + """ + Return the version string of OpenCAMLib + """ +ArcSpanType: SpanType # value = +EDGE: CCType # value = +EDGE_BALL: CCType # value = +EDGE_CONE: CCType # value = +EDGE_CONE_BASE: CCType # value = +EDGE_CYL: CCType # value = +EDGE_HORIZ: CCType # value = +EDGE_HORIZ_CYL: CCType # value = +EDGE_HORIZ_TOR: CCType # value = +EDGE_NEG: CCType # value = +EDGE_POS: CCType # value = +EDGE_SHAFT: CCType # value = +ERROR: CCType # value = +FACET: CCType # value = +FACET_CYL: CCType # value = +FACET_TIP: CCType # value = +LineSpanType: SpanType # value = +NONE: CCType # value = +VERTEX: CCType # value = +VERTEX_CYL: CCType # value = diff --git a/src/pythonlib/opencamlib/py.typed b/src/pythonlib/opencamlib/py.typed new file mode 100644 index 00000000..e69de29b From 0171acade580573b91868e24f062317a59d6c2d2 Mon Sep 17 00:00:00 2001 From: CalaW Date: Sat, 19 Apr 2025 23:07:18 +0800 Subject: [PATCH 11/26] Revert "Add Boost.Python patch for Python 3.11 support" This reverts commit e894a138c47fc9e40f11fee18a79188827c6beb4. --- .github/patches/boost-python-3.11.patch | 35 ------------------------- 1 file changed, 35 deletions(-) delete mode 100644 .github/patches/boost-python-3.11.patch diff --git a/.github/patches/boost-python-3.11.patch b/.github/patches/boost-python-3.11.patch deleted file mode 100644 index 561506df..00000000 --- a/.github/patches/boost-python-3.11.patch +++ /dev/null @@ -1,35 +0,0 @@ -From a218babc8daee904a83f550fb66e5cb3f1cb3013 Mon Sep 17 00:00:00 2001 -From: Victor Stinner -Date: Mon, 25 Apr 2022 10:51:46 +0200 -Subject: [PATCH] Fix enum_type_object type on Python 3.11 - -The enum_type_object type inherits from PyLong_Type which is not tracked -by the GC. Instances doesn't have to be tracked by the GC: remove the -Py_TPFLAGS_HAVE_GC flag. - -The Python C API documentation says: - - "To create a container type, the tp_flags field of the type object - must include the Py_TPFLAGS_HAVE_GC and provide an implementation of - the tp_traverse handler." - -https://docs.python.org/dev/c-api/gcsupport.html - -The new exception was introduced in Python 3.11 by: -https://github.com/python/cpython/issues/88429 ---- - src/object/enum.cpp | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/src/object/enum.cpp b/src/object/enum.cpp -index 293e7058991721f60c5b1ff89fcd2406a11531fb..5753b32e0742605ade7d929f2e766a78e3cfda7f 100644 ---- a/src/object/enum.cpp -+++ b/src/object/enum.cpp -@@ -113,7 +113,6 @@ static PyTypeObject enum_type_object = { - #if PY_VERSION_HEX < 0x03000000 - | Py_TPFLAGS_CHECKTYPES - #endif -- | Py_TPFLAGS_HAVE_GC - | Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ From a12670046f02e957c2410587221ab1af43e78f39 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Wed, 15 Jul 2026 20:22:47 +0800 Subject: [PATCH 12/26] fix scikit-build --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 667568ec..08442a18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ requires = ["scikit-build-core", "pybind11"] build-backend = "scikit_build_core.build" [tool.scikit-build] -cmake.verbose = true +build.verbose = true logging.level = "DEBUG" wheel.packages = ["src/pythonlib/opencamlib"] From 2171fad0837721cfce7621ea43d9049bf658a565 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Fri, 31 Jul 2026 22:06:18 +0800 Subject: [PATCH 13/26] Add py::keep_alive so we can do `waterline.setCutter(ocl.CylCutter())` without segfault --- src/pythonlib/ocl_algo.cpp | 16 ++++++++-------- src/pythonlib/ocl_dropcutter.cpp | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/pythonlib/ocl_algo.cpp b/src/pythonlib/ocl_algo.cpp index a8a0f93a..c46ccb55 100644 --- a/src/pythonlib/ocl_algo.cpp +++ b/src/pythonlib/ocl_algo.cpp @@ -54,8 +54,8 @@ void export_algo(py::module& m) { py::class_(m, "BatchPushCutter") .def(py::init<>()) .def("run", &BatchPushCutter::run) - .def("setSTL", &BatchPushCutter::setSTL) - .def("setCutter", &BatchPushCutter::setCutter) + .def("setSTL", &BatchPushCutter::setSTL, py::keep_alive<1, 2>()) + .def("setCutter", &BatchPushCutter::setCutter, py::keep_alive<1, 2>()) .def("setThreads", &BatchPushCutter::setThreads) .def("appendFiber", &BatchPushCutter::appendFiber) .def("getOverlapTriangles", &BatchPushCutter::getOverlapTriangles) @@ -70,8 +70,8 @@ void export_algo(py::module& m) { py::class_(m, "Waterline") .def(py::init<>()) - .def("setCutter", &Waterline::setCutter) - .def("setSTL", &Waterline::setSTL) + .def("setCutter", &Waterline::setCutter, py::keep_alive<1, 2>()) + .def("setSTL", &Waterline::setSTL, py::keep_alive<1, 2>()) .def("setZ", &Waterline::setZ) .def("setSampling", &Waterline::setSampling) .def("run", &Waterline::run) @@ -85,8 +85,8 @@ void export_algo(py::module& m) { py::class_(m, "AdaptiveWaterline") .def(py::init<>()) - .def("setCutter", &AdaptiveWaterline::setCutter) - .def("setSTL", &AdaptiveWaterline::setSTL) + .def("setCutter", &AdaptiveWaterline::setCutter, py::keep_alive<1, 2>()) + .def("setSTL", &AdaptiveWaterline::setSTL, py::keep_alive<1, 2>()) .def("setZ", &AdaptiveWaterline::setZ) .def("setSampling", &AdaptiveWaterline::setSampling) .def("setMinSampling", &AdaptiveWaterline::setMinSampling) @@ -138,8 +138,8 @@ void export_algo(py::module& m) { .def("run", &clsurf::CutterLocationSurface::run) .def("setMinSampling", &clsurf::CutterLocationSurface::setMinSampling) .def("setSampling", &clsurf::CutterLocationSurface::setSampling) - .def("setSTL", &clsurf::CutterLocationSurface::setSTL) - .def("setCutter", &clsurf::CutterLocationSurface::setCutter) + .def("setSTL", &clsurf::CutterLocationSurface::setSTL, py::keep_alive<1, 2>()) + .def("setCutter", &clsurf::CutterLocationSurface::setCutter, py::keep_alive<1, 2>()) .def("getVertices", &clsurf::CutterLocationSurface::getVertices) .def("getEdges", &clsurf::CutterLocationSurface::getEdges) .def("__str__", &clsurf::CutterLocationSurface::str); diff --git a/src/pythonlib/ocl_dropcutter.cpp b/src/pythonlib/ocl_dropcutter.cpp index ce13305a..148b7d83 100644 --- a/src/pythonlib/ocl_dropcutter.cpp +++ b/src/pythonlib/ocl_dropcutter.cpp @@ -38,8 +38,8 @@ void export_dropcutter(py::module_& m) { .def(py::init<>()) .def("run", &BatchDropCutter::run) .def("getCLPoints", &BatchDropCutter::getCLPoints) - .def("setSTL", &BatchDropCutter::setSTL) - .def("setCutter", &BatchDropCutter::setCutter) + .def("setSTL", &BatchDropCutter::setSTL, py::keep_alive<1, 2>()) + .def("setCutter", &BatchDropCutter::setCutter, py::keep_alive<1, 2>()) .def("setThreads", &BatchDropCutter::setThreads) .def("getThreads", &BatchDropCutter::getThreads) .def("appendPoint", &BatchDropCutter::appendPoint) @@ -52,10 +52,10 @@ void export_dropcutter(py::module_& m) { .def(py::init<>()) .def("run", &PathDropCutter::run) .def("getCLPoints", &PathDropCutter::getCLPoints) - .def("setCutter", &PathDropCutter::setCutter) - .def("setSTL", &PathDropCutter::setSTL) + .def("setCutter", &PathDropCutter::setCutter, py::keep_alive<1, 2>()) + .def("setSTL", &PathDropCutter::setSTL, py::keep_alive<1, 2>()) .def("setSampling", &PathDropCutter::setSampling) - .def("setPath", &PathDropCutter::setPath) + .def("setPath", &PathDropCutter::setPath, py::keep_alive<1, 2>()) .def("getZ", &PathDropCutter::getZ) .def("setZ", &PathDropCutter::setZ) .def_property("minimumZ", &PathDropCutter::getZ, &PathDropCutter::setZ); @@ -64,13 +64,13 @@ void export_dropcutter(py::module_& m) { .def(py::init<>()) .def("run", &AdaptivePathDropCutter::run) .def("getCLPoints", &AdaptivePathDropCutter::getCLPoints) - .def("setCutter", &AdaptivePathDropCutter::setCutter) - .def("setSTL", &AdaptivePathDropCutter::setSTL) + .def("setCutter", &AdaptivePathDropCutter::setCutter, py::keep_alive<1, 2>()) + .def("setSTL", &AdaptivePathDropCutter::setSTL, py::keep_alive<1, 2>()) .def("setSampling", &AdaptivePathDropCutter::setSampling) .def("setMinSampling", &AdaptivePathDropCutter::setMinSampling) .def("setCosLimit", &AdaptivePathDropCutter::setCosLimit) .def("getSampling", &AdaptivePathDropCutter::getSampling) - .def("setPath", &AdaptivePathDropCutter::setPath) + .def("setPath", &AdaptivePathDropCutter::setPath, py::keep_alive<1, 2>()) .def("getZ", &AdaptivePathDropCutter::getZ) .def("setZ", &AdaptivePathDropCutter::setZ) .def_property("minimumZ", &AdaptivePathDropCutter::getZ, &AdaptivePathDropCutter::setZ); From bc11c1d32040932643f2375373919ce303ae7e32 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Fri, 31 Jul 2026 22:07:30 +0800 Subject: [PATCH 14/26] remove usage of to_array so pythonlib can use c++14 --- src/pythonlib/ocl_geometry.cpp | 11 ++++++++--- src/pythonlib/pythonlib.cmake | 2 -- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/pythonlib/ocl_geometry.cpp b/src/pythonlib/ocl_geometry.cpp index b0da1aa1..ac356f54 100644 --- a/src/pythonlib/ocl_geometry.cpp +++ b/src/pythonlib/ocl_geometry.cpp @@ -18,6 +18,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ +#include + #include #include #include @@ -108,10 +110,13 @@ void export_geometry(py::module_& m) { .def("cc", &CLPoint::getCC) .def("getCC", &CLPoint::getCC); - pyTriangle.def(py::init()) - .def("getPoints", [](const Triangle& t) { return std::to_array(t.p); }) + pyTriangle + .def(py::init()) + .def("getPoints", + [](const Triangle& t) { return std::array{t.p[0], t.p[1], t.p[2]}; }) .def("__str__", &ostream_str) - .def_property_readonly("p", [](const Triangle& t) { return std::to_array(t.p); }) + .def_property_readonly( + "p", [](const Triangle& t) { return std::array{t.p[0], t.p[1], t.p[2]}; }) .def_readonly("n", &Triangle::n); py::class_(m, "Bbox") diff --git a/src/pythonlib/pythonlib.cmake b/src/pythonlib/pythonlib.cmake index efffd9e5..66ab714c 100644 --- a/src/pythonlib/pythonlib.cmake +++ b/src/pythonlib/pythonlib.cmake @@ -1,5 +1,3 @@ -set(CMAKE_CXX_STANDARD 20) - find_package(Python3 COMPONENTS Interpreter Development.Module REQUIRED) if(Python3_FOUND) message(STATUS "Found Python: " ${Python3_VERSION}) From 6850a6c51df4e6358851ecd6fe25d816f8bce8b8 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Sat, 1 Aug 2026 15:05:09 +0800 Subject: [PATCH 15/26] fix: correct syntax in str() override for MillingCutter_py --- src/pythonlib/millingcutter_py.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pythonlib/millingcutter_py.hpp b/src/pythonlib/millingcutter_py.hpp index ef278d90..dd159819 100644 --- a/src/pythonlib/millingcutter_py.hpp +++ b/src/pythonlib/millingcutter_py.hpp @@ -48,7 +48,7 @@ class MillingCutter_py : public MillingCutter { PYBIND11_OVERRIDE(MillingCutter*, MillingCutter, offsetCutter, d); } - std::string str() const override { PYBIND11_OVERRIDE(std::string, MillingCutter, str); } + std::string str() const override { PYBIND11_OVERRIDE(std::string, MillingCutter, str,); } }; } // end namespace ocl From 1d37ecd824d110a21a0acbf5235d537866421586 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 3 Aug 2026 01:49:50 +0800 Subject: [PATCH 16/26] Remove incomplete Python cutter override support The previous Boost.Python override support for `MillingCutter` was incomplete and effectively unusable: - `vertexDrop` was not virtual, so Python overrides were never called by `dropCutter()`. - Several required virtual functions (e.g. height/width queries) were not exposed, making it impossible to implement a complete custom cutter. - `offsetCutter()` returns an owning raw pointer, which is incompatible with Python object lifetime and could lead to dangling pointers or crashes. Even if these issues were addressed, overriding the low-level contact routines from Python would not be a practical or useful extension mechanism. The API was introduced incorrectly and is not known to have been used, so removing it does not introduce a compatibility concern. --- src/pythonlib/millingcutter_py.hpp | 56 ------------------------------ src/pythonlib/ocl_cutters.cpp | 4 +-- 2 files changed, 1 insertion(+), 59 deletions(-) delete mode 100644 src/pythonlib/millingcutter_py.hpp diff --git a/src/pythonlib/millingcutter_py.hpp b/src/pythonlib/millingcutter_py.hpp deleted file mode 100644 index dd159819..00000000 --- a/src/pythonlib/millingcutter_py.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* $Id$ - * - * Copyright (c) 2010 Anders Wallin (anders.e.e.wallin "at" gmail.com). - * - * This file is part of OpenCAMlib - * (see https://github.com/aewallin/opencamlib). - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . - */ - -#ifndef MILLING_CUTTER_PY_H -#define MILLING_CUTTER_PY_H - -#include - -#include "millingcutter.hpp" - -namespace ocl { - -class MillingCutter_py : public MillingCutter { -public: - using MillingCutter::MillingCutter; // inherit constructors if needed - - bool vertexDrop(CLPoint& cl, const Triangle& t) const { - PYBIND11_OVERRIDE(bool, MillingCutter, vertexDrop, cl, t); - } - - bool facetDrop(CLPoint& cl, const Triangle& t) const override { - PYBIND11_OVERRIDE(bool, MillingCutter, facetDrop, cl, t); - } - - bool edgeDrop(CLPoint& cl, const Triangle& t) const override { - PYBIND11_OVERRIDE(bool, MillingCutter, edgeDrop, cl, t); - } - - MillingCutter* offsetCutter(double d) const override { - PYBIND11_OVERRIDE(MillingCutter*, MillingCutter, offsetCutter, d); - } - - std::string str() const override { PYBIND11_OVERRIDE(std::string, MillingCutter, str,); } -}; - -} // end namespace ocl - -#endif // MILLING_CUTTER_PY_H diff --git a/src/pythonlib/ocl_cutters.cpp b/src/pythonlib/ocl_cutters.cpp index 9d557a64..7ca9a5ef 100644 --- a/src/pythonlib/ocl_cutters.cpp +++ b/src/pythonlib/ocl_cutters.cpp @@ -26,14 +26,12 @@ #include "conecutter.hpp" #include "cylcutter.hpp" #include "millingcutter.hpp" -#include "millingcutter_py.hpp" namespace py = pybind11; using namespace ocl; void export_cutters(py::module& m) { - py::class_(m, "MillingCutter") - .def(py::init<>()) + py::class_(m, "MillingCutter") .def("vertexDrop", &MillingCutter::vertexDrop) .def("facetDrop", &MillingCutter::facetDrop) .def("edgeDrop", &MillingCutter::edgeDrop) From 51ae05fc4432e931c155c909fcf6b157e177545b Mon Sep 17 00:00:00 2001 From: Koen Schmeets Date: Sat, 18 Jul 2026 12:48:16 +0200 Subject: [PATCH 17/26] Create venv for Python --- install.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/install.sh b/install.sh index e4a77b1e..84b50b20 100755 --- a/install.sh +++ b/install.sh @@ -419,14 +419,14 @@ get_python_executable() { build_pythonlib() { python_executable=$(get_python_executable) + ${python_executable} -m venv env + if [ "${determined_os}" = "windows" ]; then + source env/Scripts/activate + else + source env/bin/activate + fi if [ -n "${OCL_PYTHON_PIP_INSTALL}" ]; then ${python_executable} -m pip install scikit-build-core distlib pyproject_metadata - # ${python_executable} -m venv env - # if [ "${determined_os}" = "windows" ]; then - # source env/Scripts/activate - # else - # source env/bin/activate - # fi # forward cmake args export CMAKE_ARGS="${OCL_GENERATOR:+"-G ${OCL_GENERATOR} "}\ ${OCL_GENERATOR_PLATFORM:+"-A ${OCL_GENERATOR_PLATFORM} "}\ From 871983e8dedfb39ba4ad1351edcc1e6d858e3d92 Mon Sep 17 00:00:00 2001 From: Koen Schmeets Date: Sat, 18 Jul 2026 13:06:00 +0200 Subject: [PATCH 18/26] Install script and nodejs lib fixes --- install.sh | 86 +++++++++++++++++++++++++--------- src/nodejslib/nodejslib.cmake | 3 +- src/npmpackage/src/napi/ocl.ts | 5 +- 3 files changed, 68 insertions(+), 26 deletions(-) diff --git a/install.sh b/install.sh index 84b50b20..635d79f4 100755 --- a/install.sh +++ b/install.sh @@ -44,57 +44,92 @@ Options: --help Shows this help page EOF +} + +invalid_argument() { + echo "$1" >&2 exit 1 } +require_option_value() { + if [ "$#" -lt 2 ] || [ -z "$2" ] || [[ "$2" = --* ]]; then + invalid_argument "Missing value for $1" + fi +} + original_args="$*" while [[ "$#" -gt 0 ]]; do case $1 in --clean) OCL_CLEAN="1"; ;; - --build-library) OCL_BUILD_LIBRARY="$2"; shift ;; - --build-type) OCL_BUILD_TYPE="$2"; shift ;; - --platform) OCL_PLATFORM="$2"; shift ;; + --build-library) require_option_value "$@"; OCL_BUILD_LIBRARY="$2"; shift ;; + --build-type) require_option_value "$@"; OCL_BUILD_TYPE="$2"; shift ;; + --platform) require_option_value "$@"; OCL_PLATFORM="$2"; shift ;; --install-system-deps) OCL_INSTALL_SYSTEM_DEPS="1"; ;; --install-ci-deps) OCL_INSTALL_CI_DEPS="1"; ;; --disable-openmp) OCL_DISABLE_OPENMP="1"; ;; --install) OCL_INSTALL="1"; ;; --sudo-install) OCL_SUDO_INSTALL="1"; ;; - --install-prefix) OCL_INSTALL_PREFIX="$2"; shift ;; + --install-prefix) require_option_value "$@"; OCL_INSTALL_PREFIX="$2"; shift ;; --install-boost) OCL_INSTALL_BOOST="1"; ;; --install-boost-from-repo) OCL_INSTALL_BOOST_FROM_REPO="1"; ;; - --boost-prefix) OCL_BOOST_PREFIX="$2"; shift ;; - --macos-architecture) OCL_MACOS_ARCHITECTURE="$2"; shift ;; - --docker-image) OCL_DOCKER_IMAGE="$2"; shift ;; - --docker-before-install) OCL_DOCKER_IMAGE_BEFORE_INSTALL="$2"; shift ;; - --cmake-generator) OCL_GENERATOR="$2"; shift ;; - --cmake-generator-platform) OCL_GENERATOR_PLATFORM="$2"; shift ;; - --python-executable) OCL_PYTHON_EXECUTABLE="$2"; shift ;; - --python-prefix) OCL_PYTHON_PREFIX="$2"; shift ;; + --boost-prefix) require_option_value "$@"; OCL_BOOST_PREFIX="$2"; shift ;; + --macos-architecture) require_option_value "$@"; OCL_MACOS_ARCHITECTURE="$2"; shift ;; + --docker-image) require_option_value "$@"; OCL_DOCKER_IMAGE="$2"; shift ;; + --docker-before-install) require_option_value "$@"; OCL_DOCKER_IMAGE_BEFORE_INSTALL="$2"; shift ;; + --cmake-generator) require_option_value "$@"; OCL_GENERATOR="$2"; shift ;; + --cmake-generator-platform) require_option_value "$@"; OCL_GENERATOR_PLATFORM="$2"; shift ;; + --python-executable) require_option_value "$@"; OCL_PYTHON_EXECUTABLE="$2"; shift ;; + --python-prefix) require_option_value "$@"; OCL_PYTHON_PREFIX="$2"; shift ;; --python-pip-install) OCL_PYTHON_PIP_INSTALL="1"; ;; - --node-architecture) OCL_NODE_ARCH="$2"; shift ;; + --node-architecture) require_option_value "$@"; OCL_NODE_ARCH="$2"; shift ;; --test) OCL_TEST="1"; ;; - --help|--*) - echo $1 - print_help ;; - *) + --help) print_help; exit 0 ;; + --*) invalid_argument "Unknown option: $1" ;; + *) invalid_argument "Unexpected argument: $1" ;; esac shift done verify_args() { - if [ -n "${OCL_CLEAN}" ] && [ -z "${OCL_BUILD_LIBRARY}" ]; then + case "${OCL_BUILD_LIBRARY:-}" in + ""|cxx|nodejs|python|emscripten) ;; + *) invalid_argument "Invalid library type: ${OCL_BUILD_LIBRARY}" ;; + esac + + case "${OCL_BUILD_TYPE:-}" in + ""|debug|release) ;; + *) invalid_argument "Invalid build type: ${OCL_BUILD_TYPE}" ;; + esac + + case "${OCL_PLATFORM:-}" in + ""|windows|macos|linux) ;; + *) invalid_argument "Invalid platform: ${OCL_PLATFORM}" ;; + esac + + case "${OCL_MACOS_ARCHITECTURE:-}" in + ""|arm64|x86_64) ;; + *) invalid_argument "Invalid macOS architecture: ${OCL_MACOS_ARCHITECTURE}" ;; + esac + + if [ -n "${OCL_CLEAN:-}" ] && [ -z "${OCL_BUILD_LIBRARY:-}" ]; then echo "Cannot set --clean without building a library. add the --build-library [lib] option or remove the --clean option" exit 1 - elif [ -n "${OCL_BUILD_TYPE}" ] && [ -z "${OCL_BUILD_LIBRARY}" ]; then + elif [ -n "${OCL_BUILD_TYPE:-}" ] && [ -z "${OCL_BUILD_LIBRARY:-}" ]; then echo "Cannot set --build-type without building a library. add the --build-library [lib] option or remove the --build-type option" exit 1 - elif [ -n "${OCL_TEST}" ] && [ -z "${OCL_BUILD_LIBRARY}" ]; then + elif [ -n "${OCL_TEST:-}" ] && [ -z "${OCL_BUILD_LIBRARY:-}" ]; then echo "Cannot set --test without building a library. add the --build-library [lib] option or remove the --test option" exit 1 - elif [ -n "${OCL_DISABLE_OPENMP}" ] && [ -z "${OCL_BUILD_LIBRARY}" ]; then + elif [ -n "${OCL_DISABLE_OPENMP:-}" ] && [ -z "${OCL_BUILD_LIBRARY:-}" ]; then echo "Cannot set --disable-openmp without building a library. add the --build-library [lib] option or remove the --disable-openmp option" exit 1 - elif [ -n "${OCL_INSTALL_PREFIX}" ] && [ -z "${OCL_INSTALL}" ] && [ -z "${OCL_SUDO_INSTALL}" ]; then + elif { [ -n "${OCL_PYTHON_EXECUTABLE:-}" ] || [ -n "${OCL_PYTHON_PREFIX:-}" ] || [ -n "${OCL_PYTHON_PIP_INSTALL:-}" ]; } && [ "${OCL_BUILD_LIBRARY:-}" != "python" ]; then + invalid_argument "Python options require --build-library python" + elif [ -n "${OCL_NODE_ARCH:-}" ] && [ "${OCL_BUILD_LIBRARY:-}" != "nodejs" ]; then + invalid_argument "--node-architecture requires --build-library nodejs" + elif [ -n "${OCL_DOCKER_IMAGE_BEFORE_INSTALL:-}" ] && [ -z "${OCL_DOCKER_IMAGE:-}" ]; then + invalid_argument "--docker-before-install requires --docker-image" + elif [ -n "${OCL_INSTALL_PREFIX:-}" ] && [ -z "${OCL_INSTALL:-}" ] && [ -z "${OCL_SUDO_INSTALL:-}" ]; then echo "WARN: Settings --install-prefix without setting --install or --sudo-install. add --install or --sudo-install option or remove the --install-prefix option" fi } @@ -397,12 +432,17 @@ build_nodejslib() { } test_nodejslib() { + node_addon_path="${build_dir}/ocl.node" + if [ ! -f "${node_addon_path}" ]; then + invalid_argument "Cannot find compiled node.js library: ${node_addon_path}" + fi + export OCL_NODE_PATH="${node_addon_path}" cd "${project_dir}/src/npmpackage" npm install npm run build-node cd ../../examples/nodejs npm link ../../src/npmpackage - if [ "${build_type}" = "debug" ]; then + if [ "${build_type_lower}" = "debug" ]; then export DEBUG="1" fi node test.js diff --git a/src/nodejslib/nodejslib.cmake b/src/nodejslib/nodejslib.cmake index a39be700..5364673f 100644 --- a/src/nodejslib/nodejslib.cmake +++ b/src/nodejslib/nodejslib.cmake @@ -56,12 +56,13 @@ add_definitions(-DNAPI_VERSION=3) if(USE_OPENMP AND APPLE) # copy libomp into install directory install( - FILES ${OpenMP_omp_LIBRARY} + FILES ${OpenMP_CXX_LIBRARIES} DESTINATION "." PERMISSIONS OWNER_READ GROUP_READ WORLD_READ ) # fix loader path add_custom_command(TARGET ocl POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${OpenMP_CXX_LIBRARIES} $ COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change `otool -L $ | grep libomp | cut -d ' ' -f1 | xargs echo` "@loader_path/libomp.dylib" $ ) endif() diff --git a/src/npmpackage/src/napi/ocl.ts b/src/npmpackage/src/napi/ocl.ts index cc8a7e7e..46d12408 100644 --- a/src/npmpackage/src/napi/ocl.ts +++ b/src/npmpackage/src/napi/ocl.ts @@ -5,6 +5,7 @@ if (process.env.DEBUG) { const platform = process.platform === 'darwin' ? 'macos' : (process.platform === 'win32' ? 'windows' : 'linux') -const oclLib = require(__dirname + '/../../build/' + buildType + '/' + platform + '-nodejs-' + process.arch + '/ocl.node') +const oclPath = process.env.OCL_NODE_PATH || (__dirname + '/../../build/' + buildType + '/' + platform + '-nodejs-' + process.arch + '/ocl.node') +const oclLib = require(oclPath) -export default oclLib \ No newline at end of file +export default oclLib From 67fd0c0ea3246fa9415a2104d16657052bae9fc4 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Wed, 29 Jul 2026 00:40:40 +0800 Subject: [PATCH 19/26] install script: better support for Python venv and fix Docker argument handling --- install.sh | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/install.sh b/install.sh index 635d79f4..658b287f 100755 --- a/install.sh +++ b/install.sh @@ -75,7 +75,7 @@ while [[ "$#" -gt 0 ]]; do --boost-prefix) require_option_value "$@"; OCL_BOOST_PREFIX="$2"; shift ;; --macos-architecture) require_option_value "$@"; OCL_MACOS_ARCHITECTURE="$2"; shift ;; --docker-image) require_option_value "$@"; OCL_DOCKER_IMAGE="$2"; shift ;; - --docker-before-install) require_option_value "$@"; OCL_DOCKER_IMAGE_BEFORE_INSTALL="$2"; shift ;; + --docker-before-install) require_option_value "$@"; OCL_DOCKER_IMAGE_BEFORE_INSTALL="$2"; docker_before_install_argument="1"; shift ;; --cmake-generator) require_option_value "$@"; OCL_GENERATOR="$2"; shift ;; --cmake-generator-platform) require_option_value "$@"; OCL_GENERATOR_PLATFORM="$2"; shift ;; --python-executable) require_option_value "$@"; OCL_PYTHON_EXECUTABLE="$2"; shift ;; @@ -127,7 +127,7 @@ verify_args() { invalid_argument "Python options require --build-library python" elif [ -n "${OCL_NODE_ARCH:-}" ] && [ "${OCL_BUILD_LIBRARY:-}" != "nodejs" ]; then invalid_argument "--node-architecture requires --build-library nodejs" - elif [ -n "${OCL_DOCKER_IMAGE_BEFORE_INSTALL:-}" ] && [ -z "${OCL_DOCKER_IMAGE:-}" ]; then + elif [ -n "${docker_before_install_argument:-}" ] && [ -z "${OCL_DOCKER_IMAGE:-}" ]; then invalid_argument "--docker-before-install requires --docker-image" elif [ -n "${OCL_INSTALL_PREFIX:-}" ] && [ -z "${OCL_INSTALL:-}" ] && [ -z "${OCL_SUDO_INSTALL:-}" ]; then echo "WARN: Settings --install-prefix without setting --install or --sudo-install. add --install or --sudo-install option or remove the --install-prefix option" @@ -194,7 +194,7 @@ install_system_dependencies() { fi if [ "${OCL_BUILD_LIBRARY}" = "python" ]; then if [ -z "${OCL_PYTHON_EXECUTABLE}" ]; then - sudo apt install -y --no-install-recommends python3 + sudo apt install -y --no-install-recommends python3 python3-venv fi fi if [ "${OCL_BUILD_LIBRARY}" = "nodejs" ]; then @@ -457,16 +457,25 @@ get_python_executable() { echo "${OCL_PYTHON_EXECUTABLE:-"${python_executable_fallback}"}" } +get_python_env_executable() { + if [ "${determined_os}" = "windows" ]; then + echo "${project_dir}/env/Scripts/python.exe" + else + echo "${project_dir}/env/bin/python" + fi +} + build_pythonlib() { python_executable=$(get_python_executable) - ${python_executable} -m venv env - if [ "${determined_os}" = "windows" ]; then - source env/Scripts/activate - else - source env/bin/activate - fi + "${python_executable}" -m venv "${project_dir}/env" + if [ "${determined_os}" = "windows" ]; then + source "${project_dir}/env/Scripts/activate" + else + source "${project_dir}/env/bin/activate" + fi + python_executable=$(get_python_env_executable) if [ -n "${OCL_PYTHON_PIP_INSTALL}" ]; then - ${python_executable} -m pip install scikit-build-core distlib pyproject_metadata + "${python_executable}" -m pip install scikit-build-core distlib pyproject_metadata # forward cmake args export CMAKE_ARGS="${OCL_GENERATOR:+"-G ${OCL_GENERATOR} "}\ ${OCL_GENERATOR_PLATFORM:+"-A ${OCL_GENERATOR_PLATFORM} "}\ @@ -474,7 +483,7 @@ ${OCL_GENERATOR_PLATFORM:+"-A ${OCL_GENERATOR_PLATFORM} "}\ -D Boost_ADDITIONAL_VERSIONS=${boost_additional_versions} \ ${OCL_BOOST_PREFIX:+"-D BOOST_ROOT=${OCL_BOOST_PREFIX} "}" cd "${project_dir}" - ${python_executable} -m pip install --verbose . + "${python_executable}" -m pip install --verbose . else mkdir -p "${build_dir}" cd "${build_dir}" @@ -500,9 +509,9 @@ ${OCL_BOOST_PREFIX:+"-D BOOST_ROOT=${OCL_BOOST_PREFIX} "}" } test_pythonlib() { - python_executable=$(get_python_executable) + python_executable=$(get_python_env_executable) cd "${project_dir}/examples/python" - ${python_executable} test.py + "${python_executable}" test.py } build_emscriptenlib() { From 3f87e9e26f15165d451a4fbe7bf770b3b79cbfb1 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 3 Aug 2026 02:41:11 +0800 Subject: [PATCH 20/26] fix(install): use the active Python environment Stop creating and activating a project-local virtual environment. Install and test with the currently selected Python executable instead. --- install.sh | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/install.sh b/install.sh index 658b287f..715db4d5 100755 --- a/install.sh +++ b/install.sh @@ -29,7 +29,7 @@ Options: --python-executable Set a custom path (or name of) the Python executable (only valid when using --build-library python) --python-prefix Set the python prefix, this will be passed to CMake as Python3_ROOT_DIR, to make sure CMake is using the correct Python installation. (only valid when using --build-library python) - --python-pip-install Uses "pip install ." to compile and install the Python library (only valid when using --build-library python) + --python-pip-install Uses the current Python environment's "pip install ." to compile and install the Python library (only valid when using --build-library python) --platform Set the platform, for when auto-detection doesn't work (one of: windows, macos, linux) @@ -194,7 +194,7 @@ install_system_dependencies() { fi if [ "${OCL_BUILD_LIBRARY}" = "python" ]; then if [ -z "${OCL_PYTHON_EXECUTABLE}" ]; then - sudo apt install -y --no-install-recommends python3 python3-venv + sudo apt install -y --no-install-recommends python3 fi fi if [ "${OCL_BUILD_LIBRARY}" = "nodejs" ]; then @@ -457,23 +457,12 @@ get_python_executable() { echo "${OCL_PYTHON_EXECUTABLE:-"${python_executable_fallback}"}" } -get_python_env_executable() { - if [ "${determined_os}" = "windows" ]; then - echo "${project_dir}/env/Scripts/python.exe" - else - echo "${project_dir}/env/bin/python" - fi -} - build_pythonlib() { python_executable=$(get_python_executable) - "${python_executable}" -m venv "${project_dir}/env" - if [ "${determined_os}" = "windows" ]; then - source "${project_dir}/env/Scripts/activate" - else - source "${project_dir}/env/bin/activate" + if ! command_exists "${python_executable}"; then + invalid_argument "Cannot find Python executable: ${python_executable}" fi - python_executable=$(get_python_env_executable) + if [ -n "${OCL_PYTHON_PIP_INSTALL}" ]; then "${python_executable}" -m pip install scikit-build-core distlib pyproject_metadata # forward cmake args @@ -509,7 +498,7 @@ ${OCL_BOOST_PREFIX:+"-D BOOST_ROOT=${OCL_BOOST_PREFIX} "}" } test_pythonlib() { - python_executable=$(get_python_env_executable) + python_executable=$(get_python_executable) cd "${project_dir}/examples/python" "${python_executable}" test.py } From e468628136707083f0d6d456cba8560a58c16b2c Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 3 Aug 2026 02:44:41 +0800 Subject: [PATCH 21/26] change macos libomp bottle tag to sequoia --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 715db4d5..1ab7b2c1 100755 --- a/install.sh +++ b/install.sh @@ -255,9 +255,9 @@ install_ci_dependencies() { OCL_MACOS_ARCHITECTURE="${OCL_MACOS_ARCHITECTURE:-arm64}" # default to arm64 prettyprint "Downloading libomp for: " "${OCL_MACOS_ARCHITECTURE}" if [ "${OCL_MACOS_ARCHITECTURE}" = "arm64" ]; then - libomp_tar_loc=$(brew fetch --bottle-tag=arm64_sonoma libomp | grep -i downloaded | grep tar.gz | cut -f2 -d ":" | xargs echo) + libomp_tar_loc=$(brew fetch --bottle-tag=arm64_sequoia libomp | grep -i downloaded | grep tar.gz | cut -f2 -d ":" | xargs echo) else - libomp_tar_loc=$(brew fetch --bottle-tag=sonoma libomp | grep -i downloaded | grep tar.gz | cut -f2 -d ":" | xargs echo) + libomp_tar_loc=$(brew fetch --bottle-tag=sequoia libomp | grep -i downloaded | grep tar.gz | cut -f2 -d ":" | xargs echo) fi temp_dir="/tmp" cp "${libomp_tar_loc}" "${temp_dir}/libomp.tar.gz" From 40bf8fd30c1b50483c2cc363d9f58364bada5fbc Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 3 Aug 2026 02:49:05 +0800 Subject: [PATCH 22/26] workflow manual run --- .github/workflows/cd.yml | 1 + .github/workflows/test.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 9fc7a39e..c50033db 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -10,6 +10,7 @@ on: release: types: - published + workflow_dispatch: jobs: cxx: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f531fbe4..c273f3f5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,7 @@ on: - develop tags: - v* + workflow_dispatch: jobs: cxx: From c645bba7831ece7d05c24fb7118b89880fac7acf Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 3 Aug 2026 03:41:46 +0800 Subject: [PATCH 23/26] fix(install): update Homebrew libomp fetching for macOS architecture --- install.sh | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/install.sh b/install.sh index 1ab7b2c1..194976be 100755 --- a/install.sh +++ b/install.sh @@ -254,18 +254,19 @@ install_ci_dependencies() { elif [ "${determined_os}" = "macos" ]; then OCL_MACOS_ARCHITECTURE="${OCL_MACOS_ARCHITECTURE:-arm64}" # default to arm64 prettyprint "Downloading libomp for: " "${OCL_MACOS_ARCHITECTURE}" + brew_cache=$(brew --cache) if [ "${OCL_MACOS_ARCHITECTURE}" = "arm64" ]; then - libomp_tar_loc=$(brew fetch --bottle-tag=arm64_sequoia libomp | grep -i downloaded | grep tar.gz | cut -f2 -d ":" | xargs echo) + brew fetch --bottle-tag=arm64_tahoe libomp >/dev/null + libomp_tar_loc=$(find "${brew_cache}/downloads" -maxdepth 1 -name "*--libomp--*arm64_tahoe.bottle.tar.gz" -print | tail -n1) else - libomp_tar_loc=$(brew fetch --bottle-tag=sequoia libomp | grep -i downloaded | grep tar.gz | cut -f2 -d ":" | xargs echo) + arch -x86_64 brew fetch --bottle-tag=sonoma libomp >/dev/null + libomp_tar_loc=$(find "${brew_cache}/downloads" -maxdepth 1 -name "*--libomp--*sonoma.bottle.tar.gz" -print | tail -n1) fi - temp_dir="/tmp" - cp "${libomp_tar_loc}" "${temp_dir}/libomp.tar.gz" - mkdir "${temp_dir}/libomp" || true - tar -xzf "${temp_dir}/libomp.tar.gz" -C "${temp_dir}/libomp" - libomp_prefix=$(find "${temp_dir}/libomp/libomp" -depth 1 | head -1) - export OPENMP_PREFIX_MACOS="${temp_dir}/libomp/libomp/fixed" - mv "${libomp_prefix}" "${OPENMP_PREFIX_MACOS}" + [ -n "${libomp_tar_loc}" ] || invalid_argument "Failed to locate ${OCL_MACOS_ARCHITECTURE} libomp bottle in Homebrew cache" + cp "${libomp_tar_loc}" /tmp/libomp.tar.gz + mkdir -p /tmp/libomp + tar -xzf /tmp/libomp.tar.gz -C /tmp/libomp + export OPENMP_PREFIX_MACOS="$(find /tmp/libomp/libomp -mindepth 1 -maxdepth 1 -type d -print | head -n1)" fi } From 30ba5e177606ede6613ca9e525e96cb5e6ee0fb9 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Mon, 3 Aug 2026 03:45:59 +0800 Subject: [PATCH 24/26] use sequoia instead of tahoe --- install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 194976be..88ea5170 100755 --- a/install.sh +++ b/install.sh @@ -256,8 +256,8 @@ install_ci_dependencies() { prettyprint "Downloading libomp for: " "${OCL_MACOS_ARCHITECTURE}" brew_cache=$(brew --cache) if [ "${OCL_MACOS_ARCHITECTURE}" = "arm64" ]; then - brew fetch --bottle-tag=arm64_tahoe libomp >/dev/null - libomp_tar_loc=$(find "${brew_cache}/downloads" -maxdepth 1 -name "*--libomp--*arm64_tahoe.bottle.tar.gz" -print | tail -n1) + brew fetch --bottle-tag=arm64_sequoia libomp >/dev/null + libomp_tar_loc=$(find "${brew_cache}/downloads" -maxdepth 1 -name "*--libomp--*arm64_sequoia.bottle.tar.gz" -print | tail -n1) else arch -x86_64 brew fetch --bottle-tag=sonoma libomp >/dev/null libomp_tar_loc=$(find "${brew_cache}/downloads" -maxdepth 1 -name "*--libomp--*sonoma.bottle.tar.gz" -print | tail -n1) From 9c4c317026f89837b710210c2cf847f48e107d2d Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Wed, 5 Aug 2026 13:07:40 +0800 Subject: [PATCH 25/26] update readme --- README.rst | 58 +++++++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/README.rst b/README.rst index eb35949e..c694a42b 100644 --- a/README.rst +++ b/README.rst @@ -68,7 +68,7 @@ OpenCAMLib provides pre-compiled C++, Node.js and Python libraries for the follo | **Linux** | x86_64 / aarch64 | +-------------+------------------+ -- The Python library is called ``opencamlib`` and is hosted on PyPi (pypi.org), precompiled libraries are available for Python v3.7 up to v3.11. +- The Python library is called ``opencamlib`` and is hosted on PyPi (pypi.org), precompiled libraries are available for Python v3.9 up to v3.14. - The Node.js + emscripten library is called ``@opencamlib/opencamlib`` and is hosted on npm (npmjs.org), precompiled libraries are available for Node-API v3 and up. - The C++ library is called ``libocl`` and is hosted on our Github Releases page. @@ -137,13 +137,7 @@ Having trouble with a pre-compiled library? Please report it to us. If there are no pre-compiled libraries for your platform or architecture, or want to customize or package opencamlib, this is for you. OpenCAMLib uses functionality from a library called Boost. -For the Python library it uses an extra library called Boost.Python. - -Only the Python bindings need Boost to be **compiled** (with Boost.Python). -All other libraries **DO NOT** need Boost to be compiled, in those cases, a headers only version will suffice. -So, if you are not compiling the Python libraries, simply download Boost, extract it into a folder, and tell CMake where to look for it. - -Make sure to download Boost from the boost.org downloads page, if you download it from github, you have to make sure to install the git submodules **and** build the headers. +Only Boost headers are required; Boost does not need to be compiled. We provide a ``install.sh`` script that helps with installation of dependencies and building OpenCAMLib libraries, you might want to take a look at it first. You can run ``./install.sh --help`` to look at the available options, or inspect it's source code to find out more. @@ -157,7 +151,10 @@ To compile OpenCAMLib, you need: - **C++ compiler** (It should at least support C++ 14) - **Git** (This is used for cloning the repository, and the emscripten SDK) - **CMake** (At least version 3.15) -- **Boost** (When compiling the Python library, you have to **compile** Boost.Python for your Python version after installation) +- **Boost** headers + +Building the Python bindings additionally requires Python development headers. +pybind11 is installed automatically when building the package with pip. At this time of writing, here are the packages to install: @@ -166,14 +163,14 @@ Ubuntu Dependencies .. code-block:: shell - sudo apt install -y git cmake curl build-essential libboost-dev + sudo apt install -y git cmake curl build-essential libboost-dev python3-dev python3-pip macOS Dependencies ------------------ .. code-block:: shell - brew install git cmake curl boost python@3.11 boost-python3 + brew install git cmake curl boost python Windows Dependencies -------------------- @@ -272,42 +269,23 @@ Next, use cmake-js to compile the library: Building for Python =================== -The Python library can be compiled similarly to the C++ example above, however, this time Boost.Python has to be compiled first. -Most systems have Boost.Python available as a download, but only for a specific Python version only (usually the latest Python version). -These might work if you are using Python from the same package provider, but, unfortunately, this is not a very reliable method, so compiling them yourself is usually the best option. - -First, download and extract Boost: +The Python bindings use pybind11 and can be built and installed directly with pip. +From the repository root, run: .. code-block:: shell - curl "https://boostorg.jfrog.io/artifactory/main/release/1.80.0/source/boost_1_80_0.tar.gz" --output "boost_1_80_0.tar.gz" --location - tar -zxf boost_1_80_0.tar.gz -C /tmp/boost - cd /tmp/boost/boost_1_80_0 + python -m pip install . + +pip creates an isolated build environment and installs scikit-build-core and pybind11 as declared build dependencies. +Boost is still required in the system. -Now we can compile it: +The package includes a ``py.typed`` marker and type information for the ``opencamlib.ocl`` extension, so Python type checkers and editors can use the bundled API signatures. +To generate the type stubs, you can use the ``pybind11-stubgen`` tool: .. code-block:: shell - echo "using python ;" > ./user-config.jam - ./bootstrap.sh - ./b2 \ - -a \ - threading="multi" \ - -j4 \ - variant="release" \ - link="static" \ - address-model="64" \ - architecture="x86" \ - --layout="system" \ - --with-python \ - --user-config="./user-config.jam" \ - cxxflags="-fPIC" \ - stage - -Note that you can customize the user-config.jam file to point it to your Python installation -(see: https://www.boost.org/doc/libs/1_78_0/libs/python/doc/html/building/configuring_boost_build.html). -You should also specify the correct architecture and address-model. -On windows, make sure to use windows style paths, e.g. ``C:\\path\\to\\Python`` + python -m pip install pybind11-stubgen + pybind11-stubgen opencamlib -o src/pythonlib/ ***** Usage From e6808d35b6921707be4797322331f9e90f651434 Mon Sep 17 00:00:00 2001 From: Chen Chen Date: Thu, 6 Aug 2026 00:29:03 +0800 Subject: [PATCH 26/26] refine binding - add GIL release - remove CCType package level export - change some python constructor signature to match cpp --- src/pythonlib/ocl_algo.cpp | 22 +++++++++++----------- src/pythonlib/ocl_cutters.cpp | 4 ++-- src/pythonlib/ocl_dropcutter.cpp | 6 +++--- src/pythonlib/ocl_geometry.cpp | 15 +++++++-------- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/pythonlib/ocl_algo.cpp b/src/pythonlib/ocl_algo.cpp index c46ccb55..a4bfd389 100644 --- a/src/pythonlib/ocl_algo.cpp +++ b/src/pythonlib/ocl_algo.cpp @@ -43,7 +43,7 @@ void export_algo(py::module& m) { py::class_(m, "ZigZag") .def(py::init<>()) - .def("run", &ZigZag::run) + .def("run", &ZigZag::run, py::call_guard()) .def("setDirection", &ZigZag::setDirection) .def("setOrigin", &ZigZag::setOrigin) .def("setStepOver", &ZigZag::setStepOver) @@ -53,7 +53,7 @@ void export_algo(py::module& m) { py::class_(m, "BatchPushCutter") .def(py::init<>()) - .def("run", &BatchPushCutter::run) + .def("run", &BatchPushCutter::run, py::call_guard()) .def("setSTL", &BatchPushCutter::setSTL, py::keep_alive<1, 2>()) .def("setCutter", &BatchPushCutter::setCutter, py::keep_alive<1, 2>()) .def("setThreads", &BatchPushCutter::setThreads) @@ -74,8 +74,8 @@ void export_algo(py::module& m) { .def("setSTL", &Waterline::setSTL, py::keep_alive<1, 2>()) .def("setZ", &Waterline::setZ) .def("setSampling", &Waterline::setSampling) - .def("run", &Waterline::run) - .def("run2", &Waterline::run2) + .def("run", &Waterline::run, py::call_guard()) + .def("run2", &Waterline::run2, py::call_guard()) .def("reset", &Waterline::reset) .def("getLoops", &Waterline::getLoops) .def("setThreads", &Waterline::setThreads) @@ -90,8 +90,8 @@ void export_algo(py::module& m) { .def("setZ", &AdaptiveWaterline::setZ) .def("setSampling", &AdaptiveWaterline::setSampling) .def("setMinSampling", &AdaptiveWaterline::setMinSampling) - .def("run", &AdaptiveWaterline::run) - .def("run2", &AdaptiveWaterline::run2) + .def("run", &AdaptiveWaterline::run, py::call_guard()) + .def("run2", &AdaptiveWaterline::run2, py::call_guard()) .def("reset", &AdaptiveWaterline::reset) .def("getLoops", &AdaptiveWaterline::getLoops) .def("setThreads", &AdaptiveWaterline::setThreads) @@ -109,9 +109,9 @@ void export_algo(py::module& m) { py::class_(m, "Weave") .def("addFiber", &weave::Weave::addFiber) - .def("build", &weave::Weave::build) + .def("build", &weave::Weave::build, py::call_guard()) .def("printGraph", &weave::Weave::printGraph) - .def("face_traverse", &weave::Weave::face_traverse) + .def("face_traverse", &weave::Weave::face_traverse, py::call_guard()) .def("getVertices", &weave::Weave::getVertices) .def("getVerticesByType", &weave::Weave::getVerticesByType) .def("getCLVertices", [](const weave::Weave& w) { return w.getVerticesByType(weave::CL); }) @@ -130,12 +130,12 @@ void export_algo(py::module& m) { .def(py::init<>()) .def("addCLPoint", &LineCLFilter::addCLPoint) .def("setTolerance", &LineCLFilter::setTolerance) - .def("run", &LineCLFilter::run) + .def("run", &LineCLFilter::run, py::call_guard()) .def("getCLPoints", [](const LineCLFilter& f) { return f.clpoints; }); py::class_(m, "CutterLocationSurface") .def(py::init()) - .def("run", &clsurf::CutterLocationSurface::run) + .def("run", &clsurf::CutterLocationSurface::run, py::call_guard()) .def("setMinSampling", &clsurf::CutterLocationSurface::setMinSampling) .def("setSampling", &clsurf::CutterLocationSurface::setSampling) .def("setSTL", &clsurf::CutterLocationSurface::setSTL, py::keep_alive<1, 2>()) @@ -147,7 +147,7 @@ void export_algo(py::module& m) { py::class_(m, "TSPSolver") .def(py::init<>()) .def("addPoint", &tsp::TSPSolver::addPoint) - .def("run", &tsp::TSPSolver::run) + .def("run", &tsp::TSPSolver::run, py::call_guard()) .def("getOutput", &tsp::TSPSolver::getOutput) .def("getLength", &tsp::TSPSolver::getLength) .def("reset", &tsp::TSPSolver::reset); diff --git a/src/pythonlib/ocl_cutters.cpp b/src/pythonlib/ocl_cutters.cpp index 7ca9a5ef..749bfb1e 100644 --- a/src/pythonlib/ocl_cutters.cpp +++ b/src/pythonlib/ocl_cutters.cpp @@ -45,11 +45,11 @@ void export_cutters(py::module& m) { py::class_(m, "CylCutter") .def(py::init()) - .def("dropCutterSTL", &CylCutter::dropCutterSTL); + .def("dropCutterSTL", &CylCutter::dropCutterSTL, py::call_guard()); py::class_(m, "BallCutter") .def(py::init()) - .def("dropCutterSTL", &BallCutter::dropCutterSTL); + .def("dropCutterSTL", &BallCutter::dropCutterSTL, py::call_guard()); py::class_(m, "BullCutter").def(py::init()); diff --git a/src/pythonlib/ocl_dropcutter.cpp b/src/pythonlib/ocl_dropcutter.cpp index 148b7d83..f378fc62 100644 --- a/src/pythonlib/ocl_dropcutter.cpp +++ b/src/pythonlib/ocl_dropcutter.cpp @@ -36,7 +36,7 @@ using namespace ocl; void export_dropcutter(py::module_& m) { py::class_(m, "BatchDropCutter") .def(py::init<>()) - .def("run", &BatchDropCutter::run) + .def("run", &BatchDropCutter::run, py::call_guard()) .def("getCLPoints", &BatchDropCutter::getCLPoints) .def("setSTL", &BatchDropCutter::setSTL, py::keep_alive<1, 2>()) .def("setCutter", &BatchDropCutter::setCutter, py::keep_alive<1, 2>()) @@ -50,7 +50,7 @@ void export_dropcutter(py::module_& m) { py::class_(m, "PathDropCutter") .def(py::init<>()) - .def("run", &PathDropCutter::run) + .def("run", &PathDropCutter::run, py::call_guard()) .def("getCLPoints", &PathDropCutter::getCLPoints) .def("setCutter", &PathDropCutter::setCutter, py::keep_alive<1, 2>()) .def("setSTL", &PathDropCutter::setSTL, py::keep_alive<1, 2>()) @@ -62,7 +62,7 @@ void export_dropcutter(py::module_& m) { py::class_(m, "AdaptivePathDropCutter") .def(py::init<>()) - .def("run", &AdaptivePathDropCutter::run) + .def("run", &AdaptivePathDropCutter::run, py::call_guard()) .def("getCLPoints", &AdaptivePathDropCutter::getCLPoints) .def("setCutter", &AdaptivePathDropCutter::setCutter, py::keep_alive<1, 2>()) .def("setSTL", &AdaptivePathDropCutter::setSTL, py::keep_alive<1, 2>()) diff --git a/src/pythonlib/ocl_geometry.cpp b/src/pythonlib/ocl_geometry.cpp index ac356f54..9ac15243 100644 --- a/src/pythonlib/ocl_geometry.cpp +++ b/src/pythonlib/ocl_geometry.cpp @@ -48,7 +48,7 @@ void export_geometry(py::module_& m) { .def(py::init<>()) .def(py::init()) .def(py::init()) - .def(py::init()) + .def(py::init()) .def(py::self * double()) .def(double() * py::self) .def(py::self - py::self) @@ -91,19 +91,18 @@ void export_geometry(py::module_& m) { .value("FACET", FACET) .value("FACET_TIP", FACET_TIP) .value("FACET_CYL", FACET_CYL) - .value("ERROR", ERROR) - .export_values(); + .value("ERROR", ERROR); py::class_(m, "CCPoint") .def(py::init<>()) - .def(py::init()) + .def(py::init()) .def(py::init()) .def("__str__", &CCPoint::str) .def_readwrite("type", &CCPoint::type); py::class_(m, "CLPoint") .def(py::init<>()) - .def(py::init()) + .def(py::init()) .def(py::init()) .def(py::init()) .def("__str__", &CLPoint::str) @@ -156,13 +155,13 @@ void export_geometry(py::module_& m) { py::class_(m, "Line") .def(py::init()) - .def(py::init()) + .def(py::init()) .def_readwrite("p1", &Line::p1) .def_readwrite("p2", &Line::p2); py::class_(m, "Arc") .def(py::init()) - .def(py::init()) + .def(py::init()) .def_readwrite("p1", &Arc::p1) .def_readwrite("p2", &Arc::p2) .def_readwrite("c", &Arc::c) @@ -175,7 +174,7 @@ void export_geometry(py::module_& m) { py::class_(m, "Path") .def(py::init<>()) - .def(py::init()) + .def(py::init()) .def("getSpans", [](const Path& p) { py::list spans;