瀏覽代碼

Merge pull request #543 from fwilliams/master

Add python bindings for igl::adjacency_list

Former-commit-id: 4db78f48f1c35d897c457ffb1b8ba6fbcf84c779
Daniele Panozzo 8 年之前
父節點
當前提交
07d84bf47b

+ 6 - 0
python/modules/py_typedefs.cpp

@@ -11,3 +11,9 @@ py::class_<RotationList>(m, "RotationList")
     .def("__iter__", [](RotationList &v) {
        return py::make_iterator(v.begin(), v.end());
 }, py::keep_alive<0, 1>());
+
+
+py::bind_vector<std::vector<int>>(m, "VectorInt");
+py::bind_vector<std::vector<std::vector<int>>>(m, "VectorVectorInt");
+
+

+ 8 - 1
python/modules/py_typedefs.h

@@ -1,5 +1,12 @@
+#include <pybind11/pybind11.h>
+#include <pybind11/stl_bind.h>
+
 typedef std::vector<Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > RotationList;
-PYBIND11_MAKE_OPAQUE(RotationList);
+PYBIND11_MAKE_OPAQUE(RotationList)
 
 //typedef std::vector<Eigen::Vector3d> TranslationList;
 //PYBIND11_MAKE_OPAQUE(TranslationList);
+
+PYBIND11_MAKE_OPAQUE(std::vector<int>)
+PYBIND11_MAKE_OPAQUE(std::vector<std::vector<int>>)
+

+ 35 - 17
python/py_doc.cpp

@@ -31,6 +31,21 @@ 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_adjacency_list = R"igl_Qu8mg5v7(// Constructs the graph adjacency list of a given mesh (V,F)
+  // Templates:
+  //   T  should be a eigen sparse matrix primitive type like int or double
+  // Inputs:
+  //   F       #F by dim list of mesh faces (must be triangles)
+  //   sorted  flag that indicates if the list should be sorted counter-clockwise
+  // Outputs: 
+  //   A  vector<vector<T> > containing at row i the adjacent vertices of vertex i
+  //
+  // Example:
+  //   // Mesh in (V,F)
+  //   vector<vector<double> > A;
+  //   adjacency_list(F,A);
+  //
+  // See also: edges, cotmatrix, diag)igl_Qu8mg5v7";
 const char *__doc_igl_arap_precomputation = R"igl_Qu8mg5v7(// Compute necessary information to start using an ARAP deformation
   //
   // Inputs:
@@ -78,10 +93,10 @@ const char *__doc_igl_barycentric_coordinates = R"igl_Qu8mg5v7(// Compute baryce
   //   )igl_Qu8mg5v7";
 const char *__doc_igl_barycentric_to_global = R"igl_Qu8mg5v7(// Converts barycentric coordinates in the embree form to 3D coordinates
   // Embree stores barycentric coordinates as triples: fid, bc1, bc2
-  // fid is the id of a face, bc1 is the displacement of the point wrt the 
+  // fid is the id of a face, bc1 is the displacement of the point wrt the
   // first vertex v0 and the edge v1-v0. Similarly, bc2 is the displacement
   // wrt v2-v0.
-  // 
+  //
   // Input:
   // V:  #Vx3 Vertices of the mesh
   // F:  #Fxe Faces of the mesh
@@ -89,6 +104,7 @@ const char *__doc_igl_barycentric_to_global = R"igl_Qu8mg5v7(// Converts barycen
   //
   // Output:
   // #X: #Xx3 3D coordinates of all points in bc)igl_Qu8mg5v7";
+
 const char *__doc_igl_bbw = R"igl_Qu8mg5v7(// Compute Bounded Biharmonic Weights on a given domain (V,Ele) with a given
   // set of boundary conditions
   //
@@ -650,12 +666,12 @@ const char *__doc_igl_get_seconds = R"igl_Qu8mg5v7(// Return the current time in
   //    ... // 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 [tetrahedron] i,j,k:
-  // grad(Xijk) = (Xj-Xi) * (Vi - Vk)^R90 / 2A + (Xk-Xi) * (Vj - Vi)^R90 / 2A
-  // where Xi is the scalar value at vertex i, Vi is the 3D position of vertex
-  // i, and A is the area of triangle (i,j,k). ^R90 represent a rotation of
-  // 90 degrees
+const char *__doc_igl_grad = R"igl_Qu8mg5v7(// Gradient of a scalar function defined on piecewise linear elements (mesh)
+  // is constant on each triangle [tetrahedron] i,j,k:
+  // grad(Xijk) = (Xj-Xi) * (Vi - Vk)^R90 / 2A + (Xk-Xi) * (Vj - Vi)^R90 / 2A
+  // where Xi is the scalar value at vertex i, Vi is the 3D position of vertex
+  // i, and A is the area of triangle (i,j,k). ^R90 represent a rotation of
+  // 90 degrees
   //)igl_Qu8mg5v7";
 const char *__doc_igl_harmonic = R"igl_Qu8mg5v7(// Compute k-harmonic weight functions "coordinates".
   //
@@ -839,12 +855,14 @@ const char *__doc_igl_min_quad_with_fixed_precompute = R"igl_Qu8mg5v7(// Known B
   // they're not then resulting probably will no longer be sparse: it will be
   // slow.
   //
-  // MIN_QUAD_WITH_FIXED Minimize quadratic energy 
+  // MIN_QUAD_WITH_FIXED Minimize a quadratic energy of the form
   //
-  // 0.5*Z'*A*Z + Z'*B + C with
+  // trace( 0.5*Z'*A*Z + Z'*B + constant )
   //
