diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 3c634b9f2..c6e7bc25f 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -107,6 +107,11 @@ if (LIBIGL_WITH_TRIANGLE) list(APPEND SHARED_SOURCES "modules/py_igl_triangle.cpp") endif () +if (LIBIGL_WITH_CGAL) + add_definitions(-DPY_CGAL) + list(APPEND SHARED_SOURCES "modules/copyleft/py_igl_cgal.cpp") +endif () + ## Prepare the python library add_library(pyigl SHARED diff --git a/python/modules/copyleft/py_igl_cgal.cpp b/python/modules/copyleft/py_igl_cgal.cpp new file mode 100644 index 000000000..40b17cb41 --- /dev/null +++ b/python/modules/copyleft/py_igl_cgal.cpp @@ -0,0 +1,18 @@ +//#include +//#include +//#include + + +#include "../../python_shared.h" + +#include + + +void python_export_igl_cgal(py::module &me) { + + py::module m = me.def_submodule( + "cgal", "Wrappers for libigl functions that use cgal"); + + #include "../../py_igl/copyleft/cgal/py_mesh_boolean.cpp" + +} diff --git a/python/py_igl/copyleft/cgal/py_mesh_boolean.cpp b/python/py_igl/copyleft/cgal/py_mesh_boolean.cpp new file mode 100644 index 000000000..654464e5f --- /dev/null +++ b/python/py_igl/copyleft/cgal/py_mesh_boolean.cpp @@ -0,0 +1,107 @@ +// COMPLETE BINDINGS ======================== + +m.def("mesh_boolean", [] +( + const Eigen::MatrixXd& VA, + const Eigen::MatrixXi& FA, + const Eigen::MatrixXd& VB, + const Eigen::MatrixXi& FB, + igl::MeshBooleanType & type, + Eigen::MatrixXd& VC, + Eigen::MatrixXi& FC, + Eigen::MatrixXi& J +) +{ + return igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, type, VC, FC, J); +}, __doc_igl_copyleft_cgal_mesh_boolean, +py::arg("VA"), py::arg("FA"), py::arg("VB"), py::arg("FB"), py::arg("type"), py::arg("VC"), py::arg("FC"), py::arg("J")); + + +m.def("mesh_boolean", [] +( + const Eigen::MatrixXd& VA, + const Eigen::MatrixXi& FA, + const Eigen::MatrixXd& VB, + const Eigen::MatrixXi& FB, + const std::string & type_str, + Eigen::MatrixXd& VC, + Eigen::MatrixXi& FC, + Eigen::MatrixXi& J +) +{ + return igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, type_str, VC, FC, J); +}, __doc_igl_copyleft_cgal_mesh_boolean, +py::arg("VA"), py::arg("FA"), py::arg("VB"), py::arg("FB"), py::arg("type_str"), py::arg("VC"), py::arg("FC"), py::arg("J")); + +m.def("mesh_boolean", [] +( + const Eigen::MatrixXd& VA, + const Eigen::MatrixXi& FA, + const Eigen::MatrixXd& VB, + const Eigen::MatrixXi& FB, + const igl::MeshBooleanType & type, + Eigen::MatrixXd& VC, + Eigen::MatrixXi& FC +) +{ + return igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, type, VC, FC); +}, __doc_igl_copyleft_cgal_mesh_boolean, +py::arg("VA"), py::arg("FA"), py::arg("VB"), py::arg("FB"), py::arg("type"), py::arg("VC"), py::arg("FC")); + + + +// INCOMPLETE BINDINGS ======================== + + + + +//m.def("mesh_boolean", [] +//( +// const Eigen::MatrixXd& VA, +// const Eigen::MatrixXd& FA, +// const Eigen::MatrixXd& VB, +// const Eigen::MatrixXd& FB, +// std::function)> & wind_num_op, +// std::function & keep, +// Eigen::MatrixXd& VC, +// Eigen::MatrixXd& FC, +// Eigen::MatrixXd& J +//) +//{ +// return igl::copyleft::cgal::mesh_boolean(VA, FA, VB, FB, wind_num_op, keep, VC, FC, J); +//}, __doc_igl_copyleft_cgal_mesh_boolean, +//py::arg("VA"), py::arg("FA"), py::arg("VB"), py::arg("FB"), py::arg("wind_num_op"), py::arg("keep"), py::arg("VC"), py::arg("FC"), py::arg("J")); + +//m.def("mesh_boolean", [] +//( +// std::vector & Vlist, +// std::vector & Flist, +// std::function)> & wind_num_op, +// std::function & keep, +// Eigen::MatrixXd& VC, +// Eigen::MatrixXd& FC, +// Eigen::MatrixXd& J +//) +//{ +// return igl::copyleft::cgal::mesh_boolean(Vlist, Flist, wind_num_op, keep, VC, FC, J); +//}, __doc_igl_copyleft_cgal_mesh_boolean, +//py::arg("Vlist"), py::arg("Flist"), py::arg("wind_num_op"), py::arg("keep"), py::arg("VC"), py::arg("FC"), py::arg("J")); + +//m.def("mesh_boolean", [] +//( +// const Eigen::MatrixXd& VV, +// const Eigen::MatrixXd& FF, +// const Eigen::MatrixXd& sizes, +// std::function)> & wind_num_op, +// std::function & keep, +// Eigen::MatrixXd& VC, +// Eigen::MatrixXd& FC, +// Eigen::MatrixXd& J +//) +//{ +// return igl::copyleft::cgal::mesh_boolean(VV, FF, sizes, wind_num_op, keep, VC, FC, J); +//}, __doc_igl_copyleft_cgal_mesh_boolean, +//py::arg("VV"), py::arg("FF"), py::arg("sizes"), py::arg("wind_num_op"), py::arg("keep"), py::arg("VC"), py::arg("FC"), py::arg("J")); + + + diff --git a/python/py_igl/py_MeshBooleanType.cpp b/python/py_igl/py_MeshBooleanType.cpp new file mode 100644 index 000000000..be621afbc --- /dev/null +++ b/python/py_igl/py_MeshBooleanType.cpp @@ -0,0 +1,10 @@ +py::enum_(m, "MeshBooleanType") + .value("MESH_BOOLEAN_TYPE_UNION", igl::MESH_BOOLEAN_TYPE_UNION) + .value("MESH_BOOLEAN_TYPE_INTERSECT", igl::MESH_BOOLEAN_TYPE_INTERSECT) + .value("MESH_BOOLEAN_TYPE_MINUS", igl::MESH_BOOLEAN_TYPE_MINUS) + .value("MESH_BOOLEAN_TYPE_XOR", igl::MESH_BOOLEAN_TYPE_XOR) + .value("MESH_BOOLEAN_TYPE_RESOLVE", igl::MESH_BOOLEAN_TYPE_RESOLVE) + .value("NUM_MESH_BOOLEAN_TYPES", igl::NUM_MESH_BOOLEAN_TYPES) + .export_values(); + + diff --git a/python/python_shared.cpp b/python/python_shared.cpp index 63024a67c..fe529278d 100644 --- a/python/python_shared.cpp +++ b/python/python_shared.cpp @@ -26,6 +26,10 @@ extern void python_export_igl_embree(py::module &); extern void python_export_igl_triangle(py::module &); #endif +#ifdef PY_CGAL +extern void python_export_igl_cgal(py::module &); +#endif + PYBIND11_PLUGIN(pyigl) { py::module m("pyigl", R"pyigldoc( Python wrappers for libigl @@ -36,6 +40,77 @@ PYBIND11_PLUGIN(pyigl) { .. autosummary:: :toctree: _generate + AABB + ARAPEnergyType + MeshBooleanType + SolverStatus + active_set + arap + avg_edge_length + barycenter + barycentric_coordinates + boundary_facets + boundary_loop + cat + colon + comb_cross_field + comb_frame_field + compute_frame_field_bisectors + copyleft_cgal_mesh_boolean + copyleft_comiso_miq + copyleft_comiso_nrosy + copyleft_tetgen_tetrahedralize + cotmatrix + covariance_scatter_matrix + cross_field_missmatch + cut_mesh_from_singularities + doublearea + edge_lengths + eigs + embree_ambient_occlusion + find_cross_field_singularities + fit_rotations + floor + gaussian_curvature + grad + harmonic + invert_diag + jet + local_basis + lscm + map_vertices_to_circle + massmatrix + min_quad_with_fixed + n_polyvector + parula + per_corner_normals + per_edge_normals + per_face_normals + per_vertex_normals + planarize_quad_mesh + point_mesh_squared_distance + polar_svd + principal_curvature + quad_planarity + readDMAT + readMESH + readOBJ + readOFF + read_triangle_mesh + rotate_vectors + setdiff + signed_distance + slice + slice_into + slice_mask + slice_tets + sortrows + triangle_triangulate + unique + unproject_onto_mesh + upsample + writeMESH + writeOBJ )pyigldoc"); @@ -63,5 +138,9 @@ PYBIND11_PLUGIN(pyigl) { python_export_igl_triangle(m); #endif + #ifdef PY_CGAL + python_export_igl_cgal(m); + #endif + return m.ptr(); } diff --git a/python/scripts/python_shared.mako b/python/scripts/python_shared.mako index 631410fa7..9ba542c01 100644 --- a/python/scripts/python_shared.mako +++ b/python/scripts/python_shared.mako @@ -26,6 +26,10 @@ extern void python_export_igl_embree(py::module &); extern void python_export_igl_triangle(py::module &); #endif +#ifdef PY_CGAL +extern void python_export_igl_cgal(py::module &); +#endif + PYBIND11_PLUGIN(pyigl) { py::module m("pyigl", R"pyigldoc( Python wrappers for libigl @@ -66,5 +70,9 @@ PYBIND11_PLUGIN(pyigl) { python_export_igl_triangle(m); #endif + #ifdef PY_CGAL + python_export_igl_cgal(m); + #endif + return m.ptr(); } diff --git a/python/tutorial/609_Boolean.py b/python/tutorial/609_Boolean.py new file mode 100755 index 000000000..912844a80 --- /dev/null +++ b/python/tutorial/609_Boolean.py @@ -0,0 +1,84 @@ +import sys, os + +# Add the igl library to the modules search path +sys.path.insert(0, os.getcwd() + "/../") +import pyigl as igl + +from shared import TUTORIAL_SHARED_PATH, check_dependencies + +dependencies = ["cgal", "viewer"] +check_dependencies(dependencies) + +boolean_type_names = {igl.MESH_BOOLEAN_TYPE_UNION: "Union", igl.MESH_BOOLEAN_TYPE_INTERSECT: "Intersect", igl.MESH_BOOLEAN_TYPE_MINUS: "Minus", igl.MESH_BOOLEAN_TYPE_XOR: "XOR", igl.MESH_BOOLEAN_TYPE_RESOLVE: "Resolve"} + +boolean_types = list(boolean_type_names.keys()) + + + + +def update(viewer): + print("Calculating A %s B..." % boolean_type_names[boolean_type]) + igl.cgal.mesh_boolean(VA, FA, VB, FB, boolean_type, VC, FC, J) + C = igl.eigen.MatrixXd(FC.rows(), 3) + + for f in range(C.rows()): + if J[f] < FA.rows(): + C.setRow(f, Red) + else: + C.setRow(f, Green) + + viewer.data.clear() + viewer.data.set_mesh(VC, FC) + viewer.data.set_colors(C) + print("Done.") + + +def key_down(viewer, key, modifier): + global boolean_type + # print(boolean_types) + if key == ord('.'): + boolean_type = boolean_types[(boolean_types.index(boolean_type) + 1) % (len(boolean_types))] + elif key == ord(','): + boolean_type = boolean_types[(boolean_types.index(boolean_type) + len(boolean_types) - 1) % len(boolean_types)] + elif key == ord('['): + viewer.core.camera_dnear -= 0.1 + elif key == ord(']'): + viewer.core.camera_dnear += 0.1 + else: + return False + + #igl.cgal.mesh_boolean(VA, FA, VB, FB, boolean_type, VC, FC) + update(viewer) + + return False + + +if __name__ == "__main__": + # Mesh with per-face color + VA = igl.eigen.MatrixXd() + FA = igl.eigen.MatrixXi() + VB = igl.eigen.MatrixXd() + FB = igl.eigen.MatrixXi() + VC = igl.eigen.MatrixXd() + FC = igl.eigen.MatrixXi() + J = igl.eigen.MatrixXi() + + Red = igl.eigen.MatrixXd([[1, 0, 0]]) + Green = igl.eigen.MatrixXd([[0, 1, 0]]) + + # Load meshes in OFF format + igl.readOFF(TUTORIAL_SHARED_PATH + "cheburashka.off", VA, FA) + igl.readOFF(TUTORIAL_SHARED_PATH + "decimated-knight.off", VB, FB) + + boolean_type = igl.MESH_BOOLEAN_TYPE_UNION + + viewer = igl.viewer.Viewer() + update(viewer) + + print( + "Usage: Press '.' to switch to next boolean operation type. \nPress ',' to switch to previous boolean operation type. \nPress ']' to push near cutting plane away from camera. \nPress '[' to pull near cutting plane closer to camera. \nHint: investigate _inside_ the model to see orientation changes. \n") + + viewer.core.show_lines = True + viewer.callback_key_down = key_down + viewer.core.camera_dnear = 3.9 + viewer.launch() diff --git a/tutorial/609_Boolean/main.cpp b/tutorial/609_Boolean/main.cpp index 38dfa36cf..decc730f5 100755 --- a/tutorial/609_Boolean/main.cpp +++ b/tutorial/609_Boolean/main.cpp @@ -41,6 +41,7 @@ void update(igl::viewer::Viewer &viewer) viewer.data.clear(); viewer.data.set_mesh(VC,FC); viewer.data.set_colors(C); + std::cout<<"A "<