Parcourir la source

Cleaned up python tutorials and added dependency checks to all tutorials

Former-commit-id: 246017f041cbbfee434879047dc41a0c7139fa53
Sebastian Koch il y a 9 ans
Parent
commit
594aad7067

+ 2 - 9
python/tutorial/001_BasicTypes.py

@@ -4,7 +4,7 @@ from iglhelpers import *
 
 # Create a numpy dense array
 # 2 types are supported by the wrappers: float64 and int64
-dense_matrix = np.array( [ (1,2,3), (4,5,6) , (7,8,9) ], dtype='float64')
+dense_matrix = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype='float64')
 
 # libigl wrappers uses Eigen as a matrix type, you can easily convert between numpy and Eigen using
 # the helper function p2e. This operation duplicates the data.
@@ -18,7 +18,7 @@ dense_matrix_eigen_2 = dense_matrix_eigen * dense_matrix_eigen
 print("Eigen Matrix: \n", dense_matrix_eigen_2, "\n", sep='')
 
 # and access single elements
-print("Eigen Matrix(0,0): ", dense_matrix_eigen_2[0,0], "\n")
+print("Eigen Matrix(0,0): ", dense_matrix_eigen_2[0, 0], "\n")
 
 # To convert it back to a numpy array, use the helper function e2p
 dense_matrix_2 = e2p(dense_matrix_eigen_2)
@@ -39,10 +39,3 @@ print("Sparse matrix Eigen: ", sparse_matrix_eigen, sep='')
 # And converted back with e2p
 sparse_matrix_2 = e2p(sparse_matrix_eigen)
 print("Sparse matrix Numpy: ", sparse_matrix_2.todense(), sep='')
-
-
-
-
-
-
-

+ 3 - 2
python/tutorial/101_FileIO.py

@@ -1,15 +1,16 @@
-from __future__ import print_function
 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
+
 
 # Load a mesh in OFF format
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
-igl.readOFF("../../tutorial/shared/cube.off", V, F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "cube.off", V, F)
 
 # Print the vertices and faces matrices
 print("Vertices: \n", V, sep='')

+ 1 - 0
python/tutorial/102_DrawMesh.py

@@ -9,6 +9,7 @@ from shared import TUTORIAL_SHARED_PATH, check_dependencies
 dependencies = ["viewer"]
 check_dependencies(dependencies)
 
+
 # Load a mesh in OFF format
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()

+ 10 - 9
python/tutorial/102_DrawMesh_TCP.py

@@ -1,11 +1,15 @@
-## This is a test application for the TCPViewer
-
-# Add the igl library to the modules search path
 import sys, os
+import time
+# Add the igl library to the modules search path
 sys.path.insert(0, os.getcwd() + "/../")
+import pyigl as igl
 
-import os
-import time
+import tcpviewer
+
+from shared import TUTORIAL_SHARED_PATH
+
+
+## This is a test application for the TCPViewer
 
 # Launch the tcp viewer
 os.system("python ../tcpviewer.py&")
@@ -13,13 +17,10 @@ os.system("python ../tcpviewer.py&")
 # Wait for it to set up the socket
 time.sleep(1)
 
-import pyigl as igl
-import tcpviewer
-
 # Read a mesh
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
-igl.readOFF('../../tutorial/shared/beetle.off', V, F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "beetle.off", V, F)
 
 # Send it to the viewer
 viewer = tcpviewer.TCPViewer()

+ 16 - 10
python/tutorial/103_Events.py

@@ -1,9 +1,15 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V1 = igl.eigen.MatrixXd()
 F1 = igl.eigen.MatrixXi()
 
@@ -15,22 +21,22 @@ def key_pressed(viewer, key, modifier):
 
     if key == ord('1'):
         # # Clear should be called before drawing the mesh
-        viewer.data.clear();
+        viewer.data.clear()
         # # Draw_mesh creates or updates the vertices and faces of the displayed mesh.
         # # If a mesh is already displayed, draw_mesh returns an error if the given V and
         # # F have size different than the current ones
-        viewer.data.set_mesh(V1, F1);
-        viewer.core.align_camera_center(V1,F1);
+        viewer.data.set_mesh(V1, F1)
+        viewer.core.align_camera_center(V1,F1)
     elif key == ord('2'):
-        viewer.data.clear();
-        viewer.data.set_mesh(V2, F2);
-        viewer.core.align_camera_center(V2,F2);
+        viewer.data.clear()
+        viewer.data.set_mesh(V2, F2)
+        viewer.core.align_camera_center(V2,F2)
     return False
 
 
 #  Load two meshes
-igl.readOFF("../../tutorial/shared/bumpy.off", V1, F1);
-igl.readOFF("../../tutorial/shared/fertility.off", V2, F2);
+igl.readOFF(TUTORIAL_SHARED_PATH + "bumpy.off", V1, F1)
+igl.readOFF(TUTORIAL_SHARED_PATH + "fertility.off", V2, F2)
 
 print("1 Switch to bump mesh")
 print("2 Switch to fertility mesh")

+ 11 - 5
python/tutorial/104_Colors.py

@@ -1,25 +1,31 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 C = igl.eigen.MatrixXd()
 
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/screwdriver.off", V, F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "screwdriver.off", V, F)
 
 # Plot the mesh
 viewer = igl.viewer.Viewer()
 viewer.data.set_mesh(V, F)
 
 # Use the z coordinate as a scalar field over the surface
-Z = V.col(2);
+Z = V.col(2)
 
 # Compute per-vertex colors
-igl.jet(Z,True,C)
+igl.jet(Z, True, C)
 
 # Add per-vertex colors
 viewer.data.set_colors(C)

+ 42 - 37
python/tutorial/105_Overlays.py

@@ -1,49 +1,54 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/bunny.off", V, F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "bunny.off", V, F)
 
 # Find the bounding box
 m = V.colwiseMinCoeff()
 M = V.colwiseMaxCoeff()
 
-
 # Corners of the bounding box
 V_box = igl.eigen.MatrixXd(
-[
-[m[0,0], m[0,1], m[0,2]],
-[M[0,0], m[0,1], m[0,2]],
-[M[0,0], M[0,1], m[0,2]],
-[m[0,0], M[0,1], m[0,2]],
-[m[0,0], m[0,1], M[0,2]],
-[M[0,0], m[0,1], M[0,2]],
-[M[0,0], M[0,1], M[0,2]],
-[m[0,0], M[0,1], M[0,2]]
-]
+    [
+        [m[0, 0], m[0, 1], m[0, 2]],
+        [M[0, 0], m[0, 1], m[0, 2]],
+        [M[0, 0], M[0, 1], m[0, 2]],
+        [m[0, 0], M[0, 1], m[0, 2]],
+        [m[0, 0], m[0, 1], M[0, 2]],
+        [M[0, 0], m[0, 1], M[0, 2]],
+        [M[0, 0], M[0, 1], M[0, 2]],
+        [m[0, 0], M[0, 1], M[0, 2]]
+    ]
 )
 
 E_box = igl.eigen.MatrixXi(
-[
-[0, 1],
-[1, 2],
-[2, 3],
-[3, 0],
-[4, 5],
-[5, 6],
-[6, 7],
-[7, 4],
-[0, 4],
-[1, 5],
-[2, 6],
-[7 ,3]
-]
+    [
+        [0, 1],
+        [1, 2],
+        [2, 3],
+        [3, 0],
+        [4, 5],
+        [5, 6],
+        [6, 7],
+        [7, 4],
+        [0, 4],
+        [1, 5],
+        [2, 6],
+        [7, 3]
+    ]
 )
 
 # Plot the mesh
@@ -51,21 +56,21 @@ viewer = igl.viewer.Viewer()
 viewer.data.set_mesh(V, F)
 
 # Plot the corners of the bounding box as points
-viewer.data.add_points(V_box,igl.eigen.MatrixXd([[1,0,0]]))
+viewer.data.add_points(V_box, igl.eigen.MatrixXd([[1, 0, 0]]))
 
 # Plot the edges of the bounding box
-for i in range(0,E_box.rows()):
+for i in range(0, E_box.rows()):
     viewer.data.add_edges(
-        V_box.row(E_box[i,0]),
-        V_box.row(E_box[i,1]),
-        igl.eigen.MatrixXd([[1,0,0]]))
+        V_box.row(E_box[i, 0]),
+        V_box.row(E_box[i, 1]),
+        igl.eigen.MatrixXd([[1, 0, 0]]))
 
 # Plot labels with the coordinates of bounding box vertices
-l1 = 'x: ' + str(m[0,0]) + ' y: ' + str(m[0,1]) + ' z: ' + str(m[0,2])
-viewer.data.add_label(m.transpose(),l1)
+l1 = 'x: ' + str(m[0, 0]) + ' y: ' + str(m[0, 1]) + ' z: ' + str(m[0, 2])
+viewer.data.add_label(m.transpose(), l1)
 
-l2 = 'x: ' + str(M[0,0]) + ' y: ' + str(M[0,1]) + ' z: ' + str(M[0,2])
-viewer.data.add_label(M.transpose(),l2)
+l2 = 'x: ' + str(M[0, 0]) + ' y: ' + str(M[0, 1]) + ' z: ' + str(M[0, 2])
+viewer.data.add_label(M.transpose(), l2)
 
 # Launch the viewer
 viewer.launch()

+ 20 - 12
python/tutorial/201_Normals.py

@@ -1,9 +1,15 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 
@@ -11,33 +17,35 @@ N_vertices = igl.eigen.MatrixXd()
 N_faces = igl.eigen.MatrixXd()
 N_corners = igl.eigen.MatrixXd()
 
+
 # This function is called every time a keyboard button is pressed
 def key_pressed(viewer, key, modifier):
     if key == ord('1'):
-      viewer.data.set_normals(N_faces)
-      return True
+        viewer.data.set_normals(N_faces)
+        return True
     elif key == ord('2'):
-      viewer.data.set_normals(N_vertices)
-      return True
+        viewer.data.set_normals(N_vertices)
+        return True
     elif key == ord('3'):
-      viewer.data.set_normals(N_corners)
-      return True
+        viewer.data.set_normals(N_corners)
+        return True
     return False
 
+
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/fandisk.off", V, F);
+igl.readOFF(TUTORIAL_SHARED_PATH + "fandisk.off", V, F)
 
 # Compute per-face normals
 N_faces = igl.eigen.MatrixXd()
-igl.per_face_normals(V,F,N_faces)
+igl.per_face_normals(V, F, N_faces)
 
 # Compute per-vertex normals
 N_vertices = igl.eigen.MatrixXd()