-  // constraints that Z(known) = Y, optionally also subject to the constraints
-  // Aeq*Z = Beq
+  // subject to
+  //
+  //   Z(known,:) = Y, and
+  //   Aeq*Z = Beq
   //
   // Templates:
   //   T  should be a eigen matrix primitive type like int or double
@@ -870,12 +888,12 @@ const char *__doc_igl_min_quad_with_fixed_solve = R"igl_Qu8mg5v7(// Solves a sys
   //   DerivedZ  type of Z (e.g. derived from VectorXd or MatrixXd)
   // Inputs:
   //   data  factorization struct with all necessary precomputation to solve
-  //   B  n by 1 column of linear coefficients
-  //   Y  b by 1 list of constant fixed values
-  //   Beq  m by 1 list of linear equality constraint constant values
+  //   B  n by k column of linear coefficients
+  //   Y  b by k list of constant fixed values
+  //   Beq  m by k list of linear equality constraint constant values
   // Outputs:
-  //   Z  n by cols solution
-  //   sol  #unknowns+#lagrange by cols solution to linear system
+  //   Z  n by k solution
+  //   sol  #unknowns+#lagrange by k 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_n_polyvector = R"igl_Qu8mg5v7(// Inputs:

+ 1 - 0
python/py_doc.h

@@ -1,4 +1,5 @@
 extern const char *__doc_igl_active_set;
+extern const char *__doc_igl_adjacency_list;
 extern const char *__doc_igl_arap_precomputation;
 extern const char *__doc_igl_arap_solve;
 extern const char *__doc_igl_avg_edge_length;

+ 2 - 0
python/py_igl.cpp

@@ -8,6 +8,7 @@
 #include <igl/MeshBooleanType.h>
 #include <igl/SolverStatus.h>
 #include <igl/active_set.h>
+#include <igl/adjacency_list.h>
 #include <igl/arap.h>
 #include <igl/avg_edge_length.h>
 #include <igl/barycenter.h>
@@ -104,6 +105,7 @@ void python_export_igl(py::module &m)
 #include "py_igl/py_MeshBooleanType.cpp"
 #include "py_igl/py_SolverStatus.cpp"
 #include "py_igl/py_active_set.cpp"
+#include "py_igl/py_adjacency_list.cpp"
 #include "py_igl/py_arap.cpp"
 #include "py_igl/py_avg_edge_length.cpp"
 #include "py_igl/py_barycenter.cpp"

+ 3 - 0
python/py_igl/py_adjacency_list.cpp

@@ -0,0 +1,3 @@
+m.def("adjacency_list", [](const Eigen::MatrixXi& F, std::vector<std::vector<int>>& A, bool sorted) {
+    igl::adjacency_list(F, A, sorted);
+}, py::arg("F"), py::arg("A"), py::arg("sorted")=false);

+ 1 - 0
python/python_shared.cpp

@@ -53,6 +53,7 @@ PYBIND11_PLUGIN(pyigl) {
            MeshBooleanType
            SolverStatus
            active_set
+           adjacency_list
            arap
            avg_edge_length
            barycenter

+ 5 - 6
python/scripts/generate_docstrings.py

@@ -1,6 +1,6 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
 #
-#  Syntax: generate_docstrings.py <path_to_c++_header_files> <path_to_python_files>
+#  Syntax: generate_docstrings.py <path to libigl C++ header_files> <path to python binding C++ files>
 #
 #  Extract documentation from C++ header files to use it in libiglPython bindings
 #
@@ -37,8 +37,7 @@ def get_filepaths(directory):
 
 
 def get_name_from_path(path, basepath, prefix, postfix):
-    f_clean = path[len(basepath):]
-    f_clean = f_clean.replace(basepath, "")
+    f_clean = os.path.relpath(path, basepath)
     f_clean = f_clean.replace(postfix, "")
     f_clean = f_clean.replace(prefix, "")
     f_clean = f_clean.replace("/", "_")
@@ -51,7 +50,7 @@ def get_name_from_path(path, basepath, prefix, postfix):
 if __name__ == '__main__':
 
     if len(sys.argv) != 3:
-        print('Syntax: %s <path_to_c++_header_files> <path_to_python_files>' % sys.argv[0])
+        print('Syntax: %s generate_docstrings.py <path to libigl C++ header_files> <path to python binding C++ files>' % sys.argv[0])
         exit(-1)
 
     # List all files in the given folder and subfolders
@@ -109,7 +108,7 @@ if __name__ == '__main__':
             for f in d["functions"]:
                 h_string = "extern const char *__doc_" + namespaces + "_" + f.name + ";\n"
                 docu_string = "See " + f.name + " for the documentation."
-                if f.documentation != "":
+                if f.documentation:
                     docu_string = f.documentation
                 cpp_string = "const char *__doc_" + namespaces + "_" + f.name + " = R\"igl_Qu8mg5v7(" + docu_string + ")igl_Qu8mg5v7\";\n"
 

+ 1 - 1
python/scripts/parser.py

@@ -118,7 +118,7 @@ def parse(path):
     # Clang can't parse files with missing definitions, add static library definition or not?
     args = ['-x', 'c++', '-std=c++11', '-fparse-all-comments', '-DIGL_STATIC_LIBRARY']
     args.append('-I/usr/include/eigen3/') # TODO Properly add all needed includes
-    syspath = ccsyspath.system_include_paths('clang++-3.7') # Add the system libraries
+    syspath = ccsyspath.system_include_paths('clang++') # Add the system libraries
     incargs = [(b'-I' + inc).decode("utf-8") for inc in syspath]
     args.extend(incargs)