moved python tutorials in a folder, doing a pass to make them python 3 compatible

This commit is contained in:
Daniele Panozzo
2015-10-05 15:30:39 +02:00
parent 5e7a2ae3da
commit 3ae8d0c1a9
27 changed files with 117 additions and 30 deletions
+48
View File
@@ -0,0 +1,48 @@
from iglhelpers import *
############# Dense Matrix Types #############
# 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')
# 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.
dense_matrix_eigen = p2e(dense_matrix)
# The Eigen wrappers allows you to do operations directly on this matrix,
# without having to convert back to numpy
dense_matrix_eigen_2 = dense_matrix_eigen * dense_matrix_eigen
# You can also inspect the data without converting it ...
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")
# To convert it back to a numpy array, use the helper function e2p
dense_matrix_2 = e2p(dense_matrix_eigen_2)
print("Numpy Array: \n", dense_matrix_2, "\n", sep='')
############# Sparse Matrix Types #############
# Sparse matrices are handled in a very similar way
# 2 types are supported by the wrappers: float64 and int64
sparse_matrix = sparse.rand(10, 10, 0.1)
# To convert to the eigen forma use p2e
sparse_matrix_eigen = p2e(sparse_matrix)
# They can directly be used plotted or used in computations
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='')
+18
View File
@@ -0,0 +1,18 @@
from __future__ import print_function
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
# Load a mesh in OFF format
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
igl.readOFF("../../tutorial/shared/cube.off", V, F)
# Print the vertices and faces matrices
print("Vertices: \n", V, sep='')
print("Faces: \n", F, sep='')
# Save the mesh in OBJ format
igl.writeOBJ("cube.obj",V,F)
+15
View File
@@ -0,0 +1,15 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
# Load a mesh in OFF format
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
igl.readOFF("../../tutorial/shared/beetle.off", V, F)
# Plot the mesh
viewer = igl.viewer.Viewer();
viewer.data.set_mesh(V, F);
viewer.launch();
+24
View File
@@ -0,0 +1,24 @@
import igl
import tcpviewer
import time
# Load a mesh in OFF format
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
time1 = time.time()
# igl.read_triangle_mesh("../tutorial/shared/armadillo.obj", V, F)
igl.readOFF("../tutorial/shared/beetle.off", V, F)
time2 = time.time()
print('Loading mesh (%d vertices) %0.3f ms' % (V.rows(),(time2-time1)*1000.0))
# Plot the mesh
viewer = tcpviewer.TCPViewer()
viewer.data.set_mesh(V, F)
viewer.core.align_camera_center(V,F)
viewer.launch()
time3 = time.time()
print('Sending to TCP viewer took %0.3f ms' % ((time3-time2)*1000.0))
+44
View File
@@ -0,0 +1,44 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V1 = igl.eigen.MatrixXd()
F1 = igl.eigen.MatrixXi()
V2 = igl.eigen.MatrixXd()
F2 = igl.eigen.MatrixXi()
def key_pressed(viewer, key, modifier):
print("Key: ", chr(key))
if key == ord('1'):
# # Clear should be called before drawing the mesh
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);
elif key == ord('2'):
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);
print("1 Switch to bump mesh")
print("2 Switch to fertility mesh")
viewer = igl.viewer.Viewer()
# Register a keyboard callback that allows to switch between
# the two loaded meshes
viewer.callback_key_pressed = key_pressed
viewer.data.set_mesh(V1, F1)
viewer.launch()
+28
View File
@@ -0,0 +1,28 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
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)
# 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);
# Compute per-vertex colors
igl.jet(Z,True,C)
# Add per-vertex colors
viewer.data.set_colors(C)
# Launch the viewer
viewer.launch()
+71
View File
@@ -0,0 +1,71 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
# Load a mesh in OFF format
igl.readOFF("../../tutorial/shared/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]]
]
)
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]
]
)
# Plot the mesh
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]]))
# Plot the edges of the bounding box
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]]))
# 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)
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();
+51
View File
@@ -0,0 +1,51 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
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
elif key == ord('2'):
viewer.data.set_normals(N_vertices)
return True
elif key == ord('3'):
viewer.data.set_normals(N_corners)
return True
return False
# Load a mesh in OFF format
igl.readOFF("../../tutorial/shared/fandisk.off", V, F);
# Compute per-face normals
N_faces = igl.eigen.MatrixXd()
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)
# Compute per-corner normals, |dihedral angle| > 20 degrees --> crease
N_corners = igl.eigen.MatrixXd()
igl.per_corner_normals(V,F,20,N_corners)
# Plot the mesh
viewer = igl.viewer.Viewer()
viewer.callback_key_pressed = key_pressed
viewer.core.show_lines = False
viewer.data.set_mesh(V, F)
viewer.data.set_normals(N_faces)
print("Press '1' for per-face normals.")
print("Press '2' for per-vertex normals.")
print("Press '3' for per-corner normals.")
viewer.launch()
+24
View File
@@ -0,0 +1,24 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
# Load mesh
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
igl.readOFF("../../tutorial/shared/bumpy.off",V,F);
# Compute Gaussian curvature
K = igl.eigen.MatrixXd();
igl.gaussian_curvature(V,F,K);
# Compute pseudocolor
C = igl.eigen.MatrixXd();
igl.jet(K,True,C);
# Plot the mesh with pseudocolors
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.data.set_colors(C)
viewer.launch()
+65
View File
@@ -0,0 +1,65 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd();
F = igl.eigen.MatrixXi();
igl.read_triangle_mesh("../../tutorial/shared/fertility.off", V, F);
# Alternative discrete mean curvature
HN = igl.eigen.MatrixXd()
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)
# Laplace-Beltrami of position
HN = -Minv*(L*V)
# Extract magnitude as mean curvature
H = HN.rowwiseNorm()
# Compute curvature directions via quadric fitting
PD1 = igl.eigen.MatrixXd()
PD2 = igl.eigen.MatrixXd()
PV1 = igl.eigen.MatrixXd()
PV2 = igl.eigen.MatrixXd()
igl.principal_curvature(V,F,PD1,PD2,PV1,PV2)
# Mean curvature
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)
viewer.data.set_colors(C)
# Average edge length for sizing
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]])
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)
# Hide wireframe
viewer.core.show_lines = False
viewer.launch();
+54
View File
@@ -0,0 +1,54 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
# Load a mesh in OFF format
igl.readOFF("../../tutorial/shared/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)
U = U.col(0)
# Compute gradient operator: #F*3 by #V
G = igl.eigen.SparseMatrixd()
igl.grad(V,F,G)
# Compute gradient of U
GU = (G*U).MapMatrix(F.rows(),3)
# Compute gradient magnitude
GU_mag = GU.rowwiseNorm()
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
# Compute pseudocolor for original function
C = igl.eigen.MatrixXd()
igl.jet(U,True,C)
# Or for gradient magnitude
# igl.jet(GU_mag,True,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()
# Draw a black segment in direction of gradient at face barycenters
BC = igl.eigen.MatrixXd()
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)
# Hide wireframe
viewer.core.show_lines = False
viewer.launch()
+113
View File
@@ -0,0 +1,113 @@
from __future__ import print_function
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
import math
global V
global U
global F
global L
V = igl.eigen.MatrixXd()
U = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
L = igl.eigen.SparseMatrixd()
viewer = igl.viewer.Viewer()
# Load a mesh in OFF format
igl.readOFF("../../tutorial/shared/cow.off", V, F)
# Compute Laplace-Beltrami operator: #V by #V
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);
# Diagonal per-triangle "mass matrix"
dblA = igl.eigen.MatrixXd()
igl.doublearea(V,F,dblA)
# Place areas along diagonal #dim times
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())
def key_pressed(viewer, key, modifier):
global V
global U
global F
global L
if key == ord('r') or key == ord('R'):
U = V;
elif key == ord(' '):
# Recompute just mass matrix on each step
M = igl.eigen.SparseMatrixd()
igl.massmatrix(U,F,igl.MASSMATRIX_TYPE_BARYCENTRIC,M);
# Solve (M-delta*L) U = M*U
S = (M - 0.001*L)
solver = igl.eigen.SimplicialLLTsparse(S)
U = solver.solve(M*U)
# Compute centroid and subtract (also important for numerics)
dblA = igl.eigen.MatrixXd()
igl.doublearea(U,F,dblA)
print(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]])
for i in range(0,BC.rows()):
centroid += 0.5*dblA[i,0]/area*BC.row(i)
U -= centroid.replicate(U.rows(),1)
# Normalize to unit surface area (important for numerics)
U = U / math.sqrt(area)
else:
return False
# Send new positions, update normals, recenter
viewer.data.set_vertices(U)
viewer.data.compute_normals()
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;
# Initialize smoothing with base mesh
U = V
viewer.data.set_mesh(U, F)
viewer.data.set_colors(C)
viewer.callback_key_pressed = key_pressed
print("Press [space] to smooth.")
print("Press [r] to reset.")
viewer.launch()
+39
View File
@@ -0,0 +1,39 @@
from __future__ import print_function
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
igl.readOFF("../../tutorial/shared/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);
# 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)
# K = I(J);
K = igl.eigen.MatrixXi()
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)
# Red for each in K
R = igl.eigen.MatrixXd([[1.0,0.3,0.3]]).replicate(K.rows(),1)
# C(K,:) = R
igl.slice_into(R,K,1,C)
# Plot the mesh with pseudocolors
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.data.set_colors(C)
viewer.launch()
+38
View File
@@ -0,0 +1,38 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
igl.readOFF("../../tutorial/shared/decimated-knight.off",V,F)
# Sort barycenters lexicographically
BC = igl.eigen.MatrixXd()
sorted_BC = igl.eigen.MatrixXd()
igl.barycenter(V,F,BC);
I = igl.eigen.MatrixXi()
J = igl.eigen.MatrixXi()
# sorted_BC = BC(I,:)
igl.sortrows(BC,True,sorted_BC,I)
# Get sorted "place" from sorted indices
J.resize(I.rows(),1)
# J(I) = 1:numel(I)
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)
# Plot the mesh with pseudocolors
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.data.set_colors(C)
viewer.launch()
+77
View File
@@ -0,0 +1,77 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
igl.readOFF("../../tutorial/shared/camelhead.off",V,F)
# Find boundary edges
E = igl.eigen.MatrixXi()
igl.boundary_facets(F,E);
# Find boundary vertices
b = igl.eigen.MatrixXi()
IA = igl.eigen.MatrixXi()
IC = igl.eigen.MatrixXi()
igl.unique(E,b,IA,IC);
# List of all vertex indices
vall = igl.eigen.MatrixXi()
vin = igl.eigen.MatrixXi()
igl.coloni(0,V.rows()-1,vall)
# List of interior indices
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)
# Dirichlet boundary conditions from z-coordinate
bc = igl.eigen.MatrixXd()
Z = V.col(2)
igl.slice(Z,b,bc)
# Solve PDE
solver = igl.eigen.SimplicialLLTsparse(-L_in_in)
Z_in = solver.solve(L_in_b*bc)
# slice into solution
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);
# 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)
# Pseudo-color based on solution
C = igl.eigen.MatrixXd()
igl.jet(Z,True,C)
# Plot the mesh with pseudocolors
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.core.show_lines = False
viewer.data.set_colors(C)
viewer.launch()
@@ -0,0 +1,100 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
igl.readOFF("../../tutorial/shared/cheburashka.off",V,F)
# Two fixed points
# Left hand, left foot
b = igl.eigen.MatrixXi([[4331],[5957]])
bc = igl.eigen.MatrixXd([[1],[-1]])
# Construct Laplacian and mass matrix
L = igl.eigen.SparseMatrixd()
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)
# Bi-Laplacian
Q = L * (Minv * L);
# Zero linear term
B = igl.eigen.MatrixXd.Zero(V.rows(),1);
Z = igl.eigen.MatrixXd()
Z_const = igl.eigen.MatrixXd()
# Alternative, short hand
mqwf = igl.min_quad_with_fixed_data()
# Empty constraints
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)
# Constraint forcing difference of two points to be 0
Aeq = igl.eigen.SparseMatrixd(1,V.rows())
# Right hand, right foot
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)
# 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())
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()
viewer.data.set_mesh(V, F)
viewer.core.show_lines = False
viewer.data.set_colors(C)
def key_down(viewer,key,mode):
if key == ord(' '):
global toggle
global C
global C_const
if toggle:
viewer.data.set_colors(C)
else:
viewer.data.set_colors(C_const)
toggle = not toggle;
return True
return False
viewer.callback_key_down = key_down
print("Press [space] to toggle between unconstrained and constrained.")
viewer.launch()
@@ -0,0 +1,90 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
b = igl.eigen.MatrixXi()
B = igl.eigen.MatrixXd()
bc = igl.eigen.MatrixXd()
lx = igl.eigen.MatrixXd()
ux = igl.eigen.MatrixXd()
Beq = igl.eigen.MatrixXd()
Bieq = igl.eigen.MatrixXd()
Z = igl.eigen.MatrixXd()
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
params = igl.active_set_params()
params.max_iter = 8
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)
viewer.data.set_colors(C)
def key_down(viewer, key, mod):
global Beq,solve
if key == ord('.'):
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
elif key == ord(' '):
solve(viewer)
return True
return False;
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
igl.readOFF("../../tutorial/shared/cheburashka.off",V,F)
# Plot the mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.core.show_lines = False
viewer.callback_key_down = key_down
# One fixed point on belly
b = igl.eigen.MatrixXi([[2556]])
bc = igl.eigen.MatrixXd([[1]])
# Construct Laplacian and mass matrix
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)
# Bi-Laplacian
Q = L.transpose() * (Minv * L)
# Zero linear term
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)
# Equality constraint constrain solution to sum to 1
Beq = igl.eigen.MatrixXd([[0.08]])
Aeq = M.diagonal().transpose().sparseView()
# (Empty inequality constraints)
solve(viewer)
print("Press '.' to increase scale and resolve.")
print("Press ',' to decrease scale and resolve.")
viewer.launch()
+60
View File
@@ -0,0 +1,60 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd()
U = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
c = 0
bbd = 1.0
twod = False
if not igl.read_triangle_mesh("../../tutorial/shared/beetle.off",V,F):
print("failed to load mesh")
twod = V.col(2).minCoeff() == V.col(2).maxCoeff()
bbd = (V.colwiseMaxCoeff() - V.colwiseMinCoeff()).norm()
L = igl.eigen.SparseMatrixd()
M = igl.eigen.SparseMatrixd()
igl.cotmatrix(V,F,L)
L = -L
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):
print("Eigs failed.")
U = (U-U.minCoeff())/(U.maxCoeff()-U.minCoeff());
viewer = igl.viewer.Viewer()
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)
C = igl.eigen.MatrixXd()
igl.parula(U.col(c),False,C)
c = (c+1)%U.cols()
if twod:
V.setcol(2,Z)
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.core.show_lines = False
viewer.launch()
+107
View File
@@ -0,0 +1,107 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
global bc_frac, bc_dir,deformation_field, V, U, V_bc, U_bc, F, b
bc_frac = 1.0
bc_dir = -0.03
deformation_field = False
V = igl.eigen.MatrixXd()
U = igl.eigen.MatrixXd()
V_bc = igl.eigen.MatrixXd()
U_bc = igl.eigen.MatrixXd()
# Z = 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
# 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)
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
else:
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
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;
return True
return False
igl.readOBJ("../../tutorial/shared/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)
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()
# Boundary conditions directly on deformed positions
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]))
if (S[b[bi]] == 0):
# Don't move handle 0
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]]))
else:
# Move other handles forward
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]])
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)
# Plot the mesh with pseudocolors
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(U, F)
viewer.core.show_lines = False
viewer.data.set_colors(C)
# viewer.core.trackball_angle = igl.eigen.Quaterniond(sqrt(2.0),0,sqrt(2.0),0)
# viewer.core.trackball_angle.normalize()
viewer.callback_pre_draw = pre_draw
viewer.callback_key_down = key_down
viewer.core.animation_max_fps = 30.0
print("Press [space] to toggle deformation.")
print("Press 'd' to toggle between biharmonic surface or displacements.")
viewer.launch()
+100
View File
@@ -0,0 +1,100 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
global z_max, z_dir, k, resolve, V, U, Z, F, b, bc
z_max = 1.0
z_dir = -0.03
k = 2
resolve = True
V = igl.eigen.MatrixXd()
U = igl.eigen.MatrixXd()
Z = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
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)
resolve = False
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)
return False
def key_down(viewer, key, mods):
global z_max, z_dir, k, resolve, V, U, Z, F, b, bc
if key == ord(' '):
viewer.core.is_animating = not viewer.core.is_animating
elif key == ord('.'):
k = k + 1
k = (4 if k>4 else k)
resolve = True
elif key == ord(','):
k = k - 1
k = (1 if k<1 else k)
resolve = True
return True
igl.readOBJ("../../tutorial/shared/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))]
b = igl.eigen.MatrixXi([[i for i in range(0,V.rows()) if (in_b[i])]]).transpose();
bc.resize(b.size(),1)
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]])
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)
# Plot the mesh with pseudocolors
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(U, F)
viewer.core.show_lines = False
viewer.data.set_colors(C)
# viewer.core.trackball_angle = igl.eigen.Quaterniond(0.81,-0.58,-0.03,-0.03)
# viewer.core.trackball_angle.normalize()
viewer.callback_pre_draw = pre_draw
viewer.callback_key_down = key_down
viewer.core.is_animating = True
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();
+93
View File
@@ -0,0 +1,93 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
from math import sin,cos,pi
sea_green = igl.eigen.MatrixXd([[70./255.,252./255.,167./255.]])
V = igl.eigen.MatrixXd()
U = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
S = igl.eigen.MatrixXd()
b = igl.eigen.MatrixXi()
mid = igl.eigen.MatrixXd()
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]))
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)
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)
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)
igl.arap_solve(bc,arap_data,U)
viewer.data.set_vertices(U)
viewer.data.compute_normals()
if viewer.core.is_animating:
anim_t += anim_t_dir
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)
U = igl.eigen.MatrixXd(V)
igl.readDMAT("../../tutorial/shared/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()
# Centroid
mid = 0.5*(V.colwiseMaxCoeff() + V.colwiseMinCoeff())
# Precomputation
arap_data.max_iter = 100
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]])
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)
# Plot the mesh with pseudocolors
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(U, F)
viewer.data.set_colors(C)
viewer.callback_pre_draw = pre_draw
viewer.callback_key_down = key_down
viewer.core.is_animating = True
viewer.core.animation_max_fps = 30.
print("Press [space] to toggle animation")
viewer.launch()
+53
View File
@@ -0,0 +1,53 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
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)
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.compute_normals()
return False
# Load a mesh in OFF format
igl.readOFF("../../tutorial/shared/camelhead.off", V, F)
# Find the open boundary
bnd = igl.eigen.MatrixXi()
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)
# Harmonic parametrization for the internal vertices
igl.harmonic(V,F,bnd,bnd_uv,1,V_uv)
# Scale UV to make the texture more clear
V_uv *= 5;
# Plot the mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.data.set_uv(V_uv)
viewer.callback_key_down = key_down
# Disable wireframe
viewer.core.show_lines = False
# Draw checkerboard texture
viewer.core.show_texture = True
# Launch the viewer
viewer.launch()
+54
View File
@@ -0,0 +1,54 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
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)
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.compute_normals()
return False
# Load a mesh in OFF format
igl.readOFF("../../tutorial/shared/camelhead.off", V, F);
# Fix two points on the boundary
bnd = igl.eigen.MatrixXi()
b = igl.eigen.MatrixXi(2,1)
igl.boundary_loop(F,bnd)
b[0] = bnd[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)
# Scale the uv
V_uv *= 5
# Plot the mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.data.set_uv(V_uv)
viewer.callback_key_down = key_down
# Disable wireframe
viewer.core.show_lines = False
# Draw checkerboard texture
viewer.core.show_texture = True
# Launch the viewer
viewer.launch()
+77
View File
@@ -0,0 +1,77 @@
# Add the igl library to the modules search path
import sys, os
sys.path.insert(0, os.getcwd() + "/../")
import igl
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
V_uv = igl.eigen.MatrixXd()
initial_guess = igl.eigen.MatrixXd()
show_uv = False
def key_down(viewer, key, modifier):
global show_uv, V_uv
if key == ord('1'):
show_uv = False
elif key == ord('2'):
show_uv = True
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)
else:
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)
# Compute the initial solution for ARAP (harmonic parametrization)
bnd = igl.eigen.MatrixXi()
igl.boundary_loop(F,bnd)
bnd_uv = igl.eigen.MatrixXd()
igl.map_vertices_to_circle(V,bnd,bnd_uv)
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);
# 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)
# Solve arap using the harmonic map as initial guess
V_uv = igl.eigen.MatrixXd(initial_guess) # important, make a copy of it!
igl.arap_solve(bc,arap_data,V_uv)
# Scale UV to make the texture more clear
V_uv *= 20
# Plot the mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.data.set_uv(V_uv)
viewer.callback_key_down = key_down
# Disable wireframe
viewer.core.show_lines = False
# Draw checkerboard texture
viewer.core.show_texture = True
# Launch the viewer
viewer.launch()
+108
View File
@@ -0,0 +1,108 @@
import igl
from math import atan2,pi,cos,sin
# Mesh
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
# Constrained faces id
b = igl.eigen.MatrixXi()
# Constrained faces representative vector
bc = igl.eigen.MatrixXd()
# Degree of the N-RoSy field
N = 4;
# Converts a representative vector per face in the full set of vectors that describe
# an N-RoSy field
def representative_to_nrosy(V, F, R, N, Y):
B1 = igl.eigen.MatrixXd()
B2 = igl.eigen.MatrixXd()
B3 = igl.eigen.MatrixXd()
igl.local_basis(V,F,B1,B2,B3)
Y.resize(F.rows()*N, 3)
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])
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))
# 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)
# Expand the representative vectors in the full vector set and plot them as lines
avg = igl.avg_edge_length(V, F)
Y = igl.eigen.MatrixXd()
representative_to_nrosy(V, F, PD1, N, Y)
B = igl.eigen.MatrixXd()
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))
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()):
if S[i] < -0.001:
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]]));
# Highlight in red the constrained faces
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'):
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)
return False
# Load a mesh in OFF format
igl.readOFF("../tutorial/shared/bumpy.off", V, F);
# Threshold faces with high anisotropy
b = igl.eigen.MatrixXi([[0]])
bc = igl.eigen.MatrixXd([[1,1,1]])
viewer = igl.viewer.Viewer()
# Interpolate the field and plot
key_down(viewer, ord('4'), 0)
# Plot the mesh
viewer.data.set_mesh(V, F)
viewer.callback_key_down = key_down
# Disable wireframe
viewer.core.show_lines = False
# Launch the viewer
viewer.launch()
+279
View File
@@ -0,0 +1,279 @@
import igl
from math import pi
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
# Face barycenters
B = igl.eigen.MatrixXd()
# Scale for visualizing the fields
global_scale = 1
extend_arrows = False;
# Cross field
X1 = igl.eigen.MatrixXd()
X2 = igl.eigen.MatrixXd()
# Bisector field
BIS1 = igl.eigen.MatrixXd()
BIS2 = igl.eigen.MatrixXd()
# Combed bisector
BIS1_combed = igl.eigen.MatrixXd()
BIS2_combed = igl.eigen.MatrixXd()
# Per-corner, integer mismatches
MMatch = igl.eigen.MatrixXi()
# Field singularities
isSingularity = igl.eigen.MatrixXi()
singularityIndex = igl.eigen.MatrixXi()
# Per corner seams
Seams = igl.eigen.MatrixXi()
# Combed field
X1_combed = igl.eigen.MatrixXd()
X2_combed = igl.eigen.MatrixXd()
# Global parametrization (with seams)
UV_seams = igl.eigen.MatrixXd()
FUV_seams = igl.eigen.MatrixXi()
# Global parametrization
UV = igl.eigen.MatrixXd()
FUV = igl.eigen.MatrixXi()
# Texture
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)
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(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
if key == ord('E'):
extend_arrows = not extend_arrows
if key < ord('1') or key > ord('8'):
return False;
viewer.data.clear()
viewer.core.show_lines = False
viewer.core.show_texture = False
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]]))
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]]))
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]]))
if key == ord('4'):
# Singularities and cuts
viewer.data.set_mesh(V, F)
# Plot cuts
l_count = Seams.sum()
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
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]]))
elif singularityIndex[i] > 2:
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]]))
# Plot cuts
l_count = Seams.sum()
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
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]]))
elif singularityIndex[i] > 2:
viewer.data.add_points(V.row(i),igl.eigen.MatrixXd([[0,1,0]]))
if key == ord('6'):
# Global parametrization UV
viewer.data.set_mesh(UV, FUV)
viewer.data.set_uv(UV)
viewer.core.show_lines = True
if key == ord('7'):
# Global parametrization in 3D
viewer.data.set_mesh(V, F)
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.core.show_texture = True
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)
return False
# Load a mesh in OFF format
igl.readOFF("../tutorial/shared/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)
# Contrain one face
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)
# 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)
X2 = igl.rotate_vectors(X1, igl.eigen.MatrixXd.Constant(1,1,pi/2), B1, B2)
gradient_size = 50
iterations = 0
stiffness = 5.0
direct_round = False
# Always work on the bisectors, it is more general
igl.compute_frame_field_bisectors(V, F, X1, X2, BIS1, BIS2)
# Comb the field, implicitly defining the seams
igl.comb_cross_field(V, F, BIS1, BIS2, BIS1_combed, BIS2_combed)
# Find the integer mismatches
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);
# Cut the mesh, duplicating all vertices on the seams
igl.cut_mesh_from_singularities(V, F, MMatch, Seams)
# Comb the frame-field accordingly
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);
# 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);
# Plot the mesh
viewer = igl.viewer.Viewer()
# Replace the standard texture with an integer shift invariant texture
(texture_R, texture_G, texture_B) = line_texture()
# Plot the original mesh with a texture parametrization
key_down(viewer,ord('7'),0)
# Launch the viewer
viewer.callback_key_down = key_down
viewer.launch()
+126
View File
@@ -0,0 +1,126 @@
import igl
import random
from math import cos,sin,pi
# Input mesh
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
# Per face bases
B1 = igl.eigen.MatrixXd()
B2 = igl.eigen.MatrixXd()
B3 = igl.eigen.MatrixXd()
# Face barycenters
B = igl.eigen.MatrixXd()
# Scale for visualizing the fields
global_scale = 1
# Random length factor
rand_factor = 5
samples = igl.eigen.MatrixXi()
def readSamples(fname):
samples = igl.eigen.MatrixXi()
numSamples = 0
fp = open(fname, 'r')
numSamples = int(fp.readline())
samples.resize(numSamples,1)
for i in range(0,numSamples):
samples[i] = int(fp.readline())
fp.close()
return samples
# Create a random set of tangent vectors
def random_constraints(b1, b2, n):
r = igl.eigen.MatrixXd(1,n*3)
for i in range(0,n):
a = random.random()*2*pi
s = 1 + random.random() * rand_factor
t = s * (cos(a) * b1 + sin(a) * b2)
r.setBlock(0,i*3,1,3,t)
return r
def key_down(viewer, key, modifier):
if key < ord('1') or key > ord('8'):
return False
viewer.data.lines.resize(0,9)
num = key - ord('0')
# Interpolate
print("Interpolating " + repr(num * 2) + "-PolyVector field")
b = igl.eigen.MatrixXi([[4550, 2321, 5413, 5350]]).transpose()
bc = igl.eigen.MatrixXd(b.size(),num*3)
for i in range(0,b.size()):
t = random_constraints(B1.row(b[i]),B2.row(b[i]),num)
bc.setRow(i,t)
# Interpolated PolyVector field
pvf = igl.eigen.MatrixXd()
igl.n_polyvector(V, F, b, bc, pvf)
# Highlight in red the constrained faces
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)
for n in range(0,num):
VF = igl.eigen.MatrixXd.Zero(F.rows(),3)
for i in range(0,b.size()):
VF.setRow(b[i],bc.block(i,n*3,1,3))
for i in range(0,samples.rows()):
VF.setRow(samples[i],pvf.block(samples[i],n*3,1,3))
c = VF.rowwiseNorm()
C2 = igl.eigen.MatrixXd()
igl.jet(c,1,1+rand_factor,C2)
viewer.data.add_edges(B - global_scale*VF, B + global_scale*VF , C2)
return False
# Load a mesh in OBJ format
igl.readOBJ("../tutorial/shared/lilium.obj", V, F)
samples = readSamples("../tutorial/shared/lilium.samples.0.2")
# Compute local basis for faces
igl.local_basis(V,F,B1,B2,B3)
# Compute face barycenters
igl.barycenter(V, F, B)
# Compute scale for visualizing fields
global_scale = 0.2*igl.avg_edge_length(V, F)
# Make the example deterministic
random.seed(0)
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.callback_key_down = key_down
viewer.core.show_lines = False
key_down(viewer,ord('2'),0)
viewer.launch()