Browse Source

Merge branch 's-koch-python_bindings'

Former-commit-id: 9b44a166c43928f29f930669cbd6cee5156309fa
Daniele Panozzo 9 years ago
parent
commit
fa4977167b

+ 182 - 0
python/py_doc.cpp

@@ -150,6 +150,21 @@ const char *__doc_igl_jet = R"igl_Qu8mg5v7(// JET like MATLAB's jet
   //   r  red value
   //   g  green value
   //   b  blue value)igl_Qu8mg5v7";
+const char *__doc_igl_cat = R"igl_Qu8mg5v7(// Perform concatenation of a two matrices along a single dimension
+  // If dim == 1, then C = [A;B]. If dim == 2 then C = [A B]
+  // 
+  // Template:
+  //   Scalar  scalar data type for sparse matrices like double or int
+  //   Mat  matrix type for all matrices (e.g. MatrixXd, SparseMatrix)
+  //   MatC  matrix type for ouput matrix (e.g. MatrixXd) needs to support
+  //     resize
+  // Inputs:
+  //   A  first input matrix
+  //   B  second input matrix
+  //   dim  dimension along which to concatenate, 0 or 1
+  // Outputs:
+  //   C  output matrix
+  //   )igl_Qu8mg5v7";
 const char *__doc_igl_eigs = R"igl_Qu8mg5v7(See eigs for the documentation.)igl_Qu8mg5v7";
 const char *__doc_igl_per_corner_normals = R"igl_Qu8mg5v7(// Compute vertex normals via vertex position list, face list
   // Inputs:
@@ -198,6 +213,29 @@ const char *__doc_igl_colon = R"igl_Qu8mg5v7(// Colon operator like matlab's col
   //     than hi, vice versa if hi<low
   // Output:
   //   I  list of values from low to hi with step size step)igl_Qu8mg5v7";
+const char *__doc_igl_fit_rotations = R"igl_Qu8mg5v7(// Known issues: This seems to be implemented in Eigen/Geometry:
+  // Eigen::umeyama
+  //
+  // FIT_ROTATIONS Given an input mesh and new positions find rotations for
+  // every covariance matrix in a stack of covariance matrices
+  // 
+  // Inputs:
+  //   S  nr*dim by dim stack of covariance matrices
+  //   single_precision  whether to use single precision (faster)
+  // Outputs:
+  //   R  dim by dim * nr list of rotations
+  //)igl_Qu8mg5v7";
+const char *__doc_igl_fit_rotations_planar = R"igl_Qu8mg5v7(// FIT_ROTATIONS Given an input mesh and new positions find 2D rotations for
+  // every vertex that best maps its one ring to the new one ring
+  // 
+  // Inputs:
+  //   S  nr*dim by dim stack of covariance matrices, third column and every
+  //   third row will be ignored
+  // Outputs:
+  //   R  dim by dim * nr list of rotations, third row and third column of each
+  //   rotation will just be identity
+  //)igl_Qu8mg5v7";
+const char *__doc_igl_fit_rotations_SSE = R"igl_Qu8mg5v7(See fit_rotations_SSE for the documentation.)igl_Qu8mg5v7";
 const char *__doc_igl_rotate_vectors = R"igl_Qu8mg5v7(// Rotate the vectors V by A radiants on the tangent plane spanned by B1 and
   // B2
   //
@@ -245,6 +283,17 @@ const char *__doc_igl_avg_edge_length = R"igl_Qu8mg5v7(// Compute the average ed
   //   l  average edge length
   //
   // See also: adjacency_matrix)igl_Qu8mg5v7";
+const char *__doc_igl_barycentric_coordinates = R"igl_Qu8mg5v7(// Compute barycentric coordinates in a tet
+  //
+  // Inputs:
+  //   P  #P by 3 Query points in 3d
+  //   A  #P by 3 Tet corners in 3d
+  //   B  #P by 3 Tet corners in 3d
+  //   C  #P by 3 Tet corners in 3d
+  //   D  #P by 3 Tet corners in 3d
+  // Outputs:
+  //   L  #P by 4 list of barycentric coordinates
+  //   )igl_Qu8mg5v7";
 const char *__doc_igl_lscm = R"igl_Qu8mg5v7(// Compute a Least-squares conformal map parametrization (equivalently
   // derived in "Intrinsic Parameterizations of Surface Meshes" [Desbrun et al.
   // 2002] and "Least Squares Conformal Maps for Automatic Texture Atlas
@@ -273,6 +322,41 @@ const char *__doc_igl_find_cross_field_singularities = R"igl_Qu8mg5v7(// Inputs:
   //   isSingularity    #V by 1 boolean eigen Vector indicating the presence of a singularity on a vertex
   //   singularityIndex #V by 1 integer eigen Vector containing the singularity indices
   //)igl_Qu8mg5v7";
