moved python tutorials in a folder, doing a pass to make them python 3 compatible
This commit is contained in:
@@ -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='')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
Executable
+15
@@ -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();
|
||||
Executable
+24
@@ -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))
|
||||
Executable
+44
@@ -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()
|
||||
Executable
+28
@@ -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()
|
||||
Executable
+71
@@ -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();
|
||||
Executable
+51
@@ -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()
|
||||
@@ -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()
|
||||
Executable
+65
@@ -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();
|
||||
Executable
+54
@@ -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()
|
||||
Executable
+113
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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()
|
||||
Executable
+107
@@ -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
@@ -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();
|
||||
Executable
+93
@@ -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()
|
||||
Executable
+53
@@ -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()
|
||||
Executable
+54
@@ -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()
|
||||
Executable
+77
@@ -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()
|
||||
Executable
+108
@@ -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()
|
||||
Executable
+279
@@ -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()
|
||||
Executable
+126
@@ -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()
|
||||
Reference in New Issue
Block a user