Browse Source

Merge branch 'python_bindings' of https://github.com/s-koch/libigl

# Conflicts:
#	python/CMakeLists.txt


Former-commit-id: 1f073ddda200066205bdc731bd4d746ca6b413e9
Daniele Panozzo 9 years ago
parent
commit
e1eb91246c

+ 8 - 8
include/igl/hsv_to_rgb.cpp

@@ -1,9 +1,9 @@
 // This file is part of libigl, a simple c++ geometry processing library.
-// 
+//
 // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
-// 
-// This Source Code Form is subject to the terms of the Mozilla Public License 
-// v. 2.0. If a copy of the MPL was not distributed with this file, You can 
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
 // obtain one at http://mozilla.org/MPL/2.0/.
 #include "hsv_to_rgb.h"
 #include <cmath>
@@ -12,21 +12,21 @@
 template <typename T>
 IGL_INLINE void igl::hsv_to_rgb(const T * hsv, T * rgb)
 {
-  igl::hsv_to_rgb( 
+  igl::hsv_to_rgb(
       hsv[0],hsv[1],hsv[2],
       rgb[0],rgb[1],rgb[2]);
 }
 
 template <typename T>
-IGL_INLINE void igl::hsv_to_rgb( 
-  const T & h, const T & s, const T & v, 
+IGL_INLINE void igl::hsv_to_rgb(
+  const T & h, const T & s, const T & v,
   T & r, T & g, T & b)
 {
   // From medit
   double f,p,q,t,hh;
   int    i;
   hh = ((int)h % 360) / 60.;
-  i = (int)floor(hh);    /* largest int <= h     */
+  i = (int)std::floor(hh);    /* largest int <= h     */
   f = hh - i;                    /* fractional part of h */
   p = v * (1.0 - s);
   q = v * (1.0 - (s * f));

+ 7 - 0
python/CMakeLists.txt

@@ -67,6 +67,8 @@ option(LIBIGL_WITH_TETGEN           "Use Tetgen"         ON)
 option(LIBIGL_WITH_TRIANGLE         "Use Triangle"       ON)
 option(LIBIGL_WITH_XML              "Use XML"            ON)
 option(LIBIGL_WITH_PYTHON           "Use Python"         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)
@@ -113,6 +115,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")

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

@@ -0,0 +1,20 @@
+//#include <Eigen/Geometry>
+//#include <Eigen/Dense>
+//#include <Eigen/Sparse>
+
+
+#include "../../python_shared.h"
+
+#include <igl/copyleft/marching_cubes.h>
+#include <igl/copyleft/swept_volume.h>
+
+
+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"
+  #include "../../py_igl/copyleft/py_swept_volume.cpp"
+
+}

+ 2 - 0
python/modules/py_igl_embree.cpp

@@ -6,6 +6,7 @@
 #include "../python_shared.h"
 
 #include <igl/embree/ambient_occlusion.h>
+#include <igl/embree/reorient_facets_raycast.h>
 
 
 void python_export_igl_embree(py::module &me) {
@@ -14,5 +15,6 @@ void python_export_igl_embree(py::module &me) {
     "embree", "Wrappers for libigl functions that use embree");
 
   #include "../py_igl/embree/py_ambient_occlusion.cpp"
+  #include "../py_igl/embree/py_reorient_facets_raycast.cpp"
 
 }

+ 22 - 0
python/modules/py_vector.cpp

@@ -180,6 +180,7 @@ py::class_<Type> bind_eigen_2(py::module &m, const char *name,
         .def("rowwiseMean", [](const Type &m) {return Type(m.rowwise().mean());} )
         .def("rowwiseNorm", [](const Type &m) {return Type(m.rowwise().norm());} )
         .def("rowwiseNormalized", [](const Type &m) {return Type(m.rowwise().normalized());} )
+        .def("rowwiseReverse", [](const Type &m) {return Type(m.rowwise().reverse());} )
         .def("rowwiseMinCoeff", [](const Type &m) {return Type(m.rowwise().minCoeff());} )
         .def("rowwiseMaxCoeff", [](const Type &m) {return Type(m.rowwise().maxCoeff());} )
 
@@ -188,6 +189,8 @@ py::class_<Type> bind_eigen_2(py::module &m, const char *name,
         .def("colwiseProd", [](const Type &m) {return Type(m.colwise().prod());} )
         .def("colwiseMean", [](const Type &m) {return Type(m.colwise().mean());} )
         .def("colwiseNorm", [](const Type &m) {return Type(m.colwise().norm());} )
+        .def("colwiseNormalized", [](const Type &m) {return Type(m.colwise().normalized());} )
+        .def("colwiseReverse", [](const Type &m) {return Type(m.colwise().reverse());} )
         .def("colwiseMinCoeff", [](const Type &m) {return Type(m.colwise().minCoeff());} )
         .def("colwiseMaxCoeff", [](const Type &m) {return Type(m.colwise().maxCoeff());} )
 
@@ -689,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");
     //

+ 124 - 0
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,45 @@ 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_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:
@@ -355,6 +395,23 @@ const char *__doc_igl_embree_ambient_occlusion = R"igl_Qu8mg5v7(// Compute ambie
     //    S  #P list of ambient occlusion values between 1 (fully occluded) and
     //      0 (not occluded)
     //)igl_Qu8mg5v7";
+const char *__doc_igl_embree_reorient_facets_raycast = R"igl_Qu8mg5v7(// Orient each component (identified by C) of a mesh (V,F) using ambient
+    // occlusion such that the front side is less occluded than back side, as
+    // described in "A Simple Method for Correcting Facet Orientations in
+    // Polygon Meshes Based on Ray Casting" [Takayama et al. 2014].
+    //
+    // Inputs:
+    //   V  #V by 3 list of vertex positions
+    //   F  #F by 3 list of triangle indices
+    //   rays_total  Total number of rays that will be shot
+    //   rays_minimum  Minimum number of rays that each patch should receive
+    //   facet_wise  Decision made for each face independently, no use of patches
+    //     (i.e., each face is treated as a patch)
+    //   use_parity  Use parity mode
+    //   is_verbose  Verbose output to cout
+    // Outputs:
+    //   I  #F list of whether face has been flipped
+    //   C  #F list of patch ID (output of bfs_orient > manifold patches))igl_Qu8mg5v7";
 const char *__doc_igl_find_cross_field_singularities = R"igl_Qu8mg5v7(// Inputs:
   //   V                #V by 3 eigen Matrix of mesh vertex 3D positions
   //   F                #F by 3 eigen Matrix of face (quad) indices
@@ -402,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
@@ -421,6 +494,16 @@ const char *__doc_igl_harmonic = R"igl_Qu8mg5v7(// Compute k-harmonic weight fun
   // Outputs:
   //   W  #V by #W list of weights
   //)igl_Qu8mg5v7";
+const char *__doc_igl_hsv_to_rgb = R"igl_Qu8mg5v7(// Convert RGB to HSV
+  //
+  // Inputs:
+  //   h  hue value (degrees: [0,360])
+  //   s  saturation value ([0,1])
+  //   v  value value ([0,1])
+  // Outputs:
+  //   r  red value ([0,1]) 
+  //   g  green value ([0,1])
+  //   b  blue value ([0,1]))igl_Qu8mg5v7";
 const char *__doc_igl_internal_angles = R"igl_Qu8mg5v7(// Compute internal angles for a triangle mesh
   //
   // Inputs:
@@ -713,6 +796,12 @@ const char *__doc_igl_quad_planarity = R"igl_Qu8mg5v7(// Compute planarity of th
   // Output:
   //   P  #F by 1 eigen Matrix of mesh face (quad) planarities
   //)igl_Qu8mg5v7";
+const char *__doc_igl_randperm = R"igl_Qu8mg5v7(// Like matlab's randperm(n) but minus 1
+  //
+  // Inputs:
+  //   n  number of elements
+  // Outputs:
+  //   I  n list of rand permutation of 0:n-1)igl_Qu8mg5v7";
 const char *__doc_igl_readDMAT = R"igl_Qu8mg5v7(See readDMAT for the documentation.)igl_Qu8mg5v7";
 const char *__doc_igl_readMESH = R"igl_Qu8mg5v7(// load a tetrahedral volume mesh from a .mesh file
   //
@@ -960,6 +1049,41 @@ const char *__doc_igl_upsample = R"igl_Qu8mg5v7(// Subdivide a mesh without movi
   //
   // Known issues:
   //   - assumes (V,F) is edge-manifold.)igl_Qu8mg5v7";
+const char *__doc_igl_winding_number = R"igl_Qu8mg5v7(// WINDING_NUMBER Compute the sum of solid angles of a triangle/tetrahedron
+  // described by points (vectors) V
+  //
+  // Templates:
+  //   dim  dimension of input
+  // Inputs:
+  //  V  n by 3 list of vertex positions
+  //  F  #F by 3 list of triangle indices, minimum index is 0
+  //  O  no by 3 list of origin positions
+  // Outputs:
+  //  S  no by 1 list of winding numbers
+  //
+  // 3d)igl_Qu8mg5v7";
+const char *__doc_igl_winding_number_3 = R"igl_Qu8mg5v7(// Inputs:
+  //   V  pointer to array containing #V by 3 vertex positions along rows,
+  //     given in column major order
+  //   n  number of mesh vertices
+  //   F  pointer to array containing #F by 3 face indices along rows,
+  //     given in column major order
+  //   m  number of faces
+  //   O  pointer to array containing #O by 3 query positions along rows,
+  //     given in column major order
+  //   no  number of origins
+  // Outputs:
+  //   S  no by 1 list of winding numbers)igl_Qu8mg5v7";
+const char *__doc_igl_winding_number_2 = R"igl_Qu8mg5v7(//// Only one evaluation origin
+  //template <typename DerivedF>
+  //IGL_INLINE void winding_number_3(
+  //  const double * V,
+  //  const int n,
+  //  const DerivedF * F,
+  //  const int m,
+  //  const double * O,
+  //  double * S);
+  // 2d)igl_Qu8mg5v7";
 const char *__doc_igl_writeMESH = R"igl_Qu8mg5v7(// save a tetrahedral volume mesh to a .mesh file
   //
   // Templates:

+ 10 - 0
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,8 @@ 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_swept_volume;
 extern const char *__doc_igl_copyleft_tetgen_tetrahedralize;
 extern const char *__doc_igl_cotmatrix;
 extern const char *__doc_igl_covariance_scatter_matrix;
@@ -25,14 +28,17 @@ extern const char *__doc_igl_doublearea_quad;
 extern const char *__doc_igl_edge_lengths;
 extern const char *__doc_igl_eigs;
 extern const char *__doc_igl_embree_ambient_occlusion;
+extern const char *__doc_igl_embree_reorient_facets_raycast;
 extern const char *__doc_igl_find_cross_field_singularities;
 extern const char *__doc_igl_fit_rotations;
 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;
 extern const char *__doc_igl_internal_angles;
 extern const char *__doc_igl_invert_diag;
 extern const char *__doc_igl_is_irregular_vertex;
@@ -58,6 +64,7 @@ extern const char *__doc_igl_point_mesh_squared_distance;
 extern const char *__doc_igl_polar_svd;
 extern const char *__doc_igl_principal_curvature;
 extern const char *__doc_igl_quad_planarity;
+extern const char *__doc_igl_randperm;
 extern const char *__doc_igl_readDMAT;
 extern const char *__doc_igl_readMESH;
 extern const char *__doc_igl_readOBJ;
@@ -78,5 +85,8 @@ extern const char *__doc_igl_unique;
 extern const char *__doc_igl_unique_rows;
 extern const char *__doc_igl_unproject_onto_mesh;
 extern const char *__doc_igl_upsample;
+extern const char *__doc_igl_winding_number;
+extern const char *__doc_igl_winding_number_3;
+extern const char *__doc_igl_winding_number_2;
 extern const char *__doc_igl_writeMESH;
 extern const char *__doc_igl_writeOBJ;

+ 10 - 0
python/py_igl.cpp

@@ -14,6 +14,7 @@
 #include <igl/boundary_facets.h>
 #include <igl/boundary_loop.h>
 #include <igl/cat.h>
+#include <igl/collapse_edge.h>
 #include <igl/colon.h>
 #include <igl/comb_cross_field.h>
 #include <igl/comb_frame_field.h>
@@ -29,8 +30,10 @@
 #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>
 #include <igl/internal_angles.h>
 #include <igl/invert_diag.h>
 #include <igl/is_irregular_vertex.h>
@@ -51,6 +54,7 @@
 #include <igl/polar_svd.h>
 #include <igl/principal_curvature.h>
 #include <igl/quad_planarity.h>
+#include <igl/randperm.h>
 #include <igl/readDMAT.h>
 #include <igl/readMESH.h>
 #include <igl/readOBJ.h>
@@ -67,6 +71,7 @@
 #include <igl/unique.h>
 #include <igl/unproject_onto_mesh.h>
 #include <igl/upsample.h>
+#include <igl/winding_number.h>
 #include <igl/writeMESH.h>
 #include <igl/writeOBJ.h>
 
@@ -85,6 +90,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"
@@ -100,8 +106,10 @@ 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"
 #include "py_igl/py_internal_angles.cpp"
 #include "py_igl/py_invert_diag.cpp"
 #include "py_igl/py_is_irregular_vertex.cpp"
@@ -122,6 +130,7 @@ void python_export_igl(py::module &m)
 #include "py_igl/py_polar_svd.cpp"
 #include "py_igl/py_principal_curvature.cpp"
 #include "py_igl/py_quad_planarity.cpp"
+#include "py_igl/py_randperm.cpp"
 #include "py_igl/py_readDMAT.cpp"
 #include "py_igl/py_readMESH.cpp"
 #include "py_igl/py_readOBJ.cpp"
@@ -138,6 +147,7 @@ void python_export_igl(py::module &m)
 #include "py_igl/py_unique.cpp"
 #include "py_igl/py_unproject_onto_mesh.cpp"
 #include "py_igl/py_upsample.cpp"
+#include "py_igl/py_winding_number.cpp"
 #include "py_igl/py_writeMESH.cpp"
 #include "py_igl/py_writeOBJ.cpp"
 

+ 21 - 0
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"));
+

+ 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"));
+
+
+

+ 37 - 0
python/py_igl/embree/py_reorient_facets_raycast.cpp

@@ -0,0 +1,37 @@
+
+
+m.def("reorient_facets_raycast", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  int rays_total,
+  int rays_minimum,
+  bool facet_wise,
+  bool use_parity,
+  bool is_verbose,
+  Eigen::MatrixXi& I,
+  Eigen::MatrixXi& C
+)
+{
+  Eigen::VectorXi Iv;
+  Eigen::VectorXi Cv;
+  igl::embree::reorient_facets_raycast(V, F, rays_total, rays_minimum, facet_wise, use_parity, is_verbose, Iv, Cv);
+  I = Iv;
+  C = Cv;
+}, __doc_igl_embree_reorient_facets_raycast,
+py::arg("V"), py::arg("F"), py::arg("rays_total"), py::arg("rays_minimum"), py::arg("facet_wise"), py::arg("use_parity"), py::arg("is_verbose"), py::arg("I"), py::arg("C"));
+
+m.def("reorient_facets_raycast", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  Eigen::MatrixXi& FF,
+  Eigen::MatrixXi& I
+)
+{
+  Eigen::VectorXi Iv;
+  igl::embree::reorient_facets_raycast(V, F, FF, Iv);
+  I = Iv;
+}, __doc_igl_embree_reorient_facets_raycast,
+py::arg("V"), py::arg("F"), py::arg("FF"), py::arg("I"));
+

+ 87 - 0
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<void (const int, const Eigen::MatrixXd &, const Eigen::MatrixXi &, const Eigen::MatrixXi &, const Eigen::VectorXi &, const Eigen::MatrixXi &, const Eigen::MatrixXi &, double &, Eigen::RowVectorXd &)> & cost_and_placement,
+//  Eigen::MatrixXd& V,
+//  Eigen::MatrixXi& F,
+//  Eigen::MatrixXi& E,
+//  Eigen::MatrixXi& EMAP,
+//  Eigen::MatrixXi& EF,
+//  Eigen::MatrixXi& EI,
+//  std::set<std::pair<double, int> > & Q,
+//  std::vector<std::set<std::pair<double, int> >::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<void (const int, const Eigen::MatrixXd &, const Eigen::MatrixXi &, const Eigen::MatrixXi &, const Eigen::VectorXi &, const Eigen::MatrixXi &, const Eigen::MatrixXi &, double &, Eigen::RowVectorXd &)> & cost_and_placement,
+//  Eigen::MatrixXd& V,
+//  Eigen::MatrixXi& F,
+//  Eigen::MatrixXi& E,
+//  Eigen::MatrixXi& EMAP,
+//  Eigen::MatrixXi& EF,
+//  Eigen::MatrixXi& EI,
+//  std::set<std::pair<double, int> > & Q,
+//  std::vector<std::set<std::pair<double, int> >::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"));
+

+ 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);
+

+ 44 - 0
python/py_igl/py_hsv_to_rgb.cpp

@@ -0,0 +1,44 @@
+// COMPLETE BINDINGS ========================
+
+
+m.def("hsv_to_rgb", []
+(
+  const Eigen::MatrixXd& H,
+  Eigen::MatrixXd& R
+)
+{
+  return igl::hsv_to_rgb(H, R);
+}, __doc_igl_hsv_to_rgb,
+py::arg("H"), py::arg("R"));
+
+
+
+
+
+// INCOMPLETE BINDINGS ========================
+
+
+//m.def("hsv_to_rgb", []
+//(
+//  T * hsv,
+//  T * rgb
+//)
+//{
+//  return igl::hsv_to_rgb(hsv, rgb);
+//}, __doc_igl_hsv_to_rgb,
+//py::arg("hsv"), py::arg("rgb"));
+
+//m.def("hsv_to_rgb", []
+//(
+//  T & h,
+//  T & s,
+//  T & v,
+//  T & r,
+//  T & g,
+//  T & b
+//)
+//{
+//  return igl::hsv_to_rgb(h, s, v, r, g, b);
+//}, __doc_igl_hsv_to_rgb,
+//py::arg("h"), py::arg("s"), py::arg("v"), py::arg("r"), py::arg("g"), py::arg("b"));
+

+ 10 - 0
python/py_igl/py_randperm.cpp

@@ -0,0 +1,10 @@
+m.def("randperm", []
+(
+  int n,
+  Eigen::MatrixXi& I
+)
+{
+  return igl::randperm(n, I);
+}, __doc_igl_randperm,
+py::arg("n"), py::arg("I"));
+

+ 4 - 4
python/py_igl/py_slice_tets.cpp

@@ -6,15 +6,15 @@ m.def("slice_tets", []
   Eigen::MatrixXd& U,
   Eigen::MatrixXi& G,
   Eigen::MatrixXi& J,
-  Eigen::SparseMatrix<double> & BC
+  Eigen::SparseMatrix<double>& BC
 )
 {
   assert_is_VectorX("plane", plane);
-  Eigen::VectorXd pl;
+  Eigen::VectorXd planev;
   if (plane.size() != 0)
-    pl = plane;
+    planev = plane;
   Eigen::VectorXi Jv;
-  igl::slice_tets(V, T, pl, U, G, Jv, BC);
+  igl::slice_tets(V, T, planev, U, G, Jv, BC);
   J = Jv;
 }, __doc_igl_slice_tets,
 py::arg("V"), py::arg("T"), py::arg("plane"), py::arg("U"), py::arg("G"), py::arg("J"), py::arg("BC"));

