diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 722427282..8a6312514 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -66,6 +66,7 @@ option(LIBIGL_WITH_PNG "Use PNG" ON) option(LIBIGL_WITH_TETGEN "Use Tetgen" ON) option(LIBIGL_WITH_TRIANGLE "Use Triangle" ON) option(LIBIGL_WITH_XML "Use XML" ON) +option(LIBIGL_WITH_COPYLEFT "Use Copyleft" ON) if(LIBIGL_WITH_CGAL) # Do not remove or move this block, cgal strange build system fails without it find_package(CGAL REQUIRED) @@ -112,6 +113,11 @@ if (LIBIGL_WITH_CGAL) list(APPEND SHARED_SOURCES "modules/copyleft/py_igl_cgal.cpp") endif () +if (LIBIGL_WITH_COPYLEFT) + add_definitions(-DPY_COPYLEFT) + list(APPEND SHARED_SOURCES "modules/copyleft/py_igl_copyleft.cpp") +endif () + if (LIBIGL_WITH_PNG) add_definitions(-DPY_PNG) list(APPEND SHARED_SOURCES "modules/py_igl_png.cpp") diff --git a/python/modules/copyleft/py_igl_copyleft.cpp b/python/modules/copyleft/py_igl_copyleft.cpp new file mode 100644 index 000000000..2693fd1fa --- /dev/null +++ b/python/modules/copyleft/py_igl_copyleft.cpp @@ -0,0 +1,18 @@ +//#include +//#include +//#include + + +#include "../../python_shared.h" + +#include + + +void python_export_igl_copyleft(py::module &me) { + + py::module m = me.def_submodule( + "copyleft", "Wrappers for libigl functions that are copyleft"); + + #include "../../py_igl/copyleft/py_marching_cubes.cpp" + +} diff --git a/python/py_doc.cpp b/python/py_doc.cpp index 4870a3838..8e6665864 100644 --- a/python/py_doc.cpp +++ b/python/py_doc.cpp @@ -112,6 +112,7 @@ const char *__doc_igl_cat = R"igl_Qu8mg5v7(// Perform concatenation of a two mat // Outputs: // C output matrix // )igl_Qu8mg5v7"; +const char *__doc_igl_collapse_edge = R"igl_Qu8mg5v7(See collapse_edge for the documentation.)igl_Qu8mg5v7"; const char *__doc_igl_colon = R"igl_Qu8mg5v7(// Colon operator like matlab's colon operator. Enumerats values between low // and hi with step step. // Templates: @@ -219,6 +220,30 @@ const char *__doc_igl_copyleft_comiso_nrosy = R"igl_Qu8mg5v7(// Generate a N-RoS // Outputs: // R #F by 3 the representative vectors of the interpolated field // S #V by 1 the singularity index for each vertex (0 = regular))igl_Qu8mg5v7"; +const char *__doc_igl_copyleft_marching_cubes = R"igl_Qu8mg5v7(// marching_cubes( values, points, x_res, y_res, z_res, vertices, faces ) + // + // performs marching cubes reconstruction on the grid defined by values, and + // points, and generates vertices and faces + // + // Input: + // values #number_of_grid_points x 1 array -- the scalar values of an + // implicit function defined on the grid points (<0 in the inside of the + // surface, 0 on the border, >0 outside) + // points #number_of_grid_points x 3 array -- 3-D positions of the grid + // points, ordered in x,y,z order: + // points[index] = the point at (x,y,z) where : + // x = (index % (xres -1), + // y = (index / (xres-1)) %(yres-1), + // z = index / (xres -1) / (yres -1) ). + // where x,y,z index x, y, z dimensions + // i.e. index = x + y*xres + z*xres*yres + // xres resolutions of the grid in x dimension + // yres resolutions of the grid in y dimension + // zres resolutions of the grid in z dimension + // Output: + // vertices #V by 3 list of mesh vertex positions + // faces #F by 3 list of mesh triangle indices + //)igl_Qu8mg5v7"; const char *__doc_igl_copyleft_tetgen_tetrahedralize = R"igl_Qu8mg5v7(// Mesh the interior of a surface mesh (V,F) using tetgen // // Inputs: diff --git a/python/py_doc.h b/python/py_doc.h index 365282b45..3fc6f0bbf 100644 --- a/python/py_doc.h +++ b/python/py_doc.h @@ -7,6 +7,7 @@ extern const char *__doc_igl_barycentric_coordinates; extern const char *__doc_igl_boundary_facets; extern const char *__doc_igl_boundary_loop; extern const char *__doc_igl_cat; +extern const char *__doc_igl_collapse_edge; extern const char *__doc_igl_colon; extern const char *__doc_igl_comb_cross_field; extern const char *__doc_igl_comb_frame_field; @@ -14,6 +15,7 @@ extern const char *__doc_igl_compute_frame_field_bisectors; extern const char *__doc_igl_copyleft_cgal_mesh_boolean; extern const char *__doc_igl_copyleft_comiso_miq; extern const char *__doc_igl_copyleft_comiso_nrosy; +extern const char *__doc_igl_copyleft_marching_cubes; extern const char *__doc_igl_copyleft_tetgen_tetrahedralize; extern const char *__doc_igl_cotmatrix; extern const char *__doc_igl_covariance_scatter_matrix; diff --git a/python/py_igl.cpp b/python/py_igl.cpp index 9485169a2..4bdf49041 100644 --- a/python/py_igl.cpp +++ b/python/py_igl.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,7 @@ void python_export_igl(py::module &m) #include "py_igl/py_boundary_facets.cpp" #include "py_igl/py_boundary_loop.cpp" #include "py_igl/py_cat.cpp" +#include "py_igl/py_collapse_edge.cpp" #include "py_igl/py_colon.cpp" #include "py_igl/py_comb_cross_field.cpp" #include "py_igl/py_comb_frame_field.cpp" diff --git a/python/py_igl/copyleft/py_marching_cubes.cpp b/python/py_igl/copyleft/py_marching_cubes.cpp new file mode 100644 index 000000000..4aac4f2d0 --- /dev/null +++ b/python/py_igl/copyleft/py_marching_cubes.cpp @@ -0,0 +1,21 @@ + + +m.def("marching_cubes", [] +( + const Eigen::MatrixXd& values, + const Eigen::MatrixXd& points, + const unsigned int x_res, + const unsigned int y_res, + const unsigned int z_res, + Eigen::MatrixXd& vertices, + Eigen::MatrixXi& faces +) +{ + assert_is_VectorX("values", values); + Eigen::VectorXd valuesv; + if (values.size() != 0) + valuesv = values; + return igl::copyleft::marching_cubes(valuesv, points, x_res, y_res, z_res, vertices, faces); +}, __doc_igl_copyleft_marching_cubes, +py::arg("values"), py::arg("points"), py::arg("x_res"), py::arg("y_res"), py::arg("z_res"), py::arg("vertices"), py::arg("faces")); + diff --git a/python/py_igl/py_collapse_edge.cpp b/python/py_igl/py_collapse_edge.cpp new file mode 100644 index 000000000..a4416802a --- /dev/null +++ b/python/py_igl/py_collapse_edge.cpp @@ -0,0 +1,87 @@ +// COMPLETE BINDINGS ======================== + + + + + + +// INCOMPLETE BINDINGS ======================== + + +//m.def("collapse_edge", [] +//( +// int e, +// Eigen::RowVectorXd & p, +// Eigen::MatrixXd& V, +// Eigen::MatrixXi& F, +// Eigen::MatrixXi& E, +// Eigen::MatrixXi& EMAP, +// Eigen::MatrixXi& EF, +// Eigen::MatrixXi& EI, +// int & e1, +// int & e2, +// int & f1, +// int & f2 +//) +//{ +// return igl::collapse_edge(e, p, V, F, E, EMAP, EF, EI, e1, e2, f1, f2); +//}, __doc_igl_collapse_edge, +//py::arg("e"), py::arg("p"), py::arg("V"), py::arg("F"), py::arg("E"), py::arg("EMAP"), py::arg("EF"), py::arg("EI"), py::arg("e1"), py::arg("e2"), py::arg("f1"), py::arg("f2")); + +//m.def("collapse_edge", [] +//( +// int e, +// Eigen::RowVectorXd & p, +// Eigen::MatrixXd& V, +// Eigen::MatrixXi& F, +// Eigen::MatrixXi& E, +// Eigen::MatrixXi& EMAP, +// Eigen::MatrixXi& EF, +// Eigen::MatrixXi& EI +//) +//{ +// return igl::collapse_edge(e, p, V, F, E, EMAP, EF, EI); +//}, __doc_igl_collapse_edge, +//py::arg("e"), py::arg("p"), py::arg("V"), py::arg("F"), py::arg("E"), py::arg("EMAP"), py::arg("EF"), py::arg("EI")); + +//m.def("collapse_edge", [] +//( +// std::function & cost_and_placement, +// Eigen::MatrixXd& V, +// Eigen::MatrixXi& F, +// Eigen::MatrixXi& E, +// Eigen::MatrixXi& EMAP, +// Eigen::MatrixXi& EF, +// Eigen::MatrixXi& EI, +// std::set > & Q, +// std::vector >::iterator> & Qit, +// Eigen::MatrixXd& C +//) +//{ +// return igl::collapse_edge(cost_and_placement, V, F, E, EMAP, EF, EI, Q, Qit, C); +//}, __doc_igl_collapse_edge, +//py::arg("cost_and_placement"), py::arg("V"), py::arg("F"), py::arg("E"), py::arg("EMAP"), py::arg("EF"), py::arg("EI"), py::arg("Q"), py::arg("Qit"), py::arg("C")); + +//m.def("collapse_edge", [] +//( +// std::function & cost_and_placement, +// Eigen::MatrixXd& V, +// Eigen::MatrixXi& F, +// Eigen::MatrixXi& E, +// Eigen::MatrixXi& EMAP, +// Eigen::MatrixXi& EF, +// Eigen::MatrixXi& EI, +// std::set > & Q, +// std::vector >::iterator> & Qit, +// Eigen::MatrixXd& C, +// int & e, +// int & e1, +// int & e2, +// int & f1, +// int & f2 +//) +//{ +// return igl::collapse_edge(cost_and_placement, V, F, E, EMAP, EF, EI, Q, Qit, C, e, e1, e2, f1, f2); +//}, __doc_igl_collapse_edge, +//py::arg("cost_and_placement"), py::arg("V"), py::arg("F"), py::arg("E"), py::arg("EMAP"), py::arg("EF"), py::arg("EI"), py::arg("Q"), py::arg("Qit"), py::arg("C"), py::arg("e"), py::arg("e1"), py::arg("e2"), py::arg("f1"), py::arg("f2")); + diff --git a/python/python_shared.cpp b/python/python_shared.cpp index 4c27b9a92..d19580b6d 100644 --- a/python/python_shared.cpp +++ b/python/python_shared.cpp @@ -30,6 +30,10 @@ extern void python_export_igl_triangle(py::module &); extern void python_export_igl_cgal(py::module &); #endif +#ifdef PY_COPYLEFT +extern void python_export_igl_copyleft(py::module &); +#endif + #ifdef PY_PNG extern void python_export_igl_png(py::module &); #endif @@ -56,6 +60,7 @@ PYBIND11_PLUGIN(pyigl) { boundary_facets boundary_loop cat + collapse_edge colon comb_cross_field comb_frame_field @@ -63,6 +68,7 @@ PYBIND11_PLUGIN(pyigl) { copyleft_cgal_mesh_boolean copyleft_comiso_miq copyleft_comiso_nrosy + copyleft_marching_cubes copyleft_tetgen_tetrahedralize cotmatrix covariance_scatter_matrix @@ -151,6 +157,10 @@ PYBIND11_PLUGIN(pyigl) { python_export_igl_cgal(m); #endif + #ifdef PY_COPYLEFT + python_export_igl_copyleft(m); + #endif + #ifdef PY_PNG python_export_igl_png(m); #endif diff --git a/python/scripts/generate_bindings.py b/python/scripts/generate_bindings.py index fe65a3708..0ffc14fea 100755 --- a/python/scripts/generate_bindings.py +++ b/python/scripts/generate_bindings.py @@ -79,7 +79,7 @@ def map_parameter_types(name, cpp_type, parsed_types, errors, enum_types): if len(parsed_types) == 0: errors.append("Empty typechain: %s" % cpp_type) - if cpp_type == "int" or cpp_type == "bool": + if cpp_type == "int" or cpp_type == "bool" or cpp_type == "unsigned int": return cpp_type, True else: return cpp_type, False diff --git a/python/tutorial/705_MarchingCubes.py b/python/tutorial/705_MarchingCubes.py new file mode 100755 index 000000000..8de3b8c62 --- /dev/null +++ b/python/tutorial/705_MarchingCubes.py @@ -0,0 +1,94 @@ +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, print_usage + +dependencies = ["copyleft"] +check_dependencies(dependencies) + + +def key_down(viewer, key, modifier): + if key == ord('1'): + viewer.data.clear() + viewer.data.set_mesh(V, F) + elif key == ord('2'): + viewer.data.clear() + viewer.data.set_mesh(SV, SF) + elif key == ord('3'): + viewer.data.clear() + viewer.data.set_mesh(BV, BF) + + return True + + +if __name__ == "__main__": + keys = {"1": "show original mesh", + "2": "show marching cubes contour of signed distance", + "3": "show marching cubes contour of indicator function"} + + print_usage(keys) + + V = igl.eigen.MatrixXd() + F = igl.eigen.MatrixXi() + + # Read in inputs as double precision floating point meshes + igl.read_triangle_mesh(TUTORIAL_SHARED_PATH + "armadillo.obj", V, F) + + # number of vertices on the largest side + s = 50 + Vmin = V.colwiseMinCoeff() + Vmax = V.colwiseMaxCoeff() + h = (Vmax - Vmin).maxCoeff() / s + res = (s * ((Vmax - Vmin) / (Vmax - Vmin).maxCoeff())).castint() + + def lerp(res, Vmin, Vmax, di, d): + return Vmin[d] + di / (res[d] - 1) * (Vmax[d] - Vmin[d]) + + # create grid + print("Creating grid...") + GV = igl.eigen.MatrixXd(res[0] * res[1] * res[2], 3) + for zi in range(res[2]): + z = lerp(res, Vmin, Vmax, zi, 2) + for yi in range(res[1]): + y = lerp(res, Vmin, Vmax, yi, 1) + for xi in range(res[0]): + x = lerp(res, Vmin, Vmax, xi, 0) + GV.setRow(xi + res[0] * (yi + res[1] * zi), igl.eigen.MatrixXd([[x, y, z]])) + + # compute values + print("Computing distances...") + S = igl.eigen.MatrixXd() + B = igl.eigen.MatrixXd() + I = igl.eigen.MatrixXi() + C = igl.eigen.MatrixXd() + N = igl.eigen.MatrixXd() + + igl.signed_distance(GV, V, F, igl.SIGNED_DISTANCE_TYPE_PSEUDONORMAL, S, I, C, N) + # Convert distances to binary inside-outside data --> aliasing artifacts + B = S.copy() + for e in range(B.rows()): + if B[e] > 0: + B[e] = 1 + else: + if B[e] < 0: + B[e] = -1 + else: + B[e] = 0 + + print("Marching cubes...") + SV = igl.eigen.MatrixXd() + BV = igl.eigen.MatrixXd() + SF = igl.eigen.MatrixXi() + BF = igl.eigen.MatrixXi() + + igl.copyleft.marching_cubes(S, GV, res[0], res[1], res[2], SV, SF) + igl.copyleft.marching_cubes(B, GV, res[0], res[1], res[2], BV, BF) + + # Plot the generated mesh + viewer = igl.viewer.Viewer() + viewer.data.set_mesh(SV, SF) + viewer.callback_key_down = key_down + viewer.launch()