Added tutorial 609_Boolean and CGAL python module + functions
Former-commit-id: 7b6b91bd7a
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//#include <Eigen/Geometry>
|
||||
//#include <Eigen/Dense>
|
||||
//#include <Eigen/Sparse>
|
||||
|
||||
|
||||
#include "../../python_shared.h"
|
||||
|
||||
#include <igl/copyleft/cgal/mesh_boolean.h>
|
||||
|
||||
|
||||
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"
|
||||
|
||||
}
|
||||
@@ -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<int (const Eigen::Matrix<int, 1, Eigen::Dynamic>)> & wind_num_op,
|
||||
// std::function<int (const int, const int)> & 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<DerivedV> & Vlist,
|
||||
// std::vector<DerivedF> & Flist,
|
||||
// std::function<int (const Eigen::Matrix<int, 1, Eigen::Dynamic>)> & wind_num_op,
|
||||
// std::function<int (const int, const int)> & 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<int (const Eigen::Matrix<int, 1, Eigen::Dynamic>)> & wind_num_op,
|
||||
// std::function<int (const int, const int)> & 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"));
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
py::enum_<igl::MeshBooleanType>(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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Executable
+84
@@ -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()
|
||||
Reference in New Issue
Block a user