-igl.per_vertex_normals(V,F,igl.PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA,N_vertices)
+igl.per_vertex_normals(V, F, igl.PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA, N_vertices)
 
 # Compute per-corner normals, |dihedral angle| > 20 degrees --> crease
 N_corners = igl.eigen.MatrixXd()
-igl.per_corner_normals(V,F,20,N_corners)
+igl.per_corner_normals(V, F, 20, N_corners)
 
 # Plot the mesh
 viewer = igl.viewer.Viewer()

+ 13 - 7
python/tutorial/202_GaussianCurvature.py

@@ -1,21 +1,27 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 # Load mesh
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
-igl.readOFF("../../tutorial/shared/bumpy.off",V,F);
+igl.readOFF(TUTORIAL_SHARED_PATH + "bumpy.off", V, F)
 
 # Compute Gaussian curvature
-K = igl.eigen.MatrixXd();
-igl.gaussian_curvature(V,F,K);
+K = igl.eigen.MatrixXd()
+igl.gaussian_curvature(V, F, K)
 
 # Compute pseudocolor
-C = igl.eigen.MatrixXd();
-igl.jet(K,True,C);
+C = igl.eigen.MatrixXd()
+igl.jet(K, True, C)
 
 # Plot the mesh with pseudocolors
 viewer = igl.viewer.Viewer()

+ 24 - 19
python/tutorial/203_CurvatureDirections.py

@@ -1,12 +1,18 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# Add the igl library to the modules search path
+sys.path.insert(0, os.getcwd() + "/../")
 import pyigl as igl
 
-V = igl.eigen.MatrixXd();
-F = igl.eigen.MatrixXi();
-igl.read_triangle_mesh("../../tutorial/shared/fertility.off", V, F);
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
+V = igl.eigen.MatrixXd()
+F = igl.eigen.MatrixXi()
+igl.read_triangle_mesh(TUTORIAL_SHARED_PATH + "fertility.off", V, F)
 
 # Alternative discrete mean curvature
 HN = igl.eigen.MatrixXd()
@@ -14,14 +20,13 @@ L = igl.eigen.SparseMatrixd()
 M = igl.eigen.SparseMatrixd()
 Minv = igl.eigen.SparseMatrixd()
 
+igl.cotmatrix(V, F, L)
+igl.massmatrix(V, F, igl.MASSMATRIX_TYPE_VORONOI, M)
 
-igl.cotmatrix(V,F,L)
-igl.massmatrix(V,F,igl.MASSMATRIX_TYPE_VORONOI,M)
-
-igl.invert_diag(M,Minv)
+igl.invert_diag(M, Minv)
 
 # Laplace-Beltrami of position
-HN = -Minv*(L*V)
+HN = -Minv * (L * V)
 
 # Extract magnitude as mean curvature
 H = HN.rowwiseNorm()
@@ -33,33 +38,33 @@ PD2 = igl.eigen.MatrixXd()
 PV1 = igl.eigen.MatrixXd()
 PV2 = igl.eigen.MatrixXd()
 
-igl.principal_curvature(V,F,PD1,PD2,PV1,PV2)
+igl.principal_curvature(V, F, PD1, PD2, PV1, PV2)
 
 # Mean curvature
-H = 0.5*(PV1+PV2)
+H = 0.5 * (PV1 + PV2)
 
 viewer = igl.viewer.Viewer()
 viewer.data.set_mesh(V, F)
 
 # Compute pseudocolor
 C = igl.eigen.MatrixXd()
-igl.parula(H,True,C)
+igl.parula(H, True, C)
 
 viewer.data.set_colors(C)
 
 # Average edge length for sizing
-avg = igl.avg_edge_length(V,F)
+avg = igl.avg_edge_length(V, F)
 
 # Draw a blue segment parallel to the minimal curvature direction
-red = igl.eigen.MatrixXd([[0.8,0.2,0.2]])
-blue = igl.eigen.MatrixXd([[0.2,0.2,0.8]])
+red = igl.eigen.MatrixXd([[0.8, 0.2, 0.2]])
+blue = igl.eigen.MatrixXd([[0.2, 0.2, 0.8]])
 
-viewer.data.add_edges(V + PD1*avg, V - PD1*avg, blue)
+viewer.data.add_edges(V + PD1 * avg, V - PD1 * avg, blue)
 
 # Draw a red segment parallel to the maximal curvature direction
-viewer.data.add_edges(V + PD2*avg, V - PD2*avg, red)
+viewer.data.add_edges(V + PD2 * avg, V - PD2 * avg, red)
 
 # Hide wireframe
 viewer.core.show_lines = False
 
-viewer.launch();
+viewer.launch()

+ 18 - 12
python/tutorial/204_Gradient.py

@@ -1,26 +1,32 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/cheburashka.off", V, F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "cheburashka.off", V, F)
 
 # Read scalar function values from a file, U: #V by 1
 U = igl.eigen.MatrixXd()
-igl.readDMAT("../../tutorial/shared/cheburashka-scalar.dmat",U)
+igl.readDMAT(TUTORIAL_SHARED_PATH + "cheburashka-scalar.dmat", U)
 U = U.col(0)
 
 # Compute gradient operator: #F*3 by #V
 G = igl.eigen.SparseMatrixd()
-igl.grad(V,F,G)
+igl.grad(V, F, G)
 
 # Compute gradient of U
-GU = (G*U).MapMatrix(F.rows(),3)
+GU = (G * U).MapMatrix(F.rows(), 3)
 
 # Compute gradient magnitude
 GU_mag = GU.rowwiseNorm()
@@ -31,22 +37,22 @@ viewer.data.set_mesh(V, F)
 # Compute pseudocolor for original function
 C = igl.eigen.MatrixXd()
 
-igl.jet(U,True,C)
+igl.jet(U, True, C)
 
 # Or for gradient magnitude
 # igl.jet(GU_mag,True,C)
 
-viewer.data.set_colors(C);
+viewer.data.set_colors(C)
 
 # Average edge length divided by average gradient (for scaling)
-max_size = igl.avg_edge_length(V,F) / GU_mag.mean()
+max_size = igl.avg_edge_length(V, F) / GU_mag.mean()
 
 # Draw a black segment in direction of gradient at face barycenters
 BC = igl.eigen.MatrixXd()
-igl.barycenter(V,F,BC)
+igl.barycenter(V, F, BC)
 
-black = igl.eigen.MatrixXd([[0.0,0.0,0.0]])
-viewer.data.add_edges(BC,BC+max_size*GU, black)
+black = igl.eigen.MatrixXd([[0.0, 0.0, 0.0]])
+viewer.data.add_edges(BC, BC + max_size * GU, black)
 
 # Hide wireframe
 viewer.core.show_lines = False

+ 32 - 32
python/tutorial/205_Laplacian.py

@@ -1,16 +1,15 @@
-from __future__ import print_function
+import sys, os
+import math
 
 # Add the igl library to the modules search path
-import sys, os
 sys.path.insert(0, os.getcwd() + "/../")
-
 import pyigl as igl
-import math
 
-global V
-global U
-global F
-global L
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
 
 V = igl.eigen.MatrixXd()
 U = igl.eigen.MatrixXd()
@@ -20,70 +19,70 @@ L = igl.eigen.SparseMatrixd()
 viewer = igl.viewer.Viewer()
 
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/cow.off", V, F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "cow.off", V, F)
 
 # Compute Laplace-Beltrami operator: #V by #V
-igl.cotmatrix(V,F,L)
+igl.cotmatrix(V, F, L)
 
 # Alternative construction of same Laplacian
 G = igl.eigen.SparseMatrixd()
 K = igl.eigen.SparseMatrixd()
 
 # Gradient/Divergence
-igl.grad(V,F,G);
+igl.grad(V, F, G)
 
 # Diagonal per-triangle "mass matrix"
 dblA = igl.eigen.MatrixXd()
-igl.doublearea(V,F,dblA)
+igl.doublearea(V, F, dblA)
 
 # Place areas along diagonal #dim times
 
-T = (dblA.replicate(3,1)*0.5).asDiagonal() * 1
+T = (dblA.replicate(3, 1) * 0.5).asDiagonal() * 1
 
 # Laplacian K built as discrete divergence of gradient or equivalently
 # discrete Dirichelet energy Hessian
 
 temp = -G.transpose()
 K = -G.transpose() * T * G
-print("|K-L|: ",(K-L).norm())
+print("|K-L|: ", (K - L).norm())
+
 
 def key_pressed(viewer, key, modifier):
-    global V
-    global U
-    global F
-    global L
+    global V, U, F, L
 
     if key == ord('r') or key == ord('R'):
-        U = V;
+        U = V
+        print("RESET")
+
     elif key == ord(' '):
 
         # Recompute just mass matrix on each step
         M = igl.eigen.SparseMatrixd()
 
-        igl.massmatrix(U,F,igl.MASSMATRIX_TYPE_BARYCENTRIC,M);
+        igl.massmatrix(U, F, igl.MASSMATRIX_TYPE_BARYCENTRIC, M)
 
         # Solve (M-delta*L) U = M*U
-        S = (M - 0.001*L)
+        S = (M - 0.001 * L)
 
         solver = igl.eigen.SimplicialLLTsparse(S)
 
-        U = solver.solve(M*U)
+        U = solver.solve(M * U)
 
         # Compute centroid and subtract (also important for numerics)
         dblA = igl.eigen.MatrixXd()
-        igl.doublearea(U,F,dblA)
+        igl.doublearea(U, F, dblA)
 
         print(dblA.sum())
 
-        area = 0.5*dblA.sum()
+        area = 0.5 * dblA.sum()
         BC = igl.eigen.MatrixXd()
-        igl.barycenter(U,F,BC)
-        centroid = igl.eigen.MatrixXd([[0.0,0.0,0.0]])
+        igl.barycenter(U, F, BC)
+        centroid = igl.eigen.MatrixXd([[0.0, 0.0, 0.0]])
 
-        for i in range(0,BC.rows()):
-            centroid += 0.5*dblA[i,0]/area*BC.row(i)
+        for i in range(0, BC.rows()):
+            centroid += 0.5 * dblA[i, 0] / area * BC.row(i)
 
-        U -= centroid.replicate(U.rows(),1)
+        U -= centroid.replicate(U.rows(), 1)
 
         # Normalize to unit surface area (important for numerics)
         U = U / math.sqrt(area)
@@ -93,13 +92,14 @@ def key_pressed(viewer, key, modifier):
     # Send new positions, update normals, recenter
     viewer.data.set_vertices(U)
     viewer.data.compute_normals()