+const char *__doc_igl_upsample = R"igl_Qu8mg5v7(// Subdivide a mesh without moving vertices: loop subdivision but odd
+  // vertices stay put and even vertices are just edge midpoints
+  // 
+  // Templates:
+  //   MatV  matrix for vertex positions, e.g. MatrixXd
+  //   MatF  matrix for vertex positions, e.g. MatrixXi
+  // Inputs:
+  //   V  #V by dim  mesh vertices
+  //   F  #F by 3  mesh triangles
+  // Outputs:
+  //   NV new vertex positions, V is guaranteed to be at top
+  //   NF new list of face indices
+  //
+  // NOTE: V should not be the same as NV,
+  // NOTE: F should not be the same as NF, use other proto
+  //
+  // Known issues:
+  //   - assumes (V,F) is edge-manifold.)igl_Qu8mg5v7";
+const char *__doc_igl_point_mesh_squared_distance = R"igl_Qu8mg5v7(// Compute distances from a set of points P to a triangle mesh (V,F)
+  //
+  // Inputs:
+  //   P  #P by 3 list of query point positions
+  //   V  #V by 3 list of vertex positions
+  //   Ele  #Ele by (3|2|1) list of (triangle|edge|point) indices
+  // Outputs:
+  //   sqrD  #P list of smallest squared distances
+  //   I  #P list of primitive indices corresponding to smallest distances
+  //   C  #P by 3 list of closest points
+  //
+  // Known bugs: This only computes distances to given primitivess. So
+  // unreferenced vertices are ignored. However, degenerate primitives are
+  // handled correctly: triangle [1 2 2] is treated as a segment [1 2], and
+  // triangle [1 1 1] is treated as a point. So one _could_ add extra
+  // combinatorially degenerate rows to Ele for all unreferenced vertices to
+  // also get distances to points.)igl_Qu8mg5v7";
 const char *__doc_igl_parula = R"igl_Qu8mg5v7(// PARULA like MATLAB's parula
   //
   // Inputs:
@@ -361,6 +445,27 @@ const char *__doc_igl_active_set = R"igl_Qu8mg5v7(// Known Bugs: rows of [Aeq;Ai
   // Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2
   // secs, igl/min_quad_with_fixed.h 7.1 secs
   //)igl_Qu8mg5v7";
+const char *__doc_igl_per_edge_normals = R"igl_Qu8mg5v7(// Compute face normals via vertex position list, face list
+  // Inputs:
+  //   V  #V by 3 eigen Matrix of mesh vertex 3D positions
+  //   F  #F by 3 eigen Matrix of face (triangle) indices
+  //   weight  weighting type
+  //   FN  #F by 3 matrix of 3D face normals per face
+  // Output:
+  //   N  #2 by 3 matrix of mesh edge 3D normals per row
+  //   E  #E by 2 matrix of edge indices per row
+  //   EMAP  #E by 1 matrix of indices from all edges to E
+  //)igl_Qu8mg5v7";
+const char *__doc_igl_covariance_scatter_matrix = R"igl_Qu8mg5v7(// Construct the covariance scatter matrix for a given arap energy
+  // Inputs:
+  //   V  #V by Vdim list of initial domain positions
+  //   F  #F by 3 list of triangle indices into V
+  //   energy  ARAPEnergyType enum value defining which energy is being used.
+  //     See ARAPEnergyType.h for valid options and explanations.
+  // Outputs:
+  //   CSM dim*#V/#F by dim*#V sparse matrix containing special laplacians along
+  //     the diagonal so that when multiplied by V gives covariance matrix
+  //     elements, can be used to speed up covariance matrix computation)igl_Qu8mg5v7";
 const char *__doc_igl_boundary_facets = R"igl_Qu8mg5v7(// BOUNDARY_FACETS Determine boundary faces (edges) of tetrahedra (triangles)
   // stored in T (analogous to qptoolbox's `outline` and `boundary_faces`).
   //
@@ -385,6 +490,27 @@ const char *__doc_igl_compute_frame_field_bisectors = R"igl_Qu8mg5v7(// Compute
   //   BIS1  #F by 3 eigen Matrix of the first per face frame field bisector
   //   BIS2  #F by 3 eigen Matrix of the second per face frame field bisector
   //)igl_Qu8mg5v7";
+const char *__doc_igl_edge_lengths = R"igl_Qu8mg5v7(// Constructs a list of lengths of edges opposite each index in a face
+  // (triangle/tet) list
+  //
+  // Templates:
+  //   DerivedV derived from vertex positions matrix type: i.e. MatrixXd
+  //   DerivedF derived from face indices matrix type: i.e. MatrixXi
+  //   DerivedL derived from edge lengths matrix type: i.e. MatrixXd
+  // Inputs:
+  //   V  eigen matrix #V by 3
+  //   F  #F by 2 list of mesh edges
+  //    or
+  //   F  #F by 3 list of mesh faces (must be triangles)
+  //    or
+  //   T  #T by 4 list of mesh elements (must be tets)
+  // Outputs:
+  //   L  #F by {1|3|6} list of edge lengths 
+  //     for edges, column of lengths
+  //     for triangles, columns correspond to edges [1,2],[2,0],[0,1]
+  //     for tets, columns correspond to edges
+  //     [3 0],[3 1],[3 2],[1 2],[2 0],[0 1]
+  //)igl_Qu8mg5v7";
 const char *__doc_igl_readOBJ = R"igl_Qu8mg5v7(// Read a mesh from an ascii obj file, filling in vertex positions, normals
   // and texture coordinates. Mesh may have faces of any number of degree
   //
@@ -487,6 +613,18 @@ const char *__doc_igl_min_quad_with_fixed_solve = R"igl_Qu8mg5v7(// Solves a sys
   //   sol  #unknowns+#lagrange by cols solution to linear system
   // Returns true on success, false on error)igl_Qu8mg5v7";
 const char *__doc_igl_min_quad_with_fixed = R"igl_Qu8mg5v7(See min_quad_with_fixed for the documentation.)igl_Qu8mg5v7";