+ 18 - 0
python/py_igl/py_winding_number.cpp

@@ -0,0 +1,18 @@
+// COMPLETE BINDINGS ========================
+
+
+m.def("winding_number", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  const Eigen::MatrixXd& O,
+  Eigen::MatrixXd& W
+)
+{
+  Eigen::VectorXd Wv;
+  igl::winding_number(V, F, O, Wv);
+  W = Wv;
+}, __doc_igl_winding_number,
+py::arg("V"), py::arg("F"), py::arg("O"), py::arg("W"));
+
+

+ 16 - 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
@@ -56,6 +60,7 @@ PYBIND11_PLUGIN(pyigl) {
            boundary_facets
            boundary_loop
            cat
+           collapse_edge
            colon
            comb_cross_field
            comb_frame_field
@@ -63,6 +68,8 @@ PYBIND11_PLUGIN(pyigl) {
            copyleft_cgal_mesh_boolean
            copyleft_comiso_miq
            copyleft_comiso_nrosy
+           copyleft_marching_cubes
+           copyleft_swept_volume
            copyleft_tetgen_tetrahedralize
            cotmatrix
            covariance_scatter_matrix
@@ -72,12 +79,15 @@ PYBIND11_PLUGIN(pyigl) {
            edge_lengths
            eigs
            embree_ambient_occlusion
+           embree_reorient_facets_raycast
            find_cross_field_singularities
            fit_rotations
            floor
            gaussian_curvature
+           get_seconds
            grad
            harmonic
+           hsv_to_rgb
            internal_angles
            invert_diag
            is_irregular_vertex
@@ -100,6 +110,7 @@ PYBIND11_PLUGIN(pyigl) {
            polar_svd
            principal_curvature
            quad_planarity
+           randperm
            readDMAT
            readMESH
            readOBJ
@@ -117,6 +128,7 @@ PYBIND11_PLUGIN(pyigl) {
            unique
            unproject_onto_mesh
            upsample
+           winding_number
            writeMESH
            writeOBJ
 
@@ -154,5 +166,9 @@ PYBIND11_PLUGIN(pyigl) {
     python_export_igl_png(m);
     #endif
 
+    #ifdef PY_COPYLEFT
+    python_export_igl_copyleft(m);
+    #endif
+
     return m.ptr();
 }

+ 1 - 1
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

+ 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();
 }

+ 112 - 0
python/tutorial/702_WindingNumber.py

@@ -0,0 +1,112 @@
+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 = ["viewer"]
+check_dependencies(dependencies)
+
+
+def append_mesh(C_vis, F_vis, V_vis, V, F, color):
+    F_vis.conservativeResize(F_vis.rows() + F.rows(), 3)
+    F_vis.setBottomRows(F.rows(), F + V_vis.rows())
+    V_vis.conservativeResize(V_vis.rows() + V.rows(), 3)
+    V_vis.setBottomRows(V.rows(), V)
+    C_vis.conservativeResize(C_vis.rows() + F.rows(), 3)
+    colorM = igl.eigen.MatrixXd(F.rows(), C_vis.cols())
+    colorM.rowwiseSet(color)
+    C_vis.setBottomRows(F.rows(), colorM)
+
+
+def update(viewer):
+    global V, F, T, W, slice_z, overlay
+    plane = igl.eigen.MatrixXd([0, 0, 1, -((1 - slice_z) * V.col(2).minCoeff() + slice_z * V.col(2).maxCoeff())])
+    V_vis = igl.eigen.MatrixXd()
+    F_vis = igl.eigen.MatrixXi()
+    J = igl.eigen.MatrixXi()
+    bary = igl.eigen.SparseMatrixd()
+    igl.slice_tets(V, T, plane, V_vis, F_vis, J, bary)
+    W_vis = igl.eigen.MatrixXd()
+    igl.slice(W, J, W_vis)
+    C_vis = igl.eigen.MatrixXd()
+    igl.parula(W_vis, False, C_vis)
+
+    if overlay == 1:  # OVERLAY_INPUT
+        append_mesh(C_vis, F_vis, V_vis, V, F, igl.eigen.MatrixXd([[1., 0.894, 0.227]]))
+    elif overlay == 2:  # OVERLAY_OUTPUT
+        append_mesh(C_vis, F_vis, V_vis, V, F, igl.eigen.MatrixXd([[0.8, 0.8, 0.8]]))
+
+    viewer.data.clear()
+    viewer.data.set_mesh(V_vis, F_vis)
+    viewer.data.set_colors(C_vis)
+    viewer.data.set_face_based(True)
+
+
+def key_down(viewer, key, modifier):
+    global overlay, slice_z
+
+    if key == ord(' '):
+        overlay = (overlay + 1) % 3
+    elif key == ord('.'):
+        slice_z = min(slice_z + 0.01, 0.99)
+    elif key == ord(','):
+        slice_z = max(slice_z - 0.01, 0.01)
+
+    update(viewer)
+
+    return False
+
+
+if __name__ == "__main__":
+    keys = {"space": "toggle showing input mesh, output mesh or slice through tet-mesh of convex hull",
+            ". / ,": "push back/pull forward slicing plane"}
+
+    print_usage(keys)
+
+    V = igl.eigen.MatrixXd()
+    BC = igl.eigen.MatrixXd()
+    W = igl.eigen.MatrixXd()
+    T = igl.eigen.MatrixXi()
+    F = igl.eigen.MatrixXi()
+    G = igl.eigen.MatrixXi()
+
+    slice_z = 0.5
+    overlay = 0
+
+    # Load mesh: (V,T) tet-mesh of convex hull, F contains facets of input
+    # surface mesh _after_ self-intersection resolution
+    igl.readMESH(TUTORIAL_SHARED_PATH + "big-sigcat.mesh", V, T, F)
+
+    # Compute barycenters of all tets
+    igl.barycenter(V, T, BC)
+
+    # Compute generalized winding number at all barycenters
+    print("Computing winding number over all %i tets..." % T.rows())
+    igl.winding_number(V, F, BC, W)
+
+    # Extract interior tets
+    Wt = sum(W > 0.5)
+    CT = igl.eigen.MatrixXi(Wt, 4)
+    k = 0
+    for t in range(T.rows()):
+        if W[t] > 0.5:
+            CT.setRow(k, T.row(t))
+            k += 1
+
+    # find bounary facets of interior tets
+    igl.boundary_facets(CT, G)
+
+    # boundary_facets seem to be reversed...
+    G = G.rowwiseReverse()
+
+    # normalize
+    W = (W - W.minCoeff()) / (W.maxCoeff() - W.minCoeff())
+
+    # Plot the generated mesh
+    viewer = igl.viewer.Viewer()
+    update(viewer)
+    viewer.callback_key_down = key_down
+    viewer.launch()

+ 94 - 0
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", "viewer"]
+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()

+ 78 - 0
python/tutorial/706_FacetOrientation.py

@@ -0,0 +1,78 @@
+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 = ["embree", "viewer"]
+check_dependencies(dependencies)
+
+
+def key_down(viewer, key, modifier):
+    global facetwise, is_showing_reoriented, FF
+    if key == ord('F') or key == ord('f'):
+        facetwise = (facetwise + 1) % 2
+    elif key == ord('S') or key == ord('s'):
+        scramble_colors()
+    elif key == ord(' '):
+        is_showing_reoriented = ~is_showing_reoriented
+
+    viewer.data.clear()
+    viewer.data.set_mesh(V, FF[facetwise] if is_showing_reoriented else F)
+    viewer.data.set_colors(RGBcolors[facetwise])
+
+    return True
+
+def scramble_colors():
+    global C, viewer, RGBcolors
+    for p in range(2):
+        R = igl.eigen.MatrixXi()
+        igl.randperm(C[p].maxCoeff() + 1, R)
+        C[p] = igl.slice(R, igl.eigen.MatrixXi(C[p]))
+        HSV = igl.eigen.MatrixXd(C[p].rows(), 3)
+        HSV.setCol(0, 360.0 * C[p].castdouble() / C[p].maxCoeff())
+        HSVright = igl.eigen.MatrixXd(HSV.rows(), 2)
+        HSVright.setConstant(1.0)
+        HSV.setRightCols(2, HSVright)
+        igl.hsv_to_rgb(HSV, RGBcolors[p])
+    viewer.data.set_colors(RGBcolors[facetwise])
+
+
+
+if __name__ == "__main__":
+    keys = {"space": "toggle between original and reoriented faces",
+            "F,f": "toggle between patchwise and facetwise reorientation",
+            "S,s": "scramble colors"}
+    print_usage(keys)
+
+    V = igl.eigen.MatrixXd()
+    F = igl.eigen.MatrixXi()
+    C = [igl.eigen.MatrixXi(), igl.eigen.MatrixXi()]
+    RGBcolors = [igl.eigen.MatrixXd(), igl.eigen.MatrixXd()]
+    FF = [igl.eigen.MatrixXi(), igl.eigen.MatrixXi()]
+    is_showing_reoriented = False
+    facetwise = 0
+
+    igl.read_triangle_mesh(TUTORIAL_SHARED_PATH + "truck.obj", V, F)
+
+    # Compute patches
+    for p in range(2):
+        I = igl.eigen.MatrixXi()
+        igl.embree.reorient_facets_raycast(V, F, F.rows() * 100, 10, p == 1, False, False, I, C[p])
+        # apply reorientation
+        FF[p].conservativeResize(F.rows(), F.cols())
+        for i in range(I.rows()):
+            if I[i]:
+                FF[p].setRow(i, F.row(i).rowwiseReverse())
+            else:
+                FF[p].setRow(i, F.row(i))
+
+    # Plot the generated mesh
+    viewer = igl.viewer.Viewer()
+    viewer.data.set_mesh(V, FF[facetwise] if is_showing_reoriented else F)
+    viewer.data.set_face_based(True)
+    scramble_colors()
+    viewer.callback_key_down = key_down
+    viewer.launch()

+ 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()

+ 21 - 18
python/tutorial/607_Picking.py → python/tutorial/708_Picking.py

@@ -5,19 +5,12 @@ sys.path.insert(0, os.getcwd() + "/../")
 import pyigl as igl
 
 
-from shared import TUTORIAL_SHARED_PATH, check_dependencies
+from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
 
 dependencies = ["viewer"]
 check_dependencies(dependencies)
 
 
-# Mesh with per-face color
-V = igl.eigen.MatrixXd()
-F = igl.eigen.MatrixXi()
-C = igl.eigen.MatrixXd()
-
-viewer = igl.viewer.Viewer()
-
 def mouse_down(viewer, a, b):
     bc = igl.eigen.MatrixXd()
 
@@ -27,6 +20,7 @@ def mouse_down(viewer, a, b):
     hit = igl.unproject_onto_mesh(coord, viewer.core.view * viewer.core.model,
       viewer.core.proj, viewer.core.viewport, V, F, fid, bc)
     if hit:
+        # paint hit red
         C.setRow(fid[0, 0], igl.eigen.MatrixXd([[1, 0, 0]]))
         viewer.data.set_colors(C)
         return True
@@ -34,16 +28,25 @@ def mouse_down(viewer, a, b):
     return False
 
 
-print("Usage: [LeftMouseClick] to select a face")
+if __name__ == "__main__":
+    keys = {"click": "Pick face on shape"}
+    print_usage(keys)
+
+    # Mesh with per-face color
+    V = igl.eigen.MatrixXd()
+    F = igl.eigen.MatrixXi()
+    C = igl.eigen.MatrixXd()
 
-# Load a mesh in OFF format
-igl.readOFF(TUTORIAL_SHARED_PATH + "fertility.off", V, F)
+    # Load a mesh in OFF format
+    igl.readOFF(TUTORIAL_SHARED_PATH + "fertility.off", V, F)
 
-# Initialize white
-C.setConstant(F.rows(), 3, 1.0)
+    # Initialize white
+    C.setConstant(F.rows(), 3, 1.0)
 
-viewer.data.set_mesh(V, F)
-viewer.data.set_colors(C)
-viewer.core.show_lines = False
-viewer.callback_mouse_down = mouse_down
-viewer.launch()
+    # Show mesh
+    viewer = igl.viewer.Viewer()
+    viewer.data.set_mesh(V, F)
+    viewer.data.set_colors(C)
+    viewer.core.show_lines = False
+    viewer.callback_mouse_down = mouse_down
+    viewer.launch()

+ 6 - 0
python/tutorial/shared.py

@@ -14,3 +14,9 @@ def check_dependencies(deps):
 
     if not all_available:
         sys.exit(-1)
+
+
+def print_usage(key_dict):
+    print("Usage:")
+    for k in key_dict.keys():
+        print("%s : %s" %(k, key_dict[k]))