-    viewer.core.align_camera_center(U,F)
+    viewer.core.align_camera_center(U, F)
     return True
 
+
 # Use original normals as pseudo-colors
 N = igl.eigen.MatrixXd()
-igl.per_vertex_normals(V,F,N)
-C = N.rowwiseNormalized()*0.5+0.5;
+igl.per_vertex_normals(V, F, N)
+C = N.rowwiseNormalized() * 0.5 + 0.5
 
 # Initialize smoothing with base mesh
 U = V

+ 15 - 11
python/tutorial/301_Slice.py

@@ -1,36 +1,40 @@
-from __future__ import print_function
+import sys, os
 
 # Add the igl library to the modules search path
-import sys, os
 sys.path.insert(0, os.getcwd() + "/../")
-
 import pyigl as igl
 
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 
-igl.readOFF("../../tutorial/shared/decimated-knight.off",V,F)
+
+igl.readOFF(TUTORIAL_SHARED_PATH + "decimated-knight.off", V, F)
 
 # 100 random indicies into rows of F
 I = igl.eigen.MatrixXi()
-igl.floor((0.5*(igl.eigen.MatrixXd.Random(100,1)+1.)*F.rows()),I);
+igl.floor((0.5 * (igl.eigen.MatrixXd.Random(100, 1) + 1.) * F.rows()), I)
 
 # 50 random indicies into rows of I
 J = igl.eigen.MatrixXi()
-igl.floor((0.5*(igl.eigen.MatrixXd.Random(50,1)+1.)*I.rows()),J)
+igl.floor((0.5 * (igl.eigen.MatrixXd.Random(50, 1) + 1.) * I.rows()), J)
 
 # K = I(J);
 K = igl.eigen.MatrixXi()
-igl.slice(I,J,K)
+igl.slice(I, J, K)
 
 # default green for all faces
-#C = p2e(np.array([[0.4,0.8,0.3]])).replicate(F.rows(),1)
-C = igl.eigen.MatrixXd([[0.4,0.8,0.3]]).replicate(F.rows(),1)
+# C = p2e(np.array([[0.4,0.8,0.3]])).replicate(F.rows(),1)
+C = igl.eigen.MatrixXd([[0.4, 0.8, 0.3]]).replicate(F.rows(), 1)
 
 # Red for each in K
-R = igl.eigen.MatrixXd([[1.0,0.3,0.3]]).replicate(K.rows(),1)
+R = igl.eigen.MatrixXd([[1.0, 0.3, 0.3]]).replicate(K.rows(), 1)
 # C(K,:) = R
-igl.slice_into(R,K,1,C)
+igl.slice_into(R, K, 1, C)
 
 # Plot the mesh with pseudocolors
 viewer = igl.viewer.Viewer()

+ 14 - 8
python/tutorial/302_Sort.py

@@ -1,35 +1,41 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 
-igl.readOFF("../../tutorial/shared/decimated-knight.off",V,F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "decimated-knight.off", V, F)
 
 # Sort barycenters lexicographically
 BC = igl.eigen.MatrixXd()
 sorted_BC = igl.eigen.MatrixXd()
 
-igl.barycenter(V,F,BC);
+igl.barycenter(V, F, BC)
 
 I = igl.eigen.MatrixXi()
 J = igl.eigen.MatrixXi()
 
 # sorted_BC = BC(I,:)
-igl.sortrows(BC,True,sorted_BC,I)
+igl.sortrows(BC, True, sorted_BC, I)
 
 # Get sorted "place" from sorted indices
-J.resize(I.rows(),1)
+J.resize(I.rows(), 1)
 # J(I) = 1:numel(I)
 
-igl.slice_into(igl.coloni(0,I.size()-1),I,J)
+igl.slice_into(igl.coloni(0, I.size() - 1), I, J)
 
 # Pseudo-color based on sorted place
 C = igl.eigen.MatrixXd()
-igl.jet(J.castdouble(),True,C)
+igl.jet(J.castdouble(), True, C)
 
 # Plot the mesh with pseudocolors
 viewer = igl.viewer.Viewer()

+ 25 - 20
python/tutorial/303_LaplaceEquation.py

@@ -1,73 +1,78 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 
-igl.readOFF("../../tutorial/shared/camelhead.off",V,F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "camelhead.off", V, F)
 
 # Find boundary edges
 E = igl.eigen.MatrixXi()
-igl.boundary_facets(F,E);
+igl.boundary_facets(F, E)
 
 # Find boundary vertices
-b  = igl.eigen.MatrixXi()
+b = igl.eigen.MatrixXi()
 IA = igl.eigen.MatrixXi()
 IC = igl.eigen.MatrixXi()
 
-igl.unique(E,b,IA,IC);
+igl.unique(E, b, IA, IC)
 
 # List of all vertex indices
-vall  = igl.eigen.MatrixXi()
-vin   = igl.eigen.MatrixXi()
+vall = igl.eigen.MatrixXi()
+vin = igl.eigen.MatrixXi()
 
-igl.coloni(0,V.rows()-1,vall)
+igl.coloni(0, V.rows() - 1, vall)
 
 # List of interior indices
-igl.setdiff(vall,b,vin,IA)
+igl.setdiff(vall, b, vin, IA)
 
 # Construct and slice up Laplacian
 L = igl.eigen.SparseMatrixd()
 L_in_in = igl.eigen.SparseMatrixd()
 L_in_b = igl.eigen.SparseMatrixd()
 
-igl.cotmatrix(V,F,L)
-igl.slice(L,vin,vin,L_in_in)
-igl.slice(L,vin,b,L_in_b)
+igl.cotmatrix(V, F, L)
+igl.slice(L, vin, vin, L_in_in)
+igl.slice(L, vin, b, L_in_b)
 
 # Dirichlet boundary conditions from z-coordinate
 bc = igl.eigen.MatrixXd()
 Z = V.col(2)
-igl.slice(Z,b,bc)
+igl.slice(Z, b, bc)
 
 # Solve PDE
 solver = igl.eigen.SimplicialLLTsparse(-L_in_in)
-Z_in = solver.solve(L_in_b*bc)
+Z_in = solver.solve(L_in_b * bc)
 
 # slice into solution
-igl.slice_into(Z_in,vin,Z)
+igl.slice_into(Z_in, vin, Z)
 
 # Alternative, short hand
 mqwf = igl.min_quad_with_fixed_data()
 
 # Linear term is 0
 B = igl.eigen.MatrixXd()
-B.setZero(V.rows(),1);
+B.setZero(V.rows(), 1)
 
 # Empty constraints
 Beq = igl.eigen.MatrixXd()
 Aeq = igl.eigen.SparseMatrixd()
 
 # Our cotmatrix is _negative_ definite, so flip sign
-igl.min_quad_with_fixed_precompute(-L,b,Aeq,True,mqwf)
-igl.min_quad_with_fixed_solve(mqwf,B,bc,Beq,Z)
+igl.min_quad_with_fixed_precompute(-L, b, Aeq, True, mqwf)
+igl.min_quad_with_fixed_solve(mqwf, B, bc, Beq, Z)
 
 # Pseudo-color based on solution
 C = igl.eigen.MatrixXd()
-igl.jet(Z,True,C)
+igl.jet(Z, True, C)
 
 # Plot the mesh with pseudocolors
 viewer = igl.viewer.Viewer()

+ 34 - 32
python/tutorial/304_LinearEqualityConstraints.py

@@ -1,18 +1,24 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 
-igl.readOFF("../../tutorial/shared/cheburashka.off",V,F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "cheburashka.off", V, F)
 
 # Two fixed points
 # Left hand, left foot
-b = igl.eigen.MatrixXi([[4331],[5957]])
-bc = igl.eigen.MatrixXd([[1],[-1]])
+b = igl.eigen.MatrixXi([[4331], [5957]])
+bc = igl.eigen.MatrixXd([[1], [-1]])
 
 # Construct Laplacian and mass matrix
 L = igl.eigen.SparseMatrixd()
@@ -20,17 +26,17 @@ M = igl.eigen.SparseMatrixd()
 Minv = igl.eigen.SparseMatrixd()
 Q = igl.eigen.SparseMatrixd()
 
-igl.cotmatrix(V,F,L)
-igl.massmatrix(V,F,igl.MASSMATRIX_TYPE_VORONOI,M)
-igl.invert_diag(M,Minv)
+igl.cotmatrix(V, F, L)
+igl.massmatrix(V, F, igl.MASSMATRIX_TYPE_VORONOI, M)
+igl.invert_diag(M, Minv)
 
 # Bi-Laplacian
-Q = L * (Minv * L);
+Q = L * (Minv * L)
 
 # Zero linear term
-B = igl.eigen.MatrixXd.Zero(V.rows(),1);
+B = igl.eigen.MatrixXd.Zero(V.rows(), 1)
 
-Z       = igl.eigen.MatrixXd()
+Z = igl.eigen.MatrixXd()
 Z_const = igl.eigen.MatrixXd()
 
 # Alternative, short hand
@@ -40,37 +46,33 @@ mqwf = igl.min_quad_with_fixed_data()
 Beq = igl.eigen.MatrixXd()
 Aeq = igl.eigen.SparseMatrixd()
 
-igl.min_quad_with_fixed_precompute(Q,b,Aeq,True,mqwf)
-igl.min_quad_with_fixed_solve(mqwf,B,bc,Beq,Z)
+igl.min_quad_with_fixed_precompute(Q, b, Aeq, True, mqwf)
+igl.min_quad_with_fixed_solve(mqwf, B, bc, Beq, Z)
 
 # Constraint forcing difference of two points to be 0
-Aeq = igl.eigen.SparseMatrixd(1,V.rows())
+Aeq = igl.eigen.SparseMatrixd(1, V.rows())
 
 # Right hand, right foot
-Aeq.insert(0,6074,1)
-Aeq.insert(0,6523,-1)
+Aeq.insert(0, 6074, 1)
+Aeq.insert(0, 6523, -1)
 Aeq.makeCompressed()
 
 Beq = igl.eigen.MatrixXd([[0]])
-igl.min_quad_with_fixed_precompute(Q,b,Aeq,True,mqwf)
-igl.min_quad_with_fixed_solve(mqwf,B,bc,Beq,Z_const)
+igl.min_quad_with_fixed_precompute(Q, b, Aeq, True, mqwf)
+igl.min_quad_with_fixed_solve(mqwf, B, bc, Beq, Z_const)
 
+# Global definitions for viewer
 # Pseudo-color based on solution