+const char *__doc_igl_writeMESH = R"igl_Qu8mg5v7(// save a tetrahedral volume mesh to a .mesh file
+  //
+  // Templates:
+  //   Scalar  type for positions and vectors (will be cast as double)
+  //   Index  type for indices (will be cast to int)
+  // Input:
+  //   mesh_file_name  path of .mesh file
+  //   V  double matrix of vertex positions  #V by 3
+  //   T  #T list of tet indices into vertex positions
+  //   F  #F list of face indices into vertex positions
+  //
+  // Known bugs: Holes and regions are not supported)igl_Qu8mg5v7";
 const char *__doc_igl_unique = R"igl_Qu8mg5v7(// Act like matlab's [C,IA,IC] = unique(X)
   //
   // Templates:
@@ -550,6 +688,23 @@ const char *__doc_igl_slice_into = R"igl_Qu8mg5v7(// Act like the matlab Y(row_i
   //   Y  ym by yn lhs matrix
   // Output:
   //   Y  ym by yn lhs matrix, same as input but Y(R,C) = X)igl_Qu8mg5v7";
+const char *__doc_igl_slice_tets = R"igl_Qu8mg5v7(// SLICE_TETS Slice through a tet mesh (V,T) along a given plane (via its
+  // implicit equation).
+  //
+  // Inputs:
+  //   V  #V by 3 list of tet mesh vertices
+  //   T  #T by 4 list of tet indices into V 
+  //   plane  list of 4 coefficients in the plane equation: [x y z 1]'*plane = 0
+  //   Optional:
+  //     'Manifold' followed by whether to stitch together triangles into a
+  //       manifold mesh {true}: results in more compact U but slightly slower.
+  // Outputs:
+  //   U  #U by 3 list of triangle mesh vertices along slice
+  //   G  #G by 3 list of triangles indices into U
+  //   J  #G list of indices into T revealing from which tet each faces comes
+  //   BC  #U by #V list of barycentric coordinates (or more generally: linear
+  //     interpolation coordinates) so that U = BC*V
+  // )igl_Qu8mg5v7";
 const char *__doc_igl_n_polyvector = R"igl_Qu8mg5v7(// Inputs:
   //   v0, v1         the two #3 by 1 vectors
   //   normalized     boolean, if false, then the vectors are normalized prior to the calculation
@@ -577,6 +732,19 @@ const char *__doc_igl_boundary_loop = R"igl_Qu8mg5v7(// Compute list of ordered
   // Outputs:
   //   L  list of loops where L[i] = ordered list of boundary vertices in loop i
   //)igl_Qu8mg5v7";
+const char *__doc_igl_polar_svd = R"igl_Qu8mg5v7(// Computes the polar decomposition (R,T) of a matrix A using SVD singular
+  // value decomposition
+  //
+  // Inputs:
+  //   A  3 by 3 matrix to be decomposed
+  // Outputs:
+  //   R  3 by 3 rotation matrix part of decomposition (**always rotataion**)
+  //   T  3 by 3 stretch matrix part of decomposition
+  //   U  3 by 3 left-singular vectors
+  //   S  3 by 1 singular values
+  //   V  3 by 3 right-singular vectors
+  //
+  //)igl_Qu8mg5v7";
 const char *__doc_igl_comb_cross_field = R"igl_Qu8mg5v7(// Inputs:
   //   V          #V by 3 eigen Matrix of mesh vertex 3D positions
   //   F          #F by 4 eigen Matrix of face (quad) indices
@@ -592,6 +760,20 @@ const char *__doc_igl_invert_diag = R"igl_Qu8mg5v7(// Templates:
   //   X  an m by n sparse matrix
   // Outputs:
   //   Y  an m by n sparse matrix)igl_Qu8mg5v7";
+const char *__doc_igl_readMESH = R"igl_Qu8mg5v7(// load a tetrahedral volume mesh from a .mesh file
+  //
+  // Templates:
+  //   Scalar  type for positions and vectors (will be read as double and cast
+  //     to Scalar)
+  //   Index  type for indices (will be read as int and cast to Index)
+  // Input:
+  //   mesh_file_name  path of .mesh file
+  // Outputs:
+  //   V  double matrix of vertex positions  #V by 3
+  //   T  #T list of tet indices into vertex positions
+  //   F  #F list of face indices into vertex positions
+  //
+  // Known bugs: Holes and regions are not supported)igl_Qu8mg5v7";
 const char *__doc_igl_copyleft_comiso_miq = R"igl_Qu8mg5v7(// Inputs:
     //   V              #V by 3 list of mesh vertex 3D positions
     //   F              #F by 3 list of faces indices in V

+ 14 - 0
python/py_doc.h

@@ -10,24 +10,34 @@ extern const char *__doc_igl_per_vertex_normals;
 extern const char *__doc_igl_sortrows;
 extern const char *__doc_igl_barycenter;
 extern const char *__doc_igl_jet;
+extern const char *__doc_igl_cat;
 extern const char *__doc_igl_eigs;
 extern const char *__doc_igl_per_corner_normals;
 extern const char *__doc_igl_massmatrix;
 extern const char *__doc_igl_colon;
+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_rotate_vectors;
 extern const char *__doc_igl_read_triangle_mesh;
 extern const char *__doc_igl_gaussian_curvature;
 extern const char *__doc_igl_avg_edge_length;
