diff --git a/easy3d/core/graph.h b/easy3d/core/graph.h index d43b6406..a239ec94 100644 --- a/easy3d/core/graph.h +++ b/easy3d/core/graph.h @@ -47,7 +47,7 @@ namespace easy3d { * https://opensource.cit-ec.de/projects/surface_mesh */ - class Graph : public virtual Model + class Graph : public Model { public: //------------------------------------------------------ topology types diff --git a/easy3d/core/point_cloud.h b/easy3d/core/point_cloud.h index 094271a4..1d14bec3 100644 --- a/easy3d/core/point_cloud.h +++ b/easy3d/core/point_cloud.h @@ -41,7 +41,7 @@ namespace easy3d { * This implementation is inspired by Surface_mesh * https://opensource.cit-ec.de/projects/surface_mesh */ - class PointCloud : public virtual Model + class PointCloud : public Model { public: //------------------------------------------------------ topology types diff --git a/easy3d/core/poly_mesh.h b/easy3d/core/poly_mesh.h index d06c3fdd..e73e6dc9 100644 --- a/easy3d/core/poly_mesh.h +++ b/easy3d/core/poly_mesh.h @@ -46,7 +46,7 @@ namespace easy3d { * https://opensource.cit-ec.de/projects/surface_mesh */ - class PolyMesh : public virtual Model + class PolyMesh : public Model { public: //------------------------------------------------------ topology types diff --git a/easy3d/core/surface_mesh.h b/easy3d/core/surface_mesh.h index 8129268d..a3c07eba 100644 --- a/easy3d/core/surface_mesh.h +++ b/easy3d/core/surface_mesh.h @@ -48,7 +48,7 @@ namespace easy3d { * \sa SurfaceMeshBuilder. */ - class SurfaceMesh : public virtual Model + class SurfaceMesh : public Model { public: //------------------------------------------------------ topology types diff --git a/easy3d/util/version.h b/easy3d/util/version.h index dc7c4192..53c71eac 100644 --- a/easy3d/util/version.h +++ b/easy3d/util/version.h @@ -59,7 +59,7 @@ namespace easy3d { #define EASY3D_VERSION_NR 1020504 /// Easy3D release date, in the format YYYYMMDD. -#define EASY3D_RELEASE_DATE 20241231 +#define EASY3D_RELEASE_DATE 20250101 #endif // EASY3D_UTIL_VERSION_H diff --git a/python/bindings/easy3d.cpp b/python/bindings/easy3d.cpp index 0371e725..48a659d9 100644 --- a/python/bindings/easy3d.cpp +++ b/python/bindings/easy3d.cpp @@ -5,22 +5,22 @@ #include +void bind_easy3d_core_vec(pybind11::module_ &m); void bind_easy3d_core_box(pybind11::module_ &m); void bind_easy3d_core_constant(pybind11::module_ &m); -void bind_easy3d_core_graph(pybind11::module_ &m); void bind_easy3d_core_line(pybind11::module_ &m); +void bind_easy3d_core_quat(pybind11::module_ &m); +void bind_easy3d_core_random(pybind11::module_ &m); void bind_easy3d_core_mat(pybind11::module_ &m); -void bind_easy3d_core_model(pybind11::module_ &m); void bind_easy3d_core_plane(pybind11::module_ &m); +void bind_easy3d_core_types(pybind11::module_ &m); +void bind_easy3d_core_model(pybind11::module_ &m); +void bind_easy3d_core_property(pybind11::module_ &m); +void bind_easy3d_core_graph(pybind11::module_ &m); void bind_easy3d_core_point_cloud(pybind11::module_ &m); void bind_easy3d_core_poly_mesh(pybind11::module_ &m); -void bind_easy3d_core_property(pybind11::module_ &m); -void bind_easy3d_core_quat(pybind11::module_ &m); -void bind_easy3d_core_random(pybind11::module_ &m); void bind_easy3d_core_surface_mesh(pybind11::module_ &m); void bind_easy3d_core_surface_mesh_builder(pybind11::module_ &m); -void bind_easy3d_core_types(pybind11::module_ &m); -void bind_easy3d_core_vec(pybind11::module_ &m); void bind_easy3d_algo_collider(pybind11::module_ &m); void bind_easy3d_algo_delaunay(pybind11::module_ &m); @@ -95,21 +95,21 @@ void bind_easy3d_video_video_encoder(pybind11::module_ &m); // Submodule declarations void bind_core(pybind11::module_ &m) { + bind_easy3d_core_vec(m); bind_easy3d_core_box(m); bind_easy3d_core_constant(m); bind_easy3d_core_line(m); - bind_easy3d_core_mat(m); - bind_easy3d_core_plane(m); - bind_easy3d_core_property(m); bind_easy3d_core_quat(m); bind_easy3d_core_random(m); + bind_easy3d_core_mat(m); + bind_easy3d_core_plane(m); bind_easy3d_core_types(m); - bind_easy3d_core_vec(m); bind_easy3d_core_model(m); + bind_easy3d_core_property(m); bind_easy3d_core_graph(m); - bind_easy3d_core_surface_mesh(m); bind_easy3d_core_point_cloud(m); + bind_easy3d_core_surface_mesh(m); bind_easy3d_core_poly_mesh(m); bind_easy3d_core_surface_mesh_builder(m); diff --git a/python/bindings/easy3d/core/model.cpp b/python/bindings/easy3d/core/model.cpp index 7db7e859..1c2bd015 100644 --- a/python/bindings/easy3d/core/model.cpp +++ b/python/bindings/easy3d/core/model.cpp @@ -17,6 +17,54 @@ PYBIND11_MAKE_OPAQUE(std::shared_ptr) #endif +//struct PyCallBack_easy3d_Model : public easy3d::Model { +// using easy3d::Model::Model; // Inherit constructors +// +// // Override pure virtual function `points()` +// std::vector& points() override { +// pybind11::gil_scoped_acquire gil; +// pybind11::function overload = pybind11::get_overload(static_cast(this), "points"); +// if (overload) { +// auto o = overload.operator()(); +// if (pybind11::detail::cast_is_temporary_value_reference&>::value) { +// static pybind11::detail::override_caster_t&> caster; +// return pybind11::detail::cast_ref&>(std::move(o), caster); +// } +// return pybind11::detail::cast_safe&>(std::move(o)); +// } +// pybind11::pybind11_fail("Tried to call pure virtual function \"Model::points\""); +// } +// +// const std::vector& points() const override { +// pybind11::gil_scoped_acquire gil; +// pybind11::function overload = pybind11::get_overload(static_cast(this), "points"); +// if (overload) { +// auto o = overload.operator()(); +// if (pybind11::detail::cast_is_temporary_value_reference&>::value) { +// static pybind11::detail::override_caster_t&> caster; +// return pybind11::detail::cast_ref&>(std::move(o), caster); +// } +// return pybind11::detail::cast_safe&>(std::move(o)); +// } +// pybind11::pybind11_fail("Tried to call pure virtual function \"Model::points\""); +// } +// +// void property_stats(std::ostream& output) const override { +// pybind11::gil_scoped_acquire gil; +// pybind11::function overload = pybind11::get_overload(static_cast(this), "property_stats"); +// if (overload) { +// auto o = overload.operator()(output); +// if (pybind11::detail::cast_is_temporary_value_reference::value) { +// static pybind11::detail::override_caster_t caster; +// return pybind11::detail::cast_ref(std::move(o), caster); +// } +// return pybind11::detail::cast_safe(std::move(o)); +// } +// pybind11::pybind11_fail("Tried to call pure virtual function \"Model::property_stats\""); +// } +// +//}; + void bind_easy3d_core_model(pybind11::module_& m) { diff --git a/python/bindings/easy3d/viewer/multi_viewer.cpp b/python/bindings/easy3d/viewer/multi_viewer.cpp index 9a0d32e2..f22e4762 100644 --- a/python/bindings/easy3d/viewer/multi_viewer.cpp +++ b/python/bindings/easy3d/viewer/multi_viewer.cpp @@ -1,8 +1,5 @@ #include -#include -#include -#include -#include +#include #include #include #include @@ -374,74 +371,14 @@ void bind_easy3d_viewer_multi_viewer(pybind11::module_& m) cl.def( pybind11::init( [](int const & a0, int const & a1){ return new easy3d::MultiViewer(a0, a1); }, [](int const & a0, int const & a1){ return new PyCallBack_easy3d_MultiViewer(a0, a1); } ), "doc"); cl.def( pybind11::init(), pybind11::arg("rows"), pybind11::arg("cols"), pybind11::arg("title") ); -// cl.def( pybind11::init( [](PyCallBack_easy3d_MultiViewer const &o){ return new PyCallBack_easy3d_MultiViewer(o); } ) ); -// cl.def( pybind11::init( [](easy3d::MultiViewer const &o){ return new easy3d::MultiViewer(o); } ) ); - - cl.def("add_model", [](easy3d::MultiViewer& self, const std::string& file_name, bool create_default_drawables = true) - { - return self.add_model(file_name, create_default_drawables); - }, - pybind11::arg("file_name"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add a model from a file to the viewer."); - cl.def("add_model", [](easy3d::MultiViewer& self, std::shared_ptr point_cloud, bool create_default_drawables = true) - { - return self.add_model(point_cloud, create_default_drawables); - }, - pybind11::arg("point_cloud"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing point cloud to the viewer."); - cl.def("add_model", [](easy3d::MultiViewer& self, std::shared_ptr surface_mesh, bool create_default_drawables = true) - { - return self.add_model(surface_mesh, create_default_drawables); - }, - pybind11::arg("surface_mesh"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing surface mesh to the viewer." - ); - cl.def("add_model", [](easy3d::MultiViewer& self, std::shared_ptr graph, bool create_default_drawables = true) - { - return self.add_model(graph, create_default_drawables); - }, - pybind11::arg("graph"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing graph to the viewer." - ); - cl.def("add_model", [](easy3d::MultiViewer& self, std::shared_ptr poly_mesh, bool create_default_drawables = true) - { - return self.add_model(poly_mesh, create_default_drawables); - }, - pybind11::arg("poly_mesh"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing polyhedral mesh to the viewer." - ); - - // Assign Model to specific view (overloaded) - cl.def("assign", [](easy3d::MultiViewer &self, int row, int col, const easy3d::PointCloud *point_cloud) { - self.assign(row, col, point_cloud); - }, - "Assign a point cloud to the view at position (row, col)", - pybind11::arg("row"), pybind11::arg("col"), pybind11::arg("point_cloud") - ); - cl.def("assign", [](easy3d::MultiViewer &self, int row, int col, const easy3d::SurfaceMesh *surface_mesh) { - self.assign(row, col, surface_mesh); - }, - "Assign a surface mesh to the view at position (row, col)", - pybind11::arg("row"), pybind11::arg("col"), pybind11::arg("surface_mesh") - ); - cl.def("assign", [](easy3d::MultiViewer &self, int row, int col, const easy3d::PolyMesh *poly_mesh) { - self.assign(row, col, poly_mesh); - }, - "Assign a polyhedral mesh to the view at position (row, col)", - pybind11::arg("row"), pybind11::arg("col"), pybind11::arg("poly_mesh") - ); - cl.def("assign", [](easy3d::MultiViewer &self, int row, int col, const easy3d::Graph *graph) { - self.assign(row, col, graph); + // Assign a model to specific view + cl.def("assign", [](easy3d::MultiViewer &self, int row, int col, const easy3d::Model *model) { + self.assign(row, col, model); }, - "Assign a graph to the view at position (row, col)", - pybind11::arg("row"), pybind11::arg("col"), pybind11::arg("graph") + "Assign a model to the view at position (row, col)", + pybind11::arg("row"), pybind11::arg("col"), pybind11::arg("model") ); - // Assign Drawable to specific view (overloaded) + // Assign a drawable to specific view cl.def("assign", [](easy3d::MultiViewer &self, int row, int col, const easy3d::Drawable *drawable) { self.assign(row, col, drawable); }, diff --git a/python/bindings/easy3d/viewer/offscreen.cpp b/python/bindings/easy3d/viewer/offscreen.cpp index fab6560d..bdd12bac 100644 --- a/python/bindings/easy3d/viewer/offscreen.cpp +++ b/python/bindings/easy3d/viewer/offscreen.cpp @@ -1,9 +1,5 @@ #include #include -#include -#include -#include -#include #include #include #include @@ -387,37 +383,30 @@ void bind_easy3d_viewer_offscreen(pybind11::module_& m) pybind11::arg("file_name"), pybind11::arg("create_default_drawables") = true, pybind11::return_value_policy::reference_internal, "Add a model from a file to the viewer."); - cl.def("add_model", [](easy3d::OffScreen& self, std::shared_ptr point_cloud, bool create_default_drawables = true) - { - return self.add_model(point_cloud, create_default_drawables); - }, - pybind11::arg("point_cloud"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing point cloud to the viewer."); - cl.def("add_model", [](easy3d::OffScreen& self, std::shared_ptr surface_mesh, bool create_default_drawables = true) - { - return self.add_model(surface_mesh, create_default_drawables); - }, - pybind11::arg("surface_mesh"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing surface mesh to the viewer." - ); - cl.def("add_model", [](easy3d::OffScreen& self, std::shared_ptr graph, bool create_default_drawables = true) - { - return self.add_model(graph, create_default_drawables); - }, - pybind11::arg("graph"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing graph to the viewer." - ); - cl.def("add_model", [](easy3d::OffScreen& self, std::shared_ptr poly_mesh, bool create_default_drawables = true) - { - return self.add_model(poly_mesh, create_default_drawables); - }, - pybind11::arg("poly_mesh"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing polyhedral mesh to the viewer." - ); + + cl.def("add_model", [](easy3d::OffScreen &self, std::shared_ptr model) { + return self.add_model(model); // Call the C++ function + }, pybind11::arg("model"), + pybind11::return_value_policy::automatic, + R"doc( + Add an existing model to the viewer to be visualized. + Parameters: + model (Model): The pointer to the model. + Returns: + Model: The pointer of the model added to the viewer. + )doc"); + + cl.def("add_drawable", [](easy3d::OffScreen &self, std::shared_ptr drawable) { + return self.add_drawable(drawable); // Call the C++ function + }, pybind11::arg("drawable"), + pybind11::return_value_policy::automatic, + R"doc( + Add a drawable to the viewer to be visualized. + Parameters: + drawable (Drawable): The pointer to the drawable. + Returns: + Drawable: The pointer of the drawable added to the viewer. + )doc"); cl.def("camera", (class easy3d::Camera* (easy3d::OffScreen::*)()) &easy3d::OffScreen::camera, "Returns the camera used by the offscreen renderer", pybind11::return_value_policy::reference_internal); cl.def("camera", (const class easy3d::Camera* (easy3d::OffScreen::*)() const) &easy3d::OffScreen::camera, "Returns the camera used by the offscreen renderer", pybind11::return_value_policy::reference_internal); diff --git a/python/bindings/easy3d/viewer/viewer.cpp b/python/bindings/easy3d/viewer/viewer.cpp index 560d1db9..baddaade 100644 --- a/python/bindings/easy3d/viewer/viewer.cpp +++ b/python/bindings/easy3d/viewer/viewer.cpp @@ -1,9 +1,5 @@ #include #include -#include -#include -#include -#include #include #include #include @@ -484,6 +480,7 @@ void bind_easy3d_viewer_viewer(pybind11::module_& m) cl.def("background_color", (const class easy3d::Vec<4, float> & (easy3d::Viewer::*)() const) &easy3d::Viewer::background_color, "Query the background color of the viewer.\n \n\n The background color of the viewer\n\nC++: easy3d::Viewer::background_color() const --> const class easy3d::Vec<4, float> &", pybind11::return_value_policy::automatic); cl.def("open", (bool (easy3d::Viewer::*)()) &easy3d::Viewer::open, "Open a model (PointCloud/SurfaceMesh/Graph) from a file into the viewer. On\n success, the viewer will be in charge of the memory management of the model.\n \n\n This method loads a model into the viewer. Internally, it will pop up a file\n dialog for the user to navigate to the file. After loading the model, the\n necessary drawables (e.g., \"vertices\" for point clouds, \"faces\" for surface\n meshes, and \"edges\" and \"vertices\" for graphs) will be created for visualization.\n \n\n true on success and false otherwise.\n\nC++: easy3d::Viewer::open() --> bool"); cl.def("save", (bool (easy3d::Viewer::*)() const) &easy3d::Viewer::save, "Save the active model (if exists) to a file.\n \n\n This method saves the active model to a file. Internally, it will pop up a file\n dialog for specifying the file name.\n \n\n true on success and false otherwise.\n\nC++: easy3d::Viewer::save() const --> bool"); + cl.def("add_model", [](easy3d::Viewer& self, const std::string& file_name, bool create_default_drawables = true) { return self.add_model(file_name, create_default_drawables); @@ -491,50 +488,31 @@ void bind_easy3d_viewer_viewer(pybind11::module_& m) pybind11::arg("file_name"), pybind11::arg("create_default_drawables") = true, pybind11::return_value_policy::reference_internal, "Add a model from a file to the viewer."); - cl.def("add_model", [](easy3d::Viewer& self, std::shared_ptr point_cloud, bool create_default_drawables = true) - { - return self.add_model(point_cloud, create_default_drawables); - }, - pybind11::arg("point_cloud"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing point cloud to the viewer."); - cl.def("add_model", [](easy3d::Viewer& self, std::shared_ptr surface_mesh, bool create_default_drawables = true) - { - return self.add_model(surface_mesh, create_default_drawables); - }, - pybind11::arg("surface_mesh"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing surface mesh to the viewer." - ); - cl.def("add_model", [](easy3d::Viewer& self, std::shared_ptr graph, bool create_default_drawables = true) - { - return self.add_model(graph, create_default_drawables); - }, - pybind11::arg("graph"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing graph to the viewer." - ); - cl.def("add_model", [](easy3d::Viewer& self, std::shared_ptr poly_mesh, bool create_default_drawables = true) - { - return self.add_model(poly_mesh, create_default_drawables); - }, - pybind11::arg("poly_mesh"), pybind11::arg("create_default_drawables") = true, - pybind11::return_value_policy::reference_internal, - "Add an existing polyhedral mesh to the viewer." - ); + + cl.def("add_model", [](easy3d::Viewer &self, std::shared_ptr model) { + return self.add_model(model); // Call the C++ function + }, pybind11::arg("model"), + pybind11::return_value_policy::automatic, + R"doc( + Add an existing model to the viewer to be visualized. + Parameters: + model (Model): The pointer to the model. + Returns: + Model: The pointer of the model added to the viewer. + )doc"); + cl.def("add_drawable", [](easy3d::Viewer &self, std::shared_ptr drawable) { return self.add_drawable(drawable); // Call the C++ function }, pybind11::arg("drawable"), - pybind11::return_value_policy::reference_internal, + pybind11::return_value_policy::automatic, R"doc( - Add a drawable to the viewer to be visualized. - - Parameters: - drawable (Drawable): The pointer to the drawable. + Add a drawable to the viewer to be visualized. + Parameters: + drawable (Drawable): The pointer to the drawable. + Returns: + Drawable: The pointer of the drawable added to the viewer. + )doc"); - Returns: - Drawable: The pointer of the drawable added to the viewer. - )doc"); cl.def("models", (const class std::vector & (easy3d::Viewer::*)() const) &easy3d::Viewer::models, "Query the models managed by this viewer.\n \n\n The models managed by this viewer.\n\nC++: easy3d::Viewer::models() const --> const class std::vector &", pybind11::return_value_policy::automatic); cl.def("drawables", (const class std::vector & (easy3d::Viewer::*)() const) &easy3d::Viewer::drawables, "Query the drawables managed by this viewer.\n \n\n The drawables managed by this viewer.\n\nC++: easy3d::Viewer::drawables() const --> const class std::vector &", pybind11::return_value_policy::automatic); cl.def("clear_scene", (void (easy3d::Viewer::*)()) &easy3d::Viewer::clear_scene, "Delete all visual contents of the viewer (all models and drawables).\n\nC++: easy3d::Viewer::clear_scene() --> void"); diff --git a/python/tutorials/ToDo b/python/tutorials/ToDo index e4650203..b557d615 100644 --- a/python/tutorials/ToDo +++ b/python/tutorials/ToDo @@ -1,6 +1,10 @@ -add examples showing the flexibility of drawables: - - create a PointsDrawable and add it to the viewer - - create a TrianglesDrawable and add it to the viewer - - create a LinesDrawable and add it to the viewer - - create a LinesDrawable2D and add it to the viewer +think about what Python users may needs: + - creat/init a point cloud from a Numpy list/array + - add/access/edit/visualize Int vertex properties (e.g., segmentation) + - give points random color based on specified (by name) Int properties. + - construct SrufaceMesh from vertices and indices, and show/explain the use of (and without) element buffer + +Some planned examples: + - put MultiView immediately after Viewer + - Use a MultiView to show drawables: PointsDrawable (random points within a cube), TrianglesDrawable, LinesDrawable, LinesDrawable2D,