ソースを参照

Added tutorial 707

Former-commit-id: 3a576992809e0a38446ba4386f552cd09947f4a5
Sebastian Koch 9 年 前
コミット
aa298105c6

+ 2 - 0
python/modules/copyleft/py_igl_copyleft.cpp

@@ -6,6 +6,7 @@
 #include "../../python_shared.h"
 
 #include <igl/copyleft/marching_cubes.h>
+#include <igl/copyleft/swept_volume.h>
 
 
 void python_export_igl_copyleft(py::module &me) {
@@ -14,5 +15,6 @@ void python_export_igl_copyleft(py::module &me) {
     "copyleft", "Wrappers for libigl functions that are copyleft");
 
   #include "../../py_igl/copyleft/py_marching_cubes.cpp"
+  #include "../../py_igl/copyleft/py_swept_volume.cpp"
 
 }

+ 19 - 0
python/modules/py_vector.cpp

@@ -692,6 +692,25 @@ void python_export_vector(py::module &m) {
     .def("solve",[](const Eigen::SimplicialLLT<Eigen::SparseMatrix<double > >& s, const Eigen::MatrixXd& rhs) { return Eigen::MatrixXd(s.solve(rhs)); })
     ;
 
+    py::class_<Eigen::Affine3d > affine3d(me, "Affine3d");
+
+    affine3d
+    .def(py::init<>())
+    .def("setIdentity",[](Eigen::Affine3d& a){
+        return a.setIdentity();
+    })
+    .def("rotate",[](Eigen::Affine3d& a, double angle, Eigen::MatrixXd axis) {
+        assert_is_Vector3("axis", axis);
+        return a.rotate(Eigen::AngleAxisd(angle, Eigen::Vector3d(axis)));
+    })
+    .def("translate",[](Eigen::Affine3d& a, Eigen::MatrixXd offset) {
+        assert_is_Vector3("offset", offset);
+        return a.translate(Eigen::Vector3d(offset));
+    })
+    .def("matrix", [](Eigen::Affine3d& a) -> Eigen::MatrixXd {
+        return Eigen::MatrixXd(a.matrix());
+    })
+    ;
     /* Bindings for Quaterniond*/
     //py::class_<Eigen::Quaterniond > quaterniond(me, "Quaterniond");
     //

+ 31 - 0
python/py_doc.cpp

@@ -244,6 +244,21 @@ const char *__doc_igl_copyleft_marching_cubes = R"igl_Qu8mg5v7(// marching_cubes
     //   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_swept_volume = R"igl_Qu8mg5v7(// Compute the surface of the swept volume of a solid object with surface
+    // (V,F) mesh under going rigid motion.
+    // 
+    // Inputs:
+    //   V  #V by 3 list of mesh positions in reference pose
+    //   F  #F by 3 list of mesh indices into V
+    //   transform  function handle so that transform(t) returns the rigid
+    //     transformation at time t∈[0,1]
+    //   steps  number of time steps: steps=3 --> t∈{0,0.5,1}
+    //   grid_res  number of grid cells on the longest side containing the
+    //     motion (isolevel+1 cells will also be added on each side as padding)
+    //   isolevel  distance level to be contoured as swept volume
+    // Outputs:
+    //   SV  #SV by 3 list of mesh positions of the swept surface
+    //   SF  #SF by 3 list of mesh faces into SV)igl_Qu8mg5v7";
 const char *__doc_igl_copyleft_tetgen_tetrahedralize = R"igl_Qu8mg5v7(// Mesh the interior of a surface mesh (V,F) using tetgen
       //
       // Inputs:
@@ -444,6 +459,22 @@ const char *__doc_igl_gaussian_curvature = R"igl_Qu8mg5v7(// Compute discrete lo
   // Output:
   //   K  #V by 1 eigen Matrix of discrete gaussian curvature values
   //)igl_Qu8mg5v7";
+const char *__doc_igl_get_seconds = R"igl_Qu8mg5v7(// Return the current time in seconds since program start
+  // 
+  // Example:
+  //    const auto & tictoc = []()
+  //    {
+  //      static double t_start = igl::get_seconds();
+  //      double diff = igl::get_seconds()-t_start;
+  //      t_start += diff;
+  //      return diff;
+  //    };
+  //    tictoc();
+  //    ... // part 1
+  //    cout<<"part 1: "<<tictoc()<<endl;
+  //    ... // part 2
+  //    cout<<"part 2: "<<tictoc()<<endl;
+  //    ... // etc)igl_Qu8mg5v7";
 const char *__doc_igl_grad = R"igl_Qu8mg5v7(// Gradient of a scalar function defined on piecewise linear elements (mesh)
   // is constant on each triangle i,j,k:
   // grad(Xijk) = (Xj-Xi) * (Vi - Vk)^R90 / 2A + (Xk-Xi) * (Vj - Vi)^R90 / 2A

+ 2 - 0
python/py_doc.h

@@ -16,6 +16,7 @@ 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_swept_volume;
 extern const char *__doc_igl_copyleft_tetgen_tetrahedralize;
 extern const char *__doc_igl_cotmatrix;
 extern const char *__doc_igl_covariance_scatter_matrix;
@@ -34,6 +35,7 @@ extern const char *__doc_igl_fit_rotations_planar;
 extern const char *__doc_igl_fit_rotations_SSE;
 extern const char *__doc_igl_floor;
 extern const char *__doc_igl_gaussian_curvature;
+extern const char *__doc_igl_get_seconds;
 extern const char *__doc_igl_grad;
 extern const char *__doc_igl_harmonic;
 extern const char *__doc_igl_hsv_to_rgb;

+ 2 - 0
python/py_igl.cpp

@@ -30,6 +30,7 @@
 #include <igl/fit_rotations.h>
 #include <igl/floor.h>
 #include <igl/gaussian_curvature.h>
+#include <igl/get_seconds.h>
 #include <igl/grad.h>
 #include <igl/harmonic.h>
 #include <igl/hsv_to_rgb.h>
@@ -105,6 +106,7 @@ void python_export_igl(py::module &m)
 #include "py_igl/py_fit_rotations.cpp"
 #include "py_igl/py_floor.cpp"
 #include "py_igl/py_gaussian_curvature.cpp"
+#include "py_igl/py_get_seconds.cpp"
 #include "py_igl/py_grad.cpp"
 #include "py_igl/py_harmonic.cpp"
 #include "py_igl/py_hsv_to_rgb.cpp"

+ 19 - 0
python/py_igl/copyleft/py_swept_volume.cpp

@@ -0,0 +1,19 @@
+
+m.def("swept_volume", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  const std::function<Eigen::Affine3d (const double)> & transform,
+  const size_t steps,
+  const size_t grid_res,
+  const size_t isolevel,
+  Eigen::MatrixXd& SV,
+  Eigen::MatrixXi& SF
+)
+{
+  return igl::copyleft::swept_volume(V, F, transform, steps, grid_res, isolevel, SV, SF);
+}, __doc_igl_copyleft_swept_volume,
+py::arg("V"), py::arg("F"), py::arg("transform"), py::arg("steps"), py::arg("grid_res"), py::arg("isolevel"), py::arg("SV"), py::arg("SF"));
+
+
+