+extern const char *__doc_igl_barycentric_coordinates;
 extern const char *__doc_igl_lscm;
 extern const char *__doc_igl_find_cross_field_singularities;
+extern const char *__doc_igl_upsample;
+extern const char *__doc_igl_point_mesh_squared_distance;
 extern const char *__doc_igl_parula;
 extern const char *__doc_igl_setdiff;
 extern const char *__doc_igl_comb_frame_field;
 extern const char *__doc_igl_map_vertices_to_circle;
 extern const char *__doc_igl_writeOBJ;
 extern const char *__doc_igl_active_set;
+extern const char *__doc_igl_per_edge_normals;
+extern const char *__doc_igl_covariance_scatter_matrix;
 extern const char *__doc_igl_boundary_facets;
 extern const char *__doc_igl_compute_frame_field_bisectors;
+extern const char *__doc_igl_edge_lengths;
 extern const char *__doc_igl_readOBJ;
 extern const char *__doc_igl_cut_mesh_from_singularities;
 extern const char *__doc_igl_readDMAT;
@@ -37,6 +47,7 @@ extern const char *__doc_igl_doublearea_quad;
 extern const char *__doc_igl_min_quad_with_fixed_precompute;
 extern const char *__doc_igl_min_quad_with_fixed_solve;
 extern const char *__doc_igl_min_quad_with_fixed;
+extern const char *__doc_igl_writeMESH;
 extern const char *__doc_igl_unique;
 extern const char *__doc_igl_unique_rows;
 extern const char *__doc_igl_arap_precomputation;
@@ -44,10 +55,13 @@ extern const char *__doc_igl_arap_solve;
 extern const char *__doc_igl_cross_field_missmatch;
 extern const char *__doc_igl_grad;
 extern const char *__doc_igl_slice_into;
+extern const char *__doc_igl_slice_tets;
 extern const char *__doc_igl_n_polyvector;
 extern const char *__doc_igl_harmonic;
 extern const char *__doc_igl_boundary_loop;
+extern const char *__doc_igl_polar_svd;
 extern const char *__doc_igl_comb_cross_field;
 extern const char *__doc_igl_invert_diag;
+extern const char *__doc_igl_readMESH;
 extern const char *__doc_igl_copyleft_comiso_miq;
 extern const char *__doc_igl_copyleft_comiso_nrosy;

+ 28 - 0
python/py_igl.cpp

@@ -49,6 +49,20 @@
 #include <igl/comb_frame_field.h>
 #include <igl/n_polyvector.h>
 
+#include <igl/point_mesh_squared_distance.h>
+#include <igl/AABB.h>
+#include <igl/readMESH.h>
+#include <igl/writeMESH.h>
+#include <igl/slice_tets.h>
+#include <igl/edge_lengths.h>
+#include <igl/upsample.h>
+#include <igl/cat.h>
+#include <igl/per_edge_normals.h>
+#include <igl/barycentric_coordinates.h>
+#include <igl/fit_rotations.h>
+#include <igl/polar_svd.h>
+#include <igl/covariance_scatter_matrix.h>
+
 
 void python_export_igl(py::module &m)
 {
@@ -99,4 +113,18 @@ void python_export_igl(py::module &m)
 #include "py_igl/py_comb_frame_field.cpp"
 #include "py_igl/py_n_polyvector.cpp"
 
+#include "py_igl/py_point_mesh_squared_distance.cpp"
+#include "py_igl/py_AABB.cpp"
+#include "py_igl/py_readMESH.cpp"
+#include "py_igl/py_writeMESH.cpp"
+#include "py_igl/py_slice_tets.cpp"
+#include "py_igl/py_edge_lengths.cpp"
+#include "py_igl/py_upsample.cpp"
+#include "py_igl/py_cat.cpp"
+#include "py_igl/py_per_edge_normals.cpp"
+#include "py_igl/py_barycentric_coordinates.cpp"
+#include "py_igl/py_fit_rotations.cpp"
+#include "py_igl/py_polar_svd.cpp"
+#include "py_igl/py_covariance_scatter_matrix.cpp"
+
 }

+ 14 - 0
python/py_igl/py_AABB.cpp

@@ -0,0 +1,14 @@
+py::class_<igl::AABB<Eigen::MatrixXd,3> > AABB(m, "AABB");
+
+AABB
+.def(py::init<>())
+.def(py::init<const igl::AABB<Eigen::MatrixXd,3>& >())
+.def("init",[](igl::AABB<Eigen::MatrixXd,3>& tree, const Eigen::MatrixXd& V, const Eigen::MatrixXi& Ele)
+{
+    return tree.init(V, Ele, Eigen::Matrix<double, Eigen::Dynamic, 3>(), Eigen::Matrix<double, Eigen::Dynamic, 3>(), Eigen::MatrixXi(), 0); 
+})
+.def("squared_distance", [](const igl::AABB<Eigen::MatrixXd,3>& tree, const Eigen::MatrixXd& V, const Eigen::MatrixXi& Ele, const Eigen::MatrixXd& P, Eigen::MatrixXd& sqrD, Eigen::MatrixXi& I, Eigen::MatrixXd& C)
+{
+    return tree.squared_distance(V, Ele, P, sqrD, I, C);
+})
+;

+ 29 - 0
python/py_igl/py_barycentric_coordinates.cpp

