Browse Source

Added tutorial 702

Former-commit-id: 64289b00505a66bd268a4036ef92cbbf7a370671
Sebastian Koch 9 years ago
parent
commit
5416e09508

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

+ 35 - 0
python/py_doc.cpp

@@ -960,6 +960,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:

+ 3 - 0
python/py_doc.h

@@ -78,5 +78,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;

+ 2 - 0
python/py_igl.cpp

@@ -67,6 +67,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>
 
@@ -138,6 +139,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"
 

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

+ 1 - 0
python/python_shared.cpp

@@ -117,6 +117,7 @@ PYBIND11_PLUGIN(pyigl) {
            unique
            unproject_onto_mesh
            upsample
+           winding_number
            writeMESH
            writeOBJ
 

+ 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 = []
+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()

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