-global C
 C = igl.eigen.MatrixXd()
-
-global C_const
 C_const = igl.eigen.MatrixXd()
-
-global toggle
 toggle = True
 
 # Use same color axes
-min_z = min(Z.minCoeff(),Z_const.minCoeff())
-max_z = max(Z.maxCoeff(),Z_const.maxCoeff())
+min_z = min(Z.minCoeff(), Z_const.minCoeff())
+max_z = max(Z.maxCoeff(), Z_const.maxCoeff())
 
-igl.jet(      Z,min_z,max_z,C);
-igl.jet(Z_const,min_z,max_z,C_const);
+igl.jet(Z, min_z, max_z, C)
+igl.jet(Z_const, min_z, max_z, C_const)
 
 # Plot the mesh with pseudocolors
 viewer = igl.viewer.Viewer()
@@ -78,22 +80,22 @@ viewer.data.set_mesh(V, F)
 viewer.core.show_lines = False
 viewer.data.set_colors(C)
 
-def key_down(viewer,key,mode):
+
+def key_down(viewer, key, mode):
     if key == ord(' '):
-        global toggle
-        global C
-        global C_const
+        global toggle, C, C_const
 
         if toggle:
             viewer.data.set_colors(C)
         else:
             viewer.data.set_colors(C_const)
 
-        toggle = not toggle;
+        toggle = not toggle
         return True
 
     return False
 
+
 viewer.callback_key_down = key_down
 
 print("Press [space] to toggle between unconstrained and constrained.")

+ 31 - 23
python/tutorial/305_QuadraticProgramming.py

@@ -1,9 +1,15 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 b = igl.eigen.MatrixXi()
 B = igl.eigen.MatrixXd()
 bc = igl.eigen.MatrixXd()
@@ -17,37 +23,39 @@ Q = igl.eigen.SparseMatrixd()
 Aeq = igl.eigen.SparseMatrixd()
 Aieq = igl.eigen.SparseMatrixd()
 
+
 def solve(viewer):
-    global Q,B,b,bc,Aeq,Beq,Aieq,Bieq,lx,ux,Z
+    global Q, B, b, bc, Aeq, Beq, Aieq, Bieq, lx, ux, Z
     params = igl.active_set_params()
     params.max_iter = 8
 
-    igl.active_set(Q,B,b,bc,Aeq,Beq,Aieq,Bieq,lx,ux,params,Z)
+    igl.active_set(Q, B, b, bc, Aeq, Beq, Aieq, Bieq, lx, ux, params, Z)
 
     C = igl.eigen.MatrixXd()
-    igl.jet(Z,0,1,C)
+    igl.jet(Z, 0, 1, C)
     viewer.data.set_colors(C)
 
+
 def key_down(viewer, key, mod):
-    global Beq,solve
+    global Beq, solve
     if key == ord('.'):
-         Beq[0,0] = Beq[0,0] * 2.0
-         solve(viewer)
-         return True
+        Beq[0, 0] = Beq[0, 0] * 2.0
+        solve(viewer)
+        return True
     elif key == ord(','):
-         Beq[0,0] = Beq[0,0] / 2.0
-         solve(viewer)
-         return True
+        Beq[0, 0] = Beq[0, 0] / 2.0
+        solve(viewer)
+        return True
     elif key == ord(' '):
-         solve(viewer)
-         return True
-    return False;
+        solve(viewer)
+        return True
+    return False
 
 
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 
-igl.readOFF("../../tutorial/shared/cheburashka.off",V,F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "cheburashka.off", V, F)
 
 # Plot the mesh
 viewer = igl.viewer.Viewer()
@@ -56,7 +64,7 @@ viewer.core.show_lines = False
 viewer.callback_key_down = key_down
 
 # One fixed point on belly
-b  = igl.eigen.MatrixXi([[2556]])
+b = igl.eigen.MatrixXi([[2556]])
 bc = igl.eigen.MatrixXd([[1]])
 
 # Construct Laplacian and mass matrix
@@ -64,19 +72,19 @@ L = igl.eigen.SparseMatrixd()
 M = igl.eigen.SparseMatrixd()
 Minv = igl.eigen.SparseMatrixd()
 
-igl.cotmatrix(V,F,L)
-igl.massmatrix(V,F,igl.MASSMATRIX_TYPE_VORONOI,M);
-igl.invert_diag(M,Minv)
+igl.cotmatrix(V, F, L)
+igl.massmatrix(V, F, igl.MASSMATRIX_TYPE_VORONOI, M)
+igl.invert_diag(M, Minv)
 
 # Bi-Laplacian
 Q = L.transpose() * (Minv * L)
 
 # Zero linear term
-B = igl.eigen.MatrixXd.Zero(V.rows(),1)
+B = igl.eigen.MatrixXd.Zero(V.rows(), 1)
 
 # Lower and upper bound
-lx = igl.eigen.MatrixXd.Zero(V.rows(),1)
-ux = igl.eigen.MatrixXd.Ones(V.rows(),1)
+lx = igl.eigen.MatrixXd.Zero(V.rows(), 1)
+ux = igl.eigen.MatrixXd.Ones(V.rows(), 1)
 
 # Equality constraint constrain solution to sum to 1
 Beq = igl.eigen.MatrixXd([[0.08]])

+ 22 - 14
python/tutorial/306_EigenDecomposition.py

@@ -1,9 +1,15 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 U = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
@@ -12,7 +18,7 @@ c = 0
 bbd = 1.0
 twod = False
 
-if not igl.read_triangle_mesh("../../tutorial/shared/beetle.off",V,F):
+if not igl.read_triangle_mesh(TUTORIAL_SHARED_PATH + "beetle.off", V, F):
     print("failed to load mesh")
 
 twod = V.col(2).minCoeff() == V.col(2).maxCoeff()
@@ -21,40 +27,42 @@ bbd = (V.colwiseMaxCoeff() - V.colwiseMinCoeff()).norm()
 L = igl.eigen.SparseMatrixd()
 M = igl.eigen.SparseMatrixd()
 
-igl.cotmatrix(V,F,L)
+igl.cotmatrix(V, F, L)
 L = -L
-igl.massmatrix(V,F,igl.MASSMATRIX_TYPE_DEFAULT,M)
+igl.massmatrix(V, F, igl.MASSMATRIX_TYPE_DEFAULT, M)
 k = 5
 
 D = igl.eigen.MatrixXd()
-if not igl.eigs(L,M,k+1,igl.EIGS_TYPE_SM,U,D):
+if not igl.eigs(L, M, k + 1, igl.EIGS_TYPE_SM, U, D):
     print("Eigs failed.")
 
-U = (U-U.minCoeff())/(U.maxCoeff()-U.minCoeff());
+U = (U - U.minCoeff()) / (U.maxCoeff() - U.minCoeff())
 
 viewer = igl.viewer.Viewer()
 
-def key_down(viewer,key,mod):
+
+def key_down(viewer, key, mod):
     global U, c
 
     if key == ord(' '):
         U = U.rightCols(k)
 
         # Rescale eigen vectors for visualization
-        Z = bbd*0.5*U.col(c)
+        Z = bbd * 0.5 * U.col(c)
         C = igl.eigen.MatrixXd()
-        igl.parula(U.col(c),False,C)
-        c = (c+1)%U.cols()
+        igl.parula(U.col(c), False, C)
+        c = (c + 1) % U.cols()
 
         if twod:
-            V.setcol(2,Z)
+            V.setcol(2, Z)
 
-        viewer.data.set_mesh(V,F)
+        viewer.data.set_mesh(V, F)
         viewer.data.compute_normals()
         viewer.data.set_colors(C)
         return True
 
+
 viewer.callback_key_down = key_down
-viewer.callback_key_down(viewer,ord(' '),0);
+viewer.callback_key_down(viewer, ord(' '), 0)
 viewer.core.show_lines = False
 viewer.launch()

+ 35 - 29
python/tutorial/401_BiharmonicDeformation.py

@@ -1,10 +1,14 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# Add the igl library to the modules search path
+sys.path.insert(0, os.getcwd() + "/../")
 import pyigl as igl
 
-global bc_frac, bc_dir,deformation_field, V, U, V_bc, U_bc, F, b
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
 bc_frac = 1.0
 bc_dir = -0.03
 deformation_field = False
@@ -18,77 +22,79 @@ U_bc = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 b = igl.eigen.MatrixXi()
 
+
 def pre_draw(viewer):
-    global bc_frac, bc_dir,deformation_field, V, U, V_bc, U_bc, F, b
+    global bc_frac, bc_dir, deformation_field, V, U, V_bc, U_bc, F, b
     # Determine boundary conditions
     if (viewer.core.is_animating):
         bc_frac += bc_dir
-        bc_dir *= (-1.0 if bc_frac>=1.0 or bc_frac <= 0.0 else 1.0)
+        bc_dir *= (-1.0 if bc_frac >= 1.0 or bc_frac <= 0.0 else 1.0)
 
-    U_bc_anim = V_bc+bc_frac*(U_bc-V_bc)
+    U_bc_anim = V_bc + bc_frac * (U_bc - V_bc)
 
     if (deformation_field):
         D = igl.eigen.MatrixXd()
         D_bc = U_bc_anim - V_bc
-        igl.harmonic(V,F,b,D_bc,2,D)
-        U = V+D
+        igl.harmonic(V, F, b, D_bc, 2, D)
+        U = V + D
     else:
-        igl.harmonic(V,F,b,U_bc_anim,2,U)
+        igl.harmonic(V, F, b, U_bc_anim, 2, U)
 
     viewer.data.set_vertices(U)
     viewer.data.compute_normals()
     return False
 
+
 def key_down(viewer, key, mods):
-    global bc_frac, bc_dir,deformation_field, V, U, V_bc, U_bc, F, b
+    global bc_frac, bc_dir, deformation_field, V, U, V_bc, U_bc, F, b
 
     if key == ord(' '):
         viewer.core.is_animating = not viewer.core.is_animating
         return True
     if key == ord('D') or key == ord('d'):
-        deformation_field = not deformation_field;
+        deformation_field = not deformation_field
         return True
     return False
 
 
-igl.readOBJ("../../tutorial/shared/decimated-max.obj",V,F)
+igl.readOBJ(TUTORIAL_SHARED_PATH + "decimated-max.obj", V, F)
 U = igl.eigen.MatrixXd(V)
 
 # S(i) = j: j<0 (vertex i not in handle), j >= 0 (vertex i in handle j)
 S = igl.eigen.MatrixXd()
-igl.readDMAT("../../tutorial/shared/decimated-max-selection.dmat",S)
+igl.readDMAT(TUTORIAL_SHARED_PATH + "decimated-max-selection.dmat", S)
 
 S = S.castint()
 
-b = igl.eigen.MatrixXi([[t[0] for t in [(i,S[i]) for i in range(0,V.rows())] if t[1] >= 0]]).transpose()
+b = igl.eigen.MatrixXi([[t[0] for t in [(i, S[i]) for i in range(0, V.rows())] if t[1] >= 0]]).transpose()
 
 # Boundary conditions directly on deformed positions
-U_bc.resize(b.rows(),V.cols())
-V_bc.resize(b.rows(),V.cols())
+U_bc.resize(b.rows(), V.cols())
+V_bc.resize(b.rows(), V.cols())
 
-for bi in range(0,b.rows()):
-    V_bc.setRow(bi,V.row(b[bi]))
+for bi in range(0, b.rows()):
+    V_bc.setRow(bi, V.row(b[bi]))
 
-    if (S[b[bi]] == 0):
+    if S[b[bi]] == 0:
         # Don't move handle 0
-        U_bc.setRow(bi,V.row(b[bi]))
+        U_bc.setRow(bi, V.row(b[bi]))
     elif S[b[bi]] == 1:
         # Move handle 1 down
-        U_bc.setRow(bi,V.row(b[bi]) + igl.eigen.MatrixXd([[0,-50,0]]))
+        U_bc.setRow(bi, V.row(b[bi]) + igl.eigen.MatrixXd([[0, -50, 0]]))
     else:
         # Move other handles forward
-        U_bc.setRow(bi,V.row(b[bi]) + igl.eigen.MatrixXd([[0,0,-25]]))
+        U_bc.setRow(bi, V.row(b[bi]) + igl.eigen.MatrixXd([[0, 0, -25]]))
 
 # Pseudo-color based on selection
-C = igl.eigen.MatrixXd(F.rows(),3)
-purple = igl.eigen.MatrixXd([[80.0/255.0,64.0/255.0,255.0/255.0]])
-gold   = igl.eigen.MatrixXd([[255.0/255.0,228.0/255.0,58.0/255.0]])
+C = igl.eigen.MatrixXd(F.rows(), 3)
+purple = igl.eigen.MatrixXd([[80.0 / 255.0, 64.0 / 255.0, 255.0 / 255.0]])
+gold = igl.eigen.MatrixXd([[255.0 / 255.0, 228.0 / 255.0, 58.0 / 255.0]])
 
-for f in range(0,F.rows()):
-    if (S[F[f,0]])>=0 and S[F[f,1]]>=0 and S[F[f,2]]>=0:
-        C.setRow(f,purple)
+for f in range(0, F.rows()):
+    if (S[F[f, 0]]) >= 0 and S[F[f, 1]] >= 0 and S[F[f, 2]] >= 0:
+        C.setRow(f, purple)
     else:
-        C.setRow(f,gold)
+        C.setRow(f, gold)
 
 # Plot the mesh with pseudocolors
 viewer = igl.viewer.Viewer()

+ 29 - 24
python/tutorial/402_PolyharmonicDeformation.py

@@ -1,17 +1,20 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# Add the igl library to the modules search path
+sys.path.insert(0, os.getcwd() + "/../")
 import pyigl as igl
 
-global z_max, z_dir, k, resolve, V, U, Z, F, b, bc
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
 
 z_max = 1.0
 z_dir = -0.03
 k = 2
 resolve = True
 
-
 V = igl.eigen.MatrixXd()
 U = igl.eigen.MatrixXd()
 
@@ -22,23 +25,25 @@ b = igl.eigen.MatrixXi()
 
 bc = igl.eigen.MatrixXd()
 
+
 def pre_draw(viewer):
     global z_max, z_dir, k, resolve, V, U, Z, F, b, bc
 
     if resolve:
-        igl.harmonic(V,F,b,bc,k,Z)
+        igl.harmonic(V, F, b, bc, k, Z)
         resolve = False
 
-    U.setCol(2,z_max*Z)
+    U.setCol(2, z_max * Z)
     viewer.data.set_vertices(U)
     viewer.data.compute_normals()
 
     if viewer.core.is_animating:
         z_max += z_dir
-        z_dir *= (-1.0 if z_max>=1.0 or z_max<=0.0 else 1.0)
+        z_dir *= (-1.0 if z_max >= 1.0 or z_max <= 0.0 else 1.0)
 
     return False
 
+
 def key_down(viewer, key, mods):
     global z_max, z_dir, k, resolve, V, U, Z, F, b, bc
 
@@ -46,42 +51,42 @@ def key_down(viewer, key, mods):
         viewer.core.is_animating = not viewer.core.is_animating
     elif key == ord('.'):
         k = k + 1
-        k = (4 if k>4 else k)
+        k = (4 if k > 4 else k)
         resolve = True
     elif key == ord(','):
         k = k - 1
-        k = (1 if k<1 else k)
+        k = (1 if k < 1 else k)
         resolve = True
     return True
 
 
-igl.readOBJ("../../tutorial/shared/bump-domain.obj",V,F)
+igl.readOBJ(TUTORIAL_SHARED_PATH + "bump-domain.obj", V, F)
 U = igl.eigen.MatrixXd(V)
 
 # Find boundary vertices outside annulus
 
 Vrn = V.rowwiseNorm()
-is_outer = [Vrn[i]-1.00 > -1e-15 for i in range(0,V.rows())]
-is_inner = [Vrn[i]-0.15 <  1e-15 for i in range(0,V.rows())]
-in_b = [ is_outer[i] or is_inner[i] for i in range(0,len(is_outer))]
+is_outer = [Vrn[i] - 1.00 > -1e-15 for i in range(0, V.rows())]
+is_inner = [Vrn[i] - 0.15 < 1e-15 for i in range(0, V.rows())]
+in_b = [is_outer[i] or is_inner[i] for i in range(0, len(is_outer))]
 
-b = igl.eigen.MatrixXi([[i for i in range(0,V.rows()) if (in_b[i])]]).transpose();
+b = igl.eigen.MatrixXi([[i for i in range(0, V.rows()) if (in_b[i])]]).transpose()
 
-bc.resize(b.size(),1)
+bc.resize(b.size(), 1)
 
-for bi in range(0,b.size()):
+for bi in range(0, b.size()):
     bc[bi] = (0.0 if is_outer[b[bi]] else 1.0)
 
 # Pseudo-color based on selection
-C = igl.eigen.MatrixXd(F.rows(),3)
-purple = igl.eigen.MatrixXd([[80.0/255.0,64.0/255.0,255.0/255.0]])
-gold   = igl.eigen.MatrixXd([[255.0/255.0,228.0/255.0,58.0/255.0]])
+C = igl.eigen.MatrixXd(F.rows(), 3)
+purple = igl.eigen.MatrixXd([[80.0 / 255.0, 64.0 / 255.0, 255.0 / 255.0]])
+gold = igl.eigen.MatrixXd([[255.0 / 255.0, 228.0 / 255.0, 58.0 / 255.0]])
 
-for f in range(0,F.rows()):
-    if( in_b[F[f,0]] and in_b[F[f,1]] and in_b[F[f,2]]):
-        C.setRow(f,purple)
+for f in range(0, F.rows()):
+    if in_b[F[f, 0]] and in_b[F[f, 1]] and in_b[F[f, 2]]:
+        C.setRow(f, purple)
     else:
-        C.setRow(f,gold)
+        C.setRow(f, gold)
 
 # Plot the mesh with pseudocolors
 viewer = igl.viewer.Viewer()
@@ -97,4 +102,4 @@ viewer.core.animation_max_fps = 30.0
 print("Press [space] to toggle animation.")
 print("Press '.' to increase k.")
 print("Press ',' to decrease k.")
-viewer.launch();
+viewer.launch()

+ 40 - 31
python/tutorial/405_AsRigidAsPossible.py

@@ -1,11 +1,17 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
+from math import sin, cos, pi
 
+# Add the igl library to the modules search path
+sys.path.insert(0, os.getcwd() + "/../")
 import pyigl as igl
-from math import sin,cos,pi
 
-sea_green = igl.eigen.MatrixXd([[70./255.,252./255.,167./255.]])
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
+sea_green = igl.eigen.MatrixXd([[70. / 255., 252. / 255., 167. / 255.]])
 
 V = igl.eigen.MatrixXd()
 U = igl.eigen.MatrixXd()
@@ -17,30 +23,31 @@ b = igl.eigen.MatrixXi()
 
 mid = igl.eigen.MatrixXd()
 
-anim_t = 0.0;
-anim_t_dir = 0.03;
+anim_t = 0.0
+anim_t_dir = 0.03
 arap_data = igl.ARAPData()
 
+
 def pre_draw(viewer):
     global anim_t
 
-    bc = igl.eigen.MatrixXd(b.size(),V.cols())
-    for i in range(0,b.size()):
-        bc.setRow(i,V.row(b[i]))
+    bc = igl.eigen.MatrixXd(b.size(), V.cols())
+    for i in range(0, b.size()):
+        bc.setRow(i, V.row(b[i]))
         if S[b[i]] == 0:
-            r = mid[0]*0.25
-            bc[i,0] = bc[i,0] + r*sin(0.5*anim_t*2.*pi)
-            bc[i,1] = bc[i,1] - r+r*cos(pi+0.5*anim_t*2.*pi)
+            r = mid[0] * 0.25
+            bc[i, 0] += r * sin(0.5 * anim_t * 2. * pi)
+            bc[i, 1] = bc[i, 1] - r + r * cos(pi + 0.5 * anim_t * 2. * pi)
         elif S[b[i]] == 1:
-            r = mid[1]*0.15
-            bc[i,1] = bc[i,1] + r + r*cos(pi + 0.15*anim_t*2.*pi)
-            bc[i,2] = bc[i,2] - r*sin(0.15*anim_t*2.*pi)
+            r = mid[1] * 0.15
+            bc[i, 1] = bc[i, 1] + r + r * cos(pi + 0.15 * anim_t * 2. * pi)
+            bc[i, 2] -= r * sin(0.15 * anim_t * 2. * pi)
         elif S[b[i]] == 2:
-            r = mid[1]*0.15
-            bc[i,2] = bc[i,2] + r+r*cos(pi+0.35*anim_t*2.*pi)
-            bc[i,0] = bc[i,0] + r*sin(0.35*anim_t*2.*pi)
+            r = mid[1] * 0.15
+            bc[i, 2] = bc[i, 2] + r + r * cos(pi + 0.35 * anim_t * 2. * pi)
+            bc[i, 0] += r * sin(0.35 * anim_t * 2. * pi)
 
-    igl.arap_solve(bc,arap_data,U)
+    igl.arap_solve(bc, arap_data, U)
     viewer.data.set_vertices(U)
     viewer.data.compute_normals()
 
@@ -49,37 +56,39 @@ def pre_draw(viewer):
 
     return False
 
+
 def key_down(viewer, key, mods):
     if key == ord(' '):
         viewer.core.is_animating = not viewer.core.is_animating
         return True
     return False
 
-igl.readOFF("../../tutorial/shared/decimated-knight.off",V,F)
+
+igl.readOFF(TUTORIAL_SHARED_PATH + "decimated-knight.off", V, F)
 U = igl.eigen.MatrixXd(V)
-igl.readDMAT("../../tutorial/shared/decimated-knight-selection.dmat",S)
+igl.readDMAT(TUTORIAL_SHARED_PATH + "decimated-knight-selection.dmat", S)
 
 # Vertices in selection
 
-b = igl.eigen.MatrixXi([[t[0] for t in [(i,S[i]) for i in range(0,V.rows())] if t[1] >= 0]]).transpose()
+b = igl.eigen.MatrixXi([[t[0] for t in [(i, S[i]) for i in range(0, V.rows())] if t[1] >= 0]]).transpose()
 
 # Centroid
-mid = 0.5*(V.colwiseMaxCoeff() + V.colwiseMinCoeff())
+mid = 0.5 * (V.colwiseMaxCoeff() + V.colwiseMinCoeff())
 
 # Precomputation
 arap_data.max_iter = 100
-igl.arap_precomputation(V,F,V.cols(),b,arap_data)
+igl.arap_precomputation(V, F, V.cols(), b, arap_data)
 
 # Set color based on selection
-C = igl.eigen.MatrixXd(F.rows(),3)
-purple = igl.eigen.MatrixXd([[80.0/255.0,64.0/255.0,255.0/255.0]])
-gold   = igl.eigen.MatrixXd([[255.0/255.0,228.0/255.0,58.0/255.0]])
+C = igl.eigen.MatrixXd(F.rows(), 3)
+purple = igl.eigen.MatrixXd([[80.0 / 255.0, 64.0 / 255.0, 255.0 / 255.0]])
+gold = igl.eigen.MatrixXd([[255.0 / 255.0, 228.0 / 255.0, 58.0 / 255.0]])
 
-for f in range(0,F.rows()):
-    if S[F[f,0]]>=0 and S[F[f,1]]>=0 and S[F[f,2]]>=0:
-        C.setRow(f,purple)
+for f in range(0, F.rows()):
+    if S[F[f, 0]] >= 0 and S[F[f, 1]] >= 0 and S[F[f, 2]] >= 0:
+        C.setRow(f, purple)
     else:
-        C.setRow(f,gold)
+        C.setRow(f, gold)
 
 # Plot the mesh with pseudocolors
 viewer = igl.viewer.Viewer()

+ 19 - 11
python/tutorial/501_HarmonicParam.py

@@ -1,41 +1,49 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 V_uv = igl.eigen.MatrixXd()
 
+
 def key_down(viewer, key, modifier):
     if key == ord('1'):
         # Plot the 3D mesh
-        viewer.data.set_mesh(V,F)
-        viewer.core.align_camera_center(V,F)
+        viewer.data.set_mesh(V, F)
+        viewer.core.align_camera_center(V, F)
     elif key == ord('2'):
         # Plot the mesh in 2D using the UV coordinates as vertex coordinates
-        viewer.data.set_mesh(V_uv,F)
-        viewer.core.align_camera_center(V_uv,F)
+        viewer.data.set_mesh(V_uv, F)
+        viewer.core.align_camera_center(V_uv, F)
     viewer.data.compute_normals()
     return False
 
+
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/camelhead.off", V, F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "camelhead.off", V, F)
 
 # Find the open boundary
 bnd = igl.eigen.MatrixXi()
-igl.boundary_loop(F,bnd)
+igl.boundary_loop(F, bnd)
 
 # Map the boundary to a circle, preserving edge proportions
 bnd_uv = igl.eigen.MatrixXd()
-igl.map_vertices_to_circle(V,bnd,bnd_uv)
+igl.map_vertices_to_circle(V, bnd, bnd_uv)
 
 # Harmonic parametrization for the internal vertices
-igl.harmonic(V,F,bnd,bnd_uv,1,V_uv)
+igl.harmonic(V, F, bnd, bnd_uv, 1, V_uv)
 
 # Scale UV to make the texture more clear
-V_uv *= 5;
+V_uv *= 5
 
 # Plot the mesh
 viewer = igl.viewer.Viewer()

+ 20 - 12
python/tutorial/502_LSCMParam.py

@@ -1,39 +1,47 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 V_uv = igl.eigen.MatrixXd()
 
+
 def key_down(viewer, key, modifier):
     if key == ord('1'):
         # Plot the 3D mesh
-        viewer.data.set_mesh(V,F)
-        viewer.core.align_camera_center(V,F)
+        viewer.data.set_mesh(V, F)
+        viewer.core.align_camera_center(V, F)
     elif key == ord('2'):
         # Plot the mesh in 2D using the UV coordinates as vertex coordinates
-        viewer.data.set_mesh(V_uv,F)
-        viewer.core.align_camera_center(V_uv,F)
+        viewer.data.set_mesh(V_uv, F)
+        viewer.core.align_camera_center(V_uv, F)
     viewer.data.compute_normals()
     return False
 
+
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/camelhead.off", V, F);
+igl.readOFF(TUTORIAL_SHARED_PATH + "camelhead.off", V, F)
 
 # Fix two points on the boundary
 bnd = igl.eigen.MatrixXi()
-b   = igl.eigen.MatrixXi(2,1)
+b = igl.eigen.MatrixXi(2, 1)
 
-igl.boundary_loop(F,bnd)
+igl.boundary_loop(F, bnd)
 b[0] = bnd[0]
-b[1] = bnd[int(bnd.size()/2)]
-bc = igl.eigen.MatrixXd([[0,0],[1,0]])
+b[1] = bnd[int(bnd.size() / 2)]
+bc = igl.eigen.MatrixXd([[0, 0], [1, 0]])
 
 # LSCM parametrization
-igl.lscm(V,F,b,bc,V_uv)
+igl.lscm(V, F, b, bc, V_uv)
 
 # Scale the uv
 V_uv *= 5

+ 24 - 16
python/tutorial/503_ARAPParam.py

@@ -1,9 +1,15 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
 
+# 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
+
+dependencies = ["viewer"]
+check_dependencies(dependencies)
+
+
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
 V_uv = igl.eigen.MatrixXd()
@@ -11,6 +17,7 @@ initial_guess = igl.eigen.MatrixXd()
 
 show_uv = False
 
+
 def key_down(viewer, key, modifier):
     global show_uv, V_uv
     if key == ord('1'):
@@ -20,43 +27,44 @@ def key_down(viewer, key, modifier):
     elif key == ord('q'):
         V_uv = initial_guess
 
-    if (show_uv):
-        viewer.data.set_mesh(V_uv,F)
-        viewer.core.align_camera_center(V_uv,F)
+    if show_uv:
+        viewer.data.set_mesh(V_uv, F)
+        viewer.core.align_camera_center(V_uv, F)
     else:
-        viewer.data.set_mesh(V,F)
-        viewer.core.align_camera_center(V,F)
+        viewer.data.set_mesh(V, F)
+        viewer.core.align_camera_center(V, F)
 
     viewer.data.compute_normals()
     return False
 
+
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/camelhead.off", V, F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "camelhead.off", V, F)
 
 # Compute the initial solution for ARAP (harmonic parametrization)
 bnd = igl.eigen.MatrixXi()
-igl.boundary_loop(F,bnd)
+igl.boundary_loop(F, bnd)
 bnd_uv = igl.eigen.MatrixXd()
-igl.map_vertices_to_circle(V,bnd,bnd_uv)
+igl.map_vertices_to_circle(V, bnd, bnd_uv)
 
-igl.harmonic(V,F,bnd,bnd_uv,1,initial_guess)
+igl.harmonic(V, F, bnd, bnd_uv, 1, initial_guess)
 
 # Add dynamic regularization to avoid to specify boundary conditions
 arap_data = igl.ARAPData()
 arap_data.with_dynamics = True
-b  = igl.eigen.MatrixXi.Zero(0,0);
-bc = igl.eigen.MatrixXd.Zero(0,0);
+b = igl.eigen.MatrixXi.Zero(0, 0)
+bc = igl.eigen.MatrixXd.Zero(0, 0)
 
 # Initialize ARAP
 arap_data.max_iter = 100
 
 # 2 means that we're going to *solve* in 2d
-igl.arap_precomputation(V,F,2,b,arap_data)
+igl.arap_precomputation(V, F, 2, b, arap_data)
 
 # Solve arap using the harmonic map as initial guess
-V_uv = igl.eigen.MatrixXd(initial_guess) # important, make a copy of it!
+V_uv = igl.eigen.MatrixXd(initial_guess)  # important, make a copy of it!
 
-igl.arap_solve(bc,arap_data,V_uv)
+igl.arap_solve(bc, arap_data, V_uv)
 
 # Scale UV to make the texture more clear
 V_uv *= 20

+ 39 - 29
python/tutorial/504_NRosyDesign.py

@@ -1,9 +1,15 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
+from math import atan2, pi, cos, sin
 
+# Add the igl library to the modules search path
+sys.path.insert(0, os.getcwd() + "/../")
 import pyigl as igl
-from math import atan2,pi,cos,sin
+
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["comiso", "viewer"]
+check_dependencies(dependencies)
+
 
 # Mesh
 V = igl.eigen.MatrixXd()
@@ -16,7 +22,8 @@ b = igl.eigen.MatrixXi()
 bc = igl.eigen.MatrixXd()
 
 # Degree of the N-RoSy field
-N = 4;
+N = 4
+
 
 # Converts a representative vector per face in the full set of vectors that describe
 # an N-RoSy field
@@ -25,27 +32,28 @@ def representative_to_nrosy(V, F, R, N, Y):
     B2 = igl.eigen.MatrixXd()
     B3 = igl.eigen.MatrixXd()
 
-    igl.local_basis(V,F,B1,B2,B3)
+    igl.local_basis(V, F, B1, B2, B3)
 
-    Y.resize(F.rows()*N, 3)
+    Y.resize(F.rows() * N, 3)
 
-    for i in range (0,F.rows()):
+    for i in range(0, F.rows()):
         x = R.row(i) * B1.row(i).transpose()
         y = R.row(i) * B2.row(i).transpose()
-        angle = atan2(y[0],x[0])
+        angle = atan2(y[0], x[0])
 
-        for j in range(0,N):
-            anglej = angle + 2*pi*j/float(N)
+        for j in range(0, N):
+            anglej = angle + 2 * pi * j / float(N)
             xj = cos(anglej)
             yj = sin(anglej)
-            Y.setRow(i*N+j, xj * B1.row(i) + yj * B2.row(i))
+            Y.setRow(i * N + j, xj * B1.row(i) + yj * B2.row(i))
+
 
 # Plots the mesh with an N-RoSy field and its singularities on top
 # The constrained faces (b) are colored in red.
 def plot_mesh_nrosy(viewer, V, F, N, PD1, S, b):
     # Clear the mesh
     viewer.data.clear()
-    viewer.data.set_mesh(V,F)
+    viewer.data.set_mesh(V, F)
 
     # Expand the representative vectors in the full vector set and plot them as lines
     avg = igl.avg_edge_length(V, F)
@@ -53,48 +61,50 @@ def plot_mesh_nrosy(viewer, V, F, N, PD1, S, b):
     representative_to_nrosy(V, F, PD1, N, Y)
 
     B = igl.eigen.MatrixXd()
-    igl.barycenter(V,F,B)
+    igl.barycenter(V, F, B)
 
-    Be = igl.eigen.MatrixXd(B.rows()*N,3)
-    for i in range(0,B.rows()):
-        for j in range(0,N):
-            Be.setRow(i*N+j,B.row(i))
+    Be = igl.eigen.MatrixXd(B.rows() * N, 3)
+    for i in range(0, B.rows()):
+        for j in range(0, N):
+            Be.setRow(i * N + j, B.row(i))
 
-    viewer.data.add_edges(Be,Be+Y*(avg/2),igl.eigen.MatrixXd([[0,0,1]]))
+    viewer.data.add_edges(Be, Be + Y * (avg / 2), igl.eigen.MatrixXd([[0, 0, 1]]))
 
     # Plot the singularities as colored dots (red for negative, blue for positive)
-    for i in range(0,S.size()):
+    for i in range(0, S.size()):
         if S[i] < -0.001:
-            viewer.data.add_points(V.row(i),igl.eigen.MatrixXd([[1,0,0]]))
+            viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
         elif S[i] > 0.001:
-            viewer.data.add_points(V.row(i),igl.eigen.MatrixXd([[0,1,0]]));
+            viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[0, 1, 0]]));
 
     # Highlight in red the constrained faces
-    C = igl.eigen.MatrixXd.Constant(F.rows(),3,1)
-    for i in range(0,b.size()):
+    C = igl.eigen.MatrixXd.Constant(F.rows(), 3, 1)
+    for i in range(0, b.size()):
         C.setRow(b[i], igl.eigen.MatrixXd([[1, 0, 0]]))
     viewer.data.set_colors(C)
 
+
 # It allows to change the degree of the field when a number is pressed
 def key_down(viewer, key, modifier):
     global N
-    if key >= ord('1') and key <= ord('9'):
+    if ord('1') <= key <= ord('9'):
         N = key - ord('0')
 
     R = igl.eigen.MatrixXd()
     S = igl.eigen.MatrixXd()
 
-    igl.comiso.nrosy(V,F,b,bc,igl.eigen.MatrixXi(),igl.eigen.MatrixXd(),igl.eigen.MatrixXd(),N,0.5,R,S)
-    plot_mesh_nrosy(viewer,V,F,N,R,S,b)
+    igl.comiso.nrosy(V, F, b, bc, igl.eigen.MatrixXi(), igl.eigen.MatrixXd(), igl.eigen.MatrixXd(), N, 0.5, R, S)
+    plot_mesh_nrosy(viewer, V, F, N, R, S, b)
 
     return False
 
+
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/bumpy.off", V, F);
+igl.readOFF(TUTORIAL_SHARED_PATH + "bumpy.off", V, F)
 
 # Threshold faces with high anisotropy
-b  = igl.eigen.MatrixXi([[0]])
-bc = igl.eigen.MatrixXd([[1,1,1]])
+b = igl.eigen.MatrixXi([[0]])
+bc = igl.eigen.MatrixXd([[1, 1, 1]])
 
 viewer = igl.viewer.Viewer()
 

+ 76 - 86
python/tutorial/505_MIQ.py

@@ -1,9 +1,15 @@
-# Add the igl library to the modules search path
 import sys, os
-sys.path.insert(0, os.getcwd() + "/../")
+from math import pi
 
+# Add the igl library to the modules search path
+sys.path.insert(0, os.getcwd() + "/../")
 import pyigl as igl
-from math import pi
+
+from shared import TUTORIAL_SHARED_PATH, check_dependencies
+
+dependencies = ["comiso", "viewer"]
+check_dependencies(dependencies)
+
 
 V = igl.eigen.MatrixXd()
 F = igl.eigen.MatrixXi()
@@ -13,7 +19,7 @@ B = igl.eigen.MatrixXd()
 
 # Scale for visualizing the fields
 global_scale = 1
-extend_arrows = False;
+extend_arrows = False
 
 # Cross field
 X1 = igl.eigen.MatrixXd()
@@ -54,25 +60,27 @@ texture_R = igl.eigen.MatrixXuc()
 texture_G = igl.eigen.MatrixXuc()
 texture_B = igl.eigen.MatrixXuc()
 
+
 # Create a texture that hides the integer translation in the parametrization
 def line_texture():
     size = 128
-    size2 = int(size/2)
+    size2 = int(size / 2)
     lineWidth = 3
     texture_R.setConstant(size, size, 255)
 
-    for i in range(0,size):
-        for j in range(size2-lineWidth,size2+lineWidth+1):
-            texture_R[i,j] = 0
+    for i in range(0, size):
+        for j in range(size2 - lineWidth, size2 + lineWidth + 1):
+            texture_R[i, j] = 0
 
-    for i in range(size2-lineWidth,size2+lineWidth+1):
-        for j in range(0,size):
-            texture_R[i,j] = 0
+    for i in range(size2 - lineWidth, size2 + lineWidth + 1):
+        for j in range(0, size):
+            texture_R[i, j] = 0
 
     texture_G = texture_R.copy()
     texture_B = texture_R.copy()
     return (texture_R, texture_G, texture_B)
 
+
 def key_down(viewer, key, modifier):
     global extend_arrows, texture_R, texture_G, texture_B
 
@@ -80,7 +88,7 @@ def key_down(viewer, key, modifier):
         extend_arrows = not extend_arrows
 
     if key < ord('1') or key > ord('8'):
-        return False;
+        return False
 
     viewer.data.clear()
     viewer.core.show_lines = False
@@ -89,20 +97,26 @@ def key_down(viewer, key, modifier):
     if key == ord('1'):
         # Cross field
         viewer.data.set_mesh(V, F)
-        viewer.data.add_edges(B - global_scale*X1 if extend_arrows else B, B + global_scale*X1 , igl.eigen.MatrixXd([[1,0,0]]))
-        viewer.data.add_edges(B - global_scale*X2 if extend_arrows else B, B + global_scale*X2 , igl.eigen.MatrixXd([[0,0,1]]))
+        viewer.data.add_edges(B - global_scale * X1 if extend_arrows else B, B + global_scale * X1,
+                              igl.eigen.MatrixXd([[1, 0, 0]]))
+        viewer.data.add_edges(B - global_scale * X2 if extend_arrows else B, B + global_scale * X2,
+                              igl.eigen.MatrixXd([[0, 0, 1]]))
 
     if key == ord('2'):
         # Bisector field
         viewer.data.set_mesh(V, F)
-        viewer.data.add_edges(B - global_scale*BIS1 if extend_arrows else B, B + global_scale*BIS1 , igl.eigen.MatrixXd([[1,0,0]]))
-        viewer.data.add_edges(B - global_scale*BIS2 if extend_arrows else B, B + global_scale*BIS2 , igl.eigen.MatrixXd([[0,0,1]]))
+        viewer.data.add_edges(B - global_scale * BIS1 if extend_arrows else B, B + global_scale * BIS1,
+                              igl.eigen.MatrixXd([[1, 0, 0]]))
+        viewer.data.add_edges(B - global_scale * BIS2 if extend_arrows else B, B + global_scale * BIS2,
+                              igl.eigen.MatrixXd([[0, 0, 1]]))
 
     if key == ord('3'):
         # Bisector field combed
         viewer.data.set_mesh(V, F)
-        viewer.data.add_edges(B - global_scale*BIS1_combed if extend_arrows else B, B + global_scale*BIS1_combed , igl.eigen.MatrixXd([[1,0,0]]))
-        viewer.data.add_edges(B - global_scale*BIS2_combed if extend_arrows else B, B + global_scale*BIS2_combed , igl.eigen.MatrixXd([[0,0,1]]))
+        viewer.data.add_edges(B - global_scale * BIS1_combed if extend_arrows else B, B + global_scale * BIS1_combed,
+                              igl.eigen.MatrixXd([[1, 0, 0]]))
+        viewer.data.add_edges(B - global_scale * BIS2_combed if extend_arrows else B, B + global_scale * BIS2_combed,
+                              igl.eigen.MatrixXd([[0, 0, 1]]))
 
     if key == ord('4'):
         # Singularities and cuts
@@ -110,53 +124,55 @@ def key_down(viewer, key, modifier):
 
         # Plot cuts
         l_count = Seams.sum()
-        P1 = igl.eigen.MatrixXd(l_count,3)
-        P2 = igl.eigen.MatrixXd(l_count,3)
+        P1 = igl.eigen.MatrixXd(l_count, 3)
+        P2 = igl.eigen.MatrixXd(l_count, 3)
 
-        for i in range(0,Seams.rows()):
-            for j in range(0,Seams.cols()):
-                if Seams[i,j] != 0:
-                    P1.setRow(l_count-1, V.row(F[i,j]))
-                    P2.setRow(l_count-1, V.row(F[i,(j+1)%3]))
-                    l_count = l_count - 1
+        for i in range(0, Seams.rows()):
+            for j in range(0, Seams.cols()):
+                if Seams[i, j] != 0:
+                    P1.setRow(l_count - 1, V.row(F[i, j]))
+                    P2.setRow(l_count - 1, V.row(F[i, (j + 1) % 3]))
+                    l_count -= 1
 
         viewer.data.add_edges(P1, P2, igl.eigen.MatrixXd([[1, 0, 0]]))
 
         # Plot the singularities as colored dots (red for negative, blue for positive)
-        for i in range(0,singularityIndex.size()):
-            if singularityIndex[i] < 2 and singularityIndex[i] > 0:
-                viewer.data.add_points(V.row(i),igl.eigen.MatrixXd([[1,0,0]]))
+        for i in range(0, singularityIndex.size()):
+            if 2 > singularityIndex[i] > 0:
+                viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
             elif singularityIndex[i] > 2:
-                viewer.data.add_points(V.row(i),igl.eigen.MatrixXd([[1,0,0]]))
+                viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
 
     if key == ord('5'):
         # Singularities and cuts, original field
         # Singularities and cuts
         viewer.data.set_mesh(V, F)
-        viewer.data.add_edges(B - global_scale*X1_combed if extend_arrows else B, B + global_scale*X1_combed ,igl.eigen.MatrixXd([[1,0,0]]))
-        viewer.data.add_edges(B - global_scale*X2_combed if extend_arrows else B, B + global_scale*X2_combed ,igl.eigen.MatrixXd([[0,0,1]]))
+        viewer.data.add_edges(B - global_scale * X1_combed if extend_arrows else B, B + global_scale * X1_combed,
+                              igl.eigen.MatrixXd([[1, 0, 0]]))
+        viewer.data.add_edges(B - global_scale * X2_combed if extend_arrows else B, B + global_scale * X2_combed,
+                              igl.eigen.MatrixXd([[0, 0, 1]]))
 
         # Plot cuts
         l_count = Seams.sum()
 
-        P1 = igl.eigen.MatrixXd(l_count,3)
-        P2 = igl.eigen.MatrixXd(l_count,3)
+        P1 = igl.eigen.MatrixXd(l_count, 3)
+        P2 = igl.eigen.MatrixXd(l_count, 3)
 
         for i in range(0, Seams.rows()):
             for j in range(0, Seams.cols()):
-                if Seams[i,j] != 0:
-                    P1.setRow(l_count-1,V.row(F[i,j]))
-                    P2.setRow(l_count-1,V.row(F[i,(j+1)%3]))
-                    l_count = l_count - 1
+                if Seams[i, j] != 0:
+                    P1.setRow(l_count - 1, V.row(F[i, j]))
+                    P2.setRow(l_count - 1, V.row(F[i, (j + 1) % 3]))
+                    l_count -= 1
 
         viewer.data.add_edges(P1, P2, igl.eigen.MatrixXd([[1, 0, 0]]))
 
         # Plot the singularities as colored dots (red for negative, blue for positive)
-        for i in range(0,singularityIndex.size()):
-            if singularityIndex[i] < 2 and singularityIndex[i] > 0:
-                viewer.data.add_points(V.row(i),igl.eigen.MatrixXd([[1,0,0]]))
+        for i in range(0, singularityIndex.size()):
+            if 2 > singularityIndex[i] > 0:
+                viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[1, 0, 0]]))
             elif singularityIndex[i] > 2:
-                viewer.data.add_points(V.row(i),igl.eigen.MatrixXd([[0,1,0]]))
+                viewer.data.add_points(V.row(i), igl.eigen.MatrixXd([[0, 1, 0]]))
 
     if key == ord('6'):
         # Global parametrization UV
@@ -167,49 +183,50 @@ def key_down(viewer, key, modifier):
     if key == ord('7'):
         # Global parametrization in 3D
         viewer.data.set_mesh(V, F)
-        viewer.data.set_uv(UV,FUV)
+        viewer.data.set_uv(UV, FUV)
         viewer.core.show_texture = True
 
     if key == ord('8'):
         # Global parametrization in 3D with seams
         viewer.data.set_mesh(V, F)
-        viewer.data.set_uv(UV_seams,FUV_seams)
+        viewer.data.set_uv(UV_seams, FUV_seams)
         viewer.core.show_texture = True
 
-    viewer.data.set_colors(igl.eigen.MatrixXd([[1,1,1]]))
+    viewer.data.set_colors(igl.eigen.MatrixXd([[1, 1, 1]]))
 
     viewer.data.set_texture(texture_R, texture_B, texture_G)
 
-    viewer.core.align_camera_center(viewer.data.V,viewer.data.F)
+    viewer.core.align_camera_center(viewer.data.V, viewer.data.F)
 
     return False
 
+
 # Load a mesh in OFF format
-igl.readOFF("../../tutorial/shared/3holes.off", V, F)
+igl.readOFF(TUTORIAL_SHARED_PATH + "3holes.off", V, F)
 
 # Compute face barycenters
 igl.barycenter(V, F, B)
 
 # Compute scale for visualizing fields
-global_scale =  .5*igl.avg_edge_length(V, F)
+global_scale = .5 * igl.avg_edge_length(V, F)
 
 # Contrain one face
-b  = igl.eigen.MatrixXi([[0]])
-bc = igl.eigen.MatrixXd([[1,0,0]])
+b = igl.eigen.MatrixXi([[0]])
+bc = igl.eigen.MatrixXd([[1, 0, 0]])
 
 # Create a smooth 4-RoSy field
 S = igl.eigen.MatrixXd()
 
-igl.comiso.nrosy(V,F,b,bc,igl.eigen.MatrixXi(),igl.eigen.MatrixXd(),igl.eigen.MatrixXd(),4,0.5,X1,S)
+igl.comiso.nrosy(V, F, b, bc, igl.eigen.MatrixXi(), igl.eigen.MatrixXd(), igl.eigen.MatrixXd(), 4, 0.5, X1, S)
 
 # Find the the orthogonal vector
 B1 = igl.eigen.MatrixXd()
 B2 = igl.eigen.MatrixXd()
 B3 = igl.eigen.MatrixXd()
 
-igl.local_basis(V,F,B1,B2,B3)
+igl.local_basis(V, F, B1, B2, B3)
 
-X2 = igl.rotate_vectors(X1, igl.eigen.MatrixXd.Constant(1,1,pi/2), B1, B2)
+X2 = igl.rotate_vectors(X1, igl.eigen.MatrixXd.Constant(1, 1, pi / 2), B1, B2)
 
 gradient_size = 50
 iterations = 0
@@ -226,7 +243,7 @@ igl.comb_cross_field(V, F, BIS1, BIS2, BIS1_combed, BIS2_combed)
 igl.cross_field_missmatch(V, F, BIS1_combed, BIS2_combed, True, MMatch)
 
 # Find the singularities
-igl.find_cross_field_singularities(V, F, MMatch, isSingularity, singularityIndex);
+igl.find_cross_field_singularities(V, F, MMatch, isSingularity, singularityIndex)
 
 # Cut the mesh, duplicating all vertices on the seams
 igl.cut_mesh_from_singularities(V, F, MMatch, Seams)
@@ -235,39 +252,12 @@ igl.cut_mesh_from_singularities(V, F, MMatch, Seams)
 igl.comb_frame_field(V, F, X1, X2, BIS1_combed, BIS2_combed, X1_combed, X2_combed)
 
 # Global parametrization
-igl.comiso.miq(V,
-           F,
-           X1_combed,
-           X2_combed,
-           MMatch,
-           isSingularity,
-           Seams,
-           UV,
-           FUV,
-           gradient_size,
-           stiffness,
-           direct_round,
-           iterations,
-           5,
-           True,
-           True);
+igl.comiso.miq(V, F, X1_combed, X2_combed, MMatch, isSingularity, Seams, UV, FUV, gradient_size, stiffness,
+               direct_round, iterations, 5, True, True)
 
 # Global parametrization (with seams, only for demonstration)
-igl.comiso.miq(V,
-         F,
-         X1_combed,
-         X2_combed,
-         MMatch,
-         isSingularity,
-         Seams,
-         UV_seams,
-         FUV_seams,
-         gradient_size,
-         stiffness,
-         direct_round,
-         iterations,
-         5,
-         False);
+igl.comiso.miq(V, F, X1_combed, X2_combed, MMatch, isSingularity, Seams, UV_seams, FUV_seams, gradient_size,
+               stiffness, direct_round, iterations, 5, False)
 
 # Plot the mesh
 viewer = igl.viewer.Viewer()
@@ -276,7 +266,7 @@ viewer = igl.viewer.Viewer()
 (texture_R, texture_G, texture_B) = line_texture()
 
 # Plot the original mesh with a texture parametrization
-key_down(viewer,ord('7'),0)
+key_down(viewer, ord('7'), 0)
 
 # Launch the viewer
 viewer.callback_key_down = key_down

+ 0 - 3
python/tutorial/509_Planarization.py

@@ -1,6 +1,4 @@
 import sys, os
-import random
-from math import cos, sin, pi
 
 # Add the igl library to the modules search path
 sys.path.insert(0, os.getcwd() + "/../")
@@ -12,7 +10,6 @@ dependencies = ["viewer"]
 check_dependencies(dependencies)
 
 
-
 viewer = igl.viewer.Viewer()
 
 # Quad mesh generated from conjugate field

+ 1 - 0
python/tutorial/604_Triangle.py

@@ -9,6 +9,7 @@ from shared import check_dependencies
 dependencies = ["triangle", "viewer"]
 check_dependencies(dependencies)
 
+
 # Input polygon
 V = igl.eigen.MatrixXd([[-1, -1], [1, -1], [1, 1], [-1, 1], [-2, -2], [2, -2], [2, 2], [-2, 2]])
 E = igl.eigen.MatrixXi([[0, 1], [1, 2], [2, 3], [3, 0], [4, 5], [5, 6], [6,7], [7,4]])

+ 0 - 1
python/tutorial/606_AmbientOcclusion.py

@@ -1,5 +1,4 @@
 import sys, os
-import math
 
 # Add the igl library to the modules search path
 sys.path.insert(0, os.getcwd() + "/../")

+ 1 - 5
python/tutorial/704_SignedDistance.py

@@ -5,16 +5,12 @@ import math
 sys.path.insert(0, os.getcwd() + "/../")
 import pyigl as igl
 
-from iglhelpers import e2p
 from shared import TUTORIAL_SHARED_PATH, check_dependencies
 
 dependencies = ["viewer"]
 check_dependencies(dependencies)
 
 
-
-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()
@@ -133,7 +129,7 @@ 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);
+update_visualization(viewer)
 viewer.callback_key_down = key_down
 viewer.core.show_lines = False
 viewer.launch()