+ 6 - 0
python/py_igl/py_get_seconds.cpp

@@ -0,0 +1,6 @@
+m.def("get_seconds", []
+()
+{
+  return igl::get_seconds();
+}, __doc_igl_get_seconds);
+

+ 10 - 0
python/python_shared.cpp

@@ -34,6 +34,10 @@ extern void python_export_igl_cgal(py::module &);
 extern void python_export_igl_png(py::module &);
 #endif
 
+#ifdef PY_COPYLEFT
+extern void python_export_igl_copyleft(py::module &);
+#endif
+
 PYBIND11_PLUGIN(pyigl) {
     py::module m("pyigl", R"pyigldoc(
         Python wrappers for libigl
@@ -65,6 +69,7 @@ PYBIND11_PLUGIN(pyigl) {
            copyleft_comiso_miq
            copyleft_comiso_nrosy
            copyleft_marching_cubes
+           copyleft_swept_volume
            copyleft_tetgen_tetrahedralize
            cotmatrix
            covariance_scatter_matrix
@@ -79,6 +84,7 @@ PYBIND11_PLUGIN(pyigl) {
            fit_rotations
            floor
            gaussian_curvature
+           get_seconds
            grad
            harmonic
            hsv_to_rgb
@@ -160,5 +166,9 @@ PYBIND11_PLUGIN(pyigl) {
     python_export_igl_png(m);
     #endif
 
+    #ifdef PY_COPYLEFT
+    python_export_igl_copyleft(m);
+    #endif
+
     return m.ptr();
 }

+ 8 - 0
python/scripts/python_shared.mako

@@ -34,6 +34,10 @@ extern void python_export_igl_cgal(py::module &);
 extern void python_export_igl_png(py::module &);
 #endif
 
+#ifdef PY_COPYLEFT
+extern void python_export_igl_copyleft(py::module &);
+#endif
+
 PYBIND11_PLUGIN(pyigl) {
     py::module m("pyigl", R"pyigldoc(
         Python wrappers for libigl
@@ -82,5 +86,9 @@ PYBIND11_PLUGIN(pyigl) {
     python_export_igl_png(m);
     #endif
 
+    #ifdef PY_COPYLEFT
+    python_export_igl_copyleft(m);
+    #endif
+
     return m.ptr();
 }

+ 83 - 0
python/tutorial/707_SweptVolume.py

@@ -0,0 +1,83 @@
+import sys, os
+
+# Add the igl library to the modules search path
+from math import pi, cos
+
+sys.path.insert(0, os.getcwd() + "/../")
+import pyigl as igl
+
+from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
+
+dependencies = ["copyleft", "viewer"]
+check_dependencies(dependencies)
+
+
+def key_down(viewer, key, modifier):
+    global show_swept_volume, SV, SF, V, F
+    if key == ord(' '):
+        show_swept_volume = not show_swept_volume
+        viewer.data.clear()
+
+        if show_swept_volume:
+            viewer.data.set_mesh(SV, SF)
+            viewer.data.uniform_colors(igl.eigen.MatrixXd([0.2, 0.2, 0.2]), igl.eigen.MatrixXd([1.0, 1.0, 1.0]), igl.eigen.MatrixXd([1.0, 1.0, 1.0])) # TODO replace with constants from cpp
+        else:
+            viewer.data.set_mesh(V, F)
+
+        viewer.core.is_animating = not show_swept_volume
+        viewer.data.set_face_based(True)
+
+    return True
+
+
+def pre_draw(viewer):
+    global show_swept_volume, V
+    if not show_swept_volume:
+        T = transform(0.25 * igl.get_seconds())
+        VT = V * T.matrix().block(0, 0, 3, 3).transpose()
+        trans = T.matrix().block(0, 3, 3, 1).transpose()
+        Vtrans = igl.eigen.MatrixXd(VT.rows(), VT.cols())
+        Vtrans.rowwiseSet(trans)
+        VT += Vtrans
+        viewer.data.set_vertices(VT)
+        viewer.data.compute_normals()
+    return False
+
+
+# Define a rigid motion
+def transform(t):
+    T = igl.eigen.Affine3d()
+    T.setIdentity()
+    T.rotate(t * 2 * pi, igl.eigen.MatrixXd([0, 1, 0]))
+    T.translate(igl.eigen.MatrixXd([0, 0.125 * cos(2 * pi * t), 0]))
+    return T
+
+
+if __name__ == "__main__":
+    keys = {"space": "toggle between transforming original mesh and swept volume"}
+    print_usage(keys)
+
+    V = igl.eigen.MatrixXd()
+    SV = igl.eigen.MatrixXd()
+    VT = igl.eigen.MatrixXd()
+    F = igl.eigen.MatrixXi()
+    SF = igl.eigen.MatrixXi()
+    show_swept_volume = False
+    grid_size = 50
+    time_steps = 200
+    isolevel = 1
+
+    igl.read_triangle_mesh(TUTORIAL_SHARED_PATH + "bunny.off", V, F)
+
+    print("Computing swept volume...")
+    igl.copyleft.swept_volume(V, F, transform, time_steps, grid_size, isolevel, SV, SF)
+    print("...finished.")
+
+    # Plot the generated mesh
+    viewer = igl.viewer.Viewer()
+    viewer.data.set_mesh(V, F)
+    viewer.data.set_face_based(True)
+    viewer.core.is_animating = not show_swept_volume
+    viewer.callback_pre_draw = pre_draw
+    viewer.callback_key_down = key_down
+    viewer.launch()