@@ -0,0 +1,29 @@
+
+
+m.def("barycentric_coordinates", []
+(
+  const Eigen::MatrixXd& P,
+  const Eigen::MatrixXd& A,
+  const Eigen::MatrixXd& B,
+  const Eigen::MatrixXd& C,
+  const Eigen::MatrixXd& D,
+  Eigen::MatrixXd& L
+)
+{
+  return igl::barycentric_coordinates(P, A, B, C, D, L);
+}, __doc_igl_barycentric_coordinates,
+py::arg("P"), py::arg("A"), py::arg("B"), py::arg("C"), py::arg("D"), py::arg("L"));
+
+m.def("barycentric_coordinates", []
+(
+  const Eigen::MatrixXd& P,
+  const Eigen::MatrixXd& A,
+  const Eigen::MatrixXd& B,
+  const Eigen::MatrixXd& C,
+  Eigen::MatrixXd& L
+)
+{
+  return igl::barycentric_coordinates(P, A, B, C, L);
+}, __doc_igl_barycentric_coordinates,
+py::arg("P"), py::arg("A"), py::arg("B"), py::arg("C"), py::arg("L"));
+

+ 56 - 0
python/py_igl/py_cat.cpp

@@ -0,0 +1,56 @@
+m.def("cat", []
+(
+  const int dim,
+  const Eigen::MatrixXd& A,
+  const Eigen::MatrixXd& B,
+  Eigen::MatrixXd& C
+)
+{
+  return igl::cat(dim, A, B, C);
+}, __doc_igl_cat,
+py::arg("dim"), py::arg("A"), py::arg("B"), py::arg("C"));
+
+m.def("cat", []
+(
+  const int dim,
+  Eigen::MatrixXd& A,
+  Eigen::MatrixXd& B
+)
+{
+  return igl::cat(dim, A, B);
+}, __doc_igl_cat,
+py::arg("dim"), py::arg("A"), py::arg("B"));
+
+m.def("cat", []
+(
+  const int dim,
+  Eigen::MatrixXi& A,
+  Eigen::MatrixXi& B
+)
+{
+  return igl::cat(dim, A, B);
+}, __doc_igl_cat,
+py::arg("dim"), py::arg("A"), py::arg("B"));
+
+//m.def("cat", []
+//(
+//  const std::vector<std::vector<Eigen::MatrixXd > > & A, 
+//  Eigen::MatrixXd & C
+//)
+//{
+//  return igl::cat(A, C);
+//}, __doc_igl_cat,
+//py::arg("A"), py::arg("C"));
+
+m.def("cat", []
+(
+  const int dim,
+  const Eigen::SparseMatrix<double>& A,
+  const Eigen::SparseMatrix<double>& B,
+  Eigen::SparseMatrix<double>& C
+)
+{
+  return igl::cat(dim, A, B, C);
+}, __doc_igl_cat,
+py::arg("dim"), py::arg("A"), py::arg("B"), py::arg("C"));
+

+ 11 - 0
python/py_igl/py_covariance_scatter_matrix.cpp

@@ -0,0 +1,11 @@
+m.def("covariance_scatter_matrix", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  const igl::ARAPEnergyType energy,
+  Eigen::SparseMatrix<double>& CSM
+)
+{
+  return igl::covariance_scatter_matrix(V,F,energy,CSM);
+}, __doc_igl_covariance_scatter_matrix,
+py::arg("V"), py::arg("F"), py::arg("energy"), py::arg("CSM"));

+ 11 - 0
python/py_igl/py_edge_lengths.cpp

@@ -0,0 +1,11 @@
+m.def("edge_lengths", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  Eigen::MatrixXd& L
+)
+{
+  return igl::edge_lengths(V, F, L);
+}, __doc_igl_edge_lengths,
+py::arg("V"), py::arg("F"), py::arg("L"));
+

+ 22 - 0
python/py_igl/py_fit_rotations.cpp

@@ -0,0 +1,22 @@
+m.def("fit_rotations", []
+(
+  const Eigen::MatrixXd& S,
+  const bool single_precision,
+  Eigen::MatrixXd& R
+)
+{
+  return igl::fit_rotations(S, single_precision, R);
+}, __doc_igl_fit_rotations,
+py::arg("S"), py::arg("single_precision"), py::arg("R"));
+
+
+m.def("fit_rotations_planar", []
+(
+  const Eigen::MatrixXd& S,
+  Eigen::MatrixXd& R
+)
+{
+  return igl::fit_rotations_planar(S, R);
+}, __doc_igl_fit_rotations_planar,
+py::arg("S"), py::arg("R"));
+

+ 25 - 2
python/py_igl/py_parula.cpp

@@ -1,3 +1,25 @@
+//m.def("parula", []
+//(
+//  const double f,
+//  T * rgb
+//)
+//{
+//  return igl::parula(f, rgb);
+//}, __doc_igl_parula,
+//py::arg("f"), py::arg("rgb"));
+
+m.def("parula", []
+(
+  const double f,
+  double & r,
+  double & g,
+  double & b
+)
+{
+  return igl::parula(f, r, g, b);
+}, __doc_igl_parula,
+py::arg("f"), py::arg("r"), py::arg("g"), py::arg("b"));
+
 m.def("parula", []
 (
   const Eigen::MatrixXd& Z,
@@ -6,7 +28,7 @@ m.def("parula", []
 )
 {
   assert_is_VectorX("Z",Z);
-  return igl::parula(Z,normalize,C);
+  return igl::parula(Z, normalize, C);
 }, __doc_igl_parula,
 py::arg("Z"), py::arg("normalize"), py::arg("C"));
 
@@ -19,6 +41,7 @@ m.def("parula", []
 )
 {
   assert_is_VectorX("Z",Z);
-  return igl::parula(Z,min_Z,max_Z,C);
+  return igl::parula(Z, min_Z, max_Z, C);
 }, __doc_igl_parula,
 py::arg("Z"), py::arg("min_Z"), py::arg("max_Z"), py::arg("C"));
+

+ 50 - 0
python/py_igl/py_per_edge_normals.cpp

@@ -0,0 +1,50 @@
+py::enum_<igl::PerEdgeNormalsWeightingType>(m, "PerEdgeNormalsWeightingType")
+    .value("PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM", igl::PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM)
+    .value("PER_EDGE_NORMALS_WEIGHTING_TYPE_AREA", igl::PER_EDGE_NORMALS_WEIGHTING_TYPE_AREA)
+    .value("PER_EDGE_NORMALS_WEIGHTING_TYPE_DEFAULT", igl::PER_EDGE_NORMALS_WEIGHTING_TYPE_DEFAULT)
+    .value("NUM_PER_EDGE_NORMALS_WEIGHTING_TYPE", igl::NUM_PER_EDGE_NORMALS_WEIGHTING_TYPE)
+    .export_values();
+
+
+m.def("per_edge_normals", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  const igl::PerEdgeNormalsWeightingType weight,
+  const Eigen::MatrixXd& FN,
+  Eigen::MatrixXd& N,
+  Eigen::MatrixXi& E,
+  Eigen::MatrixXi& EMAP
+)
+{
+  return igl::per_edge_normals(V, F, weight, FN, N, E, EMAP);
+}, __doc_igl_per_edge_normals,
+py::arg("V"), py::arg("F"), py::arg("weight"), py::arg("FN"), py::arg("N"), py::arg("E"), py::arg("EMAP"));
+
+m.def("per_edge_normals", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  const igl::PerEdgeNormalsWeightingType weight,
+  Eigen::MatrixXd& N,
+  Eigen::MatrixXi& E,
+  Eigen::MatrixXi& EMAP
+)
+{
+  return igl::per_edge_normals(V, F, weight, N, E, EMAP);
+}, __doc_igl_per_edge_normals,
+py::arg("V"), py::arg("F"), py::arg("weight"), py::arg("N"), py::arg("E"), py::arg("EMAP"));
+
+m.def("per_edge_normals", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  Eigen::MatrixXd& N,
+  Eigen::MatrixXi& E,
+  Eigen::MatrixXi& EMAP
+)
+{
+  return igl::per_edge_normals(V, F, N, E, EMAP);
+}, __doc_igl_per_edge_normals,
+py::arg("V"), py::arg("F"), py::arg("N"), py::arg("E"), py::arg("EMAP"));
+

+ 15 - 0
python/py_igl/py_point_mesh_squared_distance.cpp

@@ -0,0 +1,15 @@
+m.def("point_mesh_squared_distance", []
+(
+  const Eigen::MatrixXd& P,
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& Ele,
+  Eigen::MatrixXd& sqrD,
+  Eigen::MatrixXi& I,
+  Eigen::MatrixXd& C
+)
+{
+  assert_is_VectorX("I",I);
+  return igl::point_mesh_squared_distance(P, V, Ele, sqrD, I, C);
+}, __doc_igl_point_mesh_squared_distance,
+py::arg("P"), py::arg("V"), py::arg("Ele"), py::arg("sqrD"), py::arg("I"), py::arg("C"));
+

+ 26 - 0
python/py_igl/py_polar_svd.cpp

@@ -0,0 +1,26 @@
+m.def("polar_svd", []
+(
+  const Eigen::MatrixXd& A,
+  Eigen::MatrixXd& R,
+  Eigen::MatrixXd& T,
+  Eigen::MatrixXd& U,
+  Eigen::MatrixXd& S,
+  Eigen::MatrixXd& V
+)
+{
+  return igl::polar_svd(A, R, T, U, S, V);
+}, __doc_igl_polar_svd,
+py::arg("A"), py::arg("R"), py::arg("T"), py::arg("U"), py::arg("S"), py::arg("V"));
+
+
+m.def("polar_svd", []
+(
+  const Eigen::MatrixXd& A,
+  Eigen::MatrixXd& R,
+  Eigen::MatrixXd& T
+)
+{
+  return igl::polar_svd(A, R, T);
+}, __doc_igl_polar_svd,
+py::arg("A"), py::arg("R"), py::arg("T"));
+

+ 24 - 0
python/py_igl/py_readMESH.cpp

@@ -0,0 +1,24 @@
+m.def("readMESH", []
+(
+  const std::string mesh_file_name,
+  std::vector<std::vector<double> > & V,
+  std::vector<std::vector<int> > & T,
+  std::vector<std::vector<int> > & F
+)
+{
+  return igl::readMESH(mesh_file_name, V, T, F);
+}, __doc_igl_readMESH,
+py::arg("mesh_file_name"), py::arg("V"), py::arg("T"), py::arg("F"));
+
+m.def("readMESH", []
+(
+  const std::string mesh_file_name,
+  Eigen::MatrixXd& V,
+  Eigen::MatrixXi& T,
+  Eigen::MatrixXi& F
+)
+{
+  return igl::readMESH(mesh_file_name, V, T, F);
+}, __doc_igl_readMESH,
+py::arg("mesh_file_name"), py::arg("V"), py::arg("T"), py::arg("F"));
+

+ 23 - 0
python/py_igl/py_slice_tets.cpp

@@ -0,0 +1,23 @@
+m.def("slice_tets", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& T,
+  const Eigen::MatrixXd& plane,
+  Eigen::MatrixXd& U,
+  Eigen::MatrixXi& G,
+  Eigen::MatrixXi& J,
+  Eigen::SparseMatrix<double> & BC
+)
+{
+  assert_is_VectorX("plane", plane);
+  Eigen::VectorXd pl;
+  if (plane.size() != 0)
+    pl = plane;
+  assert_is_VectorX("J", J);
+  Eigen::VectorXi Jv;
+  if (J.size() != 0)
+    Jv = J;
+  return igl::slice_tets(V, T, pl, U, G, Jv, BC);
+}, __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"));
+

+ 22 - 0
python/py_igl/py_upsample.cpp

@@ -0,0 +1,22 @@
+m.def("upsample", []
+(
+  Eigen::MatrixXd& V,
+  Eigen::MatrixXi& F
+)
+{
+  return igl::upsample(V, F);
+}, __doc_igl_upsample,
+py::arg("V"), py::arg("F"));
+
+m.def("upsample", []
+(
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXi& F,
+  Eigen::MatrixXd& NV,
+  Eigen::MatrixXi& NF
+)
+{
+  return igl::upsample(V, F, NV, NF);
+}, __doc_igl_upsample,
+py::arg("V"), py::arg("F"), py::arg("NV"), py::arg("NF"));
+

+ 24 - 0
python/py_igl/py_writeMESH.cpp

@@ -0,0 +1,24 @@
+m.def("writeMESH", []
+(
+  const std::string mesh_file_name,
+  const std::vector<std::vector<double> > & V,
+  const std::vector<std::vector<int> > & T,
+  const std::vector<std::vector<int> > & F
+)
+{
+  return igl::writeMESH(mesh_file_name, V, T, F);
+}, __doc_igl_writeMESH,
+py::arg("mesh_file_name"), py::arg("V"), py::arg("T"), py::arg("F"));
+
+m.def("writeMESH", []
+(
+  const std::string str,
+  const Eigen::MatrixXd& V,
+  const Eigen::MatrixXd& T,
+  const Eigen::MatrixXi& F
+)
+{
+  return igl::writeMESH(str, V, T, F);
+}, __doc_igl_writeMESH,
+py::arg("str"), py::arg("V"), py::arg("T"), py::arg("F"));
+

+ 6 - 0
python/py_vector.cpp

@@ -91,6 +91,7 @@ py::class_<Type> bind_eigen_2(py::module &m, const char *name,
         .def("size", [](const Type &m) { return m.size(); })
         .def("cols", [](const Type &m) { return m.cols(); })
         .def("rows", [](const Type &m) { return m.rows(); })
+        .def("shape", [](const Type &m) { return std::tuple<int,int>(m.rows(), m.cols()); })
 
         /* Extract rows and colums */
         .def("col", [](const Type &m, int i) {
@@ -356,6 +357,8 @@ py::class_<Type> bind_eigen_sparse_2(py::module &m, const char *name,
         .def("size", [](const Type &m) { return m.size(); })
         .def("cols", [](const Type &m) { return m.cols(); })
         .def("rows", [](const Type &m) { return m.rows(); })
+        .def("shape", [](const Type &m) { return std::tuple<int,int>(m.rows(), m.cols()); })
+
 
         /* Initialization */
         .def("setZero", [](Type &m) { m.setZero(); })
@@ -515,6 +518,7 @@ py::class_<Type> bind_eigen_diagonal_2(py::module &m, const char *name,
         .def("size", [](const Type &m) { return m.size(); })
         .def("cols", [](const Type &m) { return m.cols(); })
         .def("rows", [](const Type &m) { return m.rows(); })
+        .def("shape", [](const Type &m) { return std::tuple<int,int>(m.rows(), m.cols()); })
 
         /* Initialization */
         .def("setZero", [](Type &m) { m.setZero(); })
@@ -648,6 +652,8 @@ void python_export_vector(py::module &m) {
        else
           return "Numerical Issue";
     })
+    .def("analyzePattern",[](Eigen::SimplicialLLT<Eigen::SparseMatrix<double > >& s, const Eigen::SparseMatrix<double>& a) { return s.analyzePattern(a); })
+    .def("factorize",[](Eigen::SimplicialLLT<Eigen::SparseMatrix<double > >& s, const Eigen::SparseMatrix<double>& a) { return s.factorize(a); })
     .def("solve",[](const Eigen::SimplicialLLT<Eigen::SparseMatrix<double > >& s, const Eigen::MatrixXd& rhs) { return Eigen::MatrixXd(s.solve(rhs)); })
     ;
 

+ 140 - 0
python/tutorial/704_SignedDistance.py

@@ -0,0 +1,140 @@
+from __future__ import print_function
+
+# Add the igl library to the modules search path
+import sys, os
+sys.path.insert(0, os.getcwd() + "/../")
+
+import pyigl as igl
+from iglhelpers import e2p
+import math
+TUTORIAL_SHARED_PATH = "../../tutorial/shared/"
+
+global V, F, T, tree, FN, VN, EN, E, EMAP, max_distance, slice_z, overlay
+
+V = igl.eigen.MatrixXd()
+F = igl.eigen.MatrixXi()
+T = igl.eigen.MatrixXi()
+tree = igl.AABB()
+FN = igl.eigen.MatrixXd()
+VN = igl.eigen.MatrixXd()
+EN = igl.eigen.MatrixXd()
+E = igl.eigen.MatrixXi()
+EMAP = igl.eigen.MatrixXi()
+
+max_distance = 1
+slice_z = 0.5
+overlay = False
+
+viewer = igl.viewer.Viewer()
+
+def update_visualization(viewer):
+    global V, F, T, tree, FN, VN, EN, E, EMAP, max_distance, slice_z, overlay
+    plane = igl.eigen.MatrixXd([0.0, 0.0, 1.0, -((1-slice_z) * V.col(2).minCoeff() + slice_z * V.col(2).maxCoeff())])
+    V_vis = igl.eigen.MatrixXd()
+    F_vis = igl.eigen.MatrixXi()
+
+    # Extract triangle mesh slice through volume mesh and subdivide nasty triangles
+    J = igl.eigen.MatrixXi()
+    bary = igl.eigen.SparseMatrixd()
+    igl.slice_tets(V, T, plane, V_vis, F_vis, J, bary)
+    max_l = 0.03
+#    while True:
+#        l = igl.eigen.MatrixXd()
+#        igl.edge_lengths(V_vis, F_vis, l)
+#        l /= (V_vis.colwise().maxCoeff() - V_vis.colwise().minCoeff()).norm()
+#        
+#        if l.maxCoeff() < max_l:
+#            break
+#        
+#        bad = e2p(l.rowwiseMaxCoeff())
+#        bad = bad > max_l
+#        F_vis_bad = igl.eigen.MatrixXi()
+#        F_vis_good = igl.eigen.MatrixXi()
+#        igl::slice_mask(F_vis, bad, 1, F_vis_bad);
+#        igl::slice_mask(F_vis, (bad!=true).eval(), 1, F_vis_good);
+#        igl.upsample(V_vis, F_vis_bad)
+#        F_vis = igl.cat(1, F_vis_bad, F_vis_good)
+
+
+#    #Compute signed distance
+#    S_vis = igl.eigen.MatrixXd()
+#    I = igl.eigen.MatrixXi()
+#    N = igl.eigen.MatrixXd()
+#    C = igl.eigen.MatrixXd()
+
+#    # Bunny is a watertight mesh so use pseudonormal for signing
+#    igl.signed_distance_pseudonormal(V_vis, V, F, tree, FN, VN, EN, EMAP, S_vis, I, C, N)
+
+#    # push to [0,1] range
+#    S_vis.array() = 0.5*(S_vis.array()/max_distance)+0.5;
+#    C_vis = igl.eigen.MatrixXi()
+#    # color without normalizing
+#    igl.parula(S_vis, False, C_vis)
+
+
+#    const auto & append_mesh = [&C_vis,&F_vis,&V_vis](const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, const RowVector3d & color)
+
+#    F_vis.conservativeResize(F_vis.rows() + F.rows(), 3)
+#    F_vis.bottomRows(F.rows()) = F.array() + V_vis.rows()
+#    V_vis.conservativeResize(V_vis.rows() + V.rows(), 3)
+#    V_vis.bottomRows(V.rows()) = V
+#    C_vis.conservativeResize(C_vis.rows() + V.rows(), 3)
+#    C_vis.bottomRows(V.rows()).rowwise() = color
+
+#    if overlay:
+#        append_mesh(V, F, RowVector3d(0.8,0.8,0.8))
+
+    viewer.data.clear()
+    viewer.data.set_mesh(V_vis, F_vis)
+#    viewer.data.set_colors(C_vis)
+    viewer.core.lighting_factor = overlay
+
+
+
+
+def key_down(viewer, key, modifier):
+    global slice_z, overlay
+
+    if key == ord(' '):
+        overlay = not overlay
+    elif key == ord('.'):
+        slice_z = min(slice_z + 0.01, 0.99)
+    elif key == ord(','):
+        slice_z = max(slice_z - 0.01, 0.01)
+    else:
+        return False
+
+    update_visualization(viewer)
+    return True
+
+
+print("Press [space] to toggle showing surface.")
+print("Press '.'/',' to push back/pull forward slicing plane.")
+
+#Load mesh: (V,T) tet-mesh of convex hull, F contains original surface triangles
+igl.readMESH(TUTORIAL_SHARED_PATH + "bunny.mesh", V, T, F);
+
+#Call to point_mesh_squared_distance to determine bounds
+sqrD = igl.eigen.MatrixXd()
+I = igl.eigen.MatrixXi()
+C = igl.eigen.MatrixXd()
+igl.point_mesh_squared_distance(V, V, F, sqrD, I, C)
+max_distance = math.sqrt(sqrD.maxCoeff())
+
+#Precompute signed distance AABB tree
+tree.init(V, F)
+
+#Precompute vertex, edge and face normals
+igl.per_face_normals(V, F, FN)
+igl.per_vertex_normals(V, F, igl.PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE, FN, VN)
+igl.per_edge_normals(V, F, igl.PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM, FN, EN, E, EMAP)
+
+#Plot the generated mesh
+update_visualization(viewer);
+viewer.callback_key_down = key_down
+viewer.core.show_lines = False
+viewer.launch()
+
+
+
+