Merge branch 'python_bindings' of https://github.com/s-koch/libigl

# Conflicts:
#	python/CMakeLists.txt
This commit is contained in:
Daniele Panozzo
2016-07-06 18:19:51 -04:00
26 changed files with 868 additions and 31 deletions
+112
View File
@@ -0,0 +1,112 @@
import sys, os
# Add the igl library to the modules search path
sys.path.insert(0, os.getcwd() + "/../")
import pyigl as igl
from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
dependencies = ["viewer"]
check_dependencies(dependencies)
def append_mesh(C_vis, F_vis, V_vis, V, F, color):
F_vis.conservativeResize(F_vis.rows() + F.rows(), 3)
F_vis.setBottomRows(F.rows(), F + V_vis.rows())
V_vis.conservativeResize(V_vis.rows() + V.rows(), 3)
V_vis.setBottomRows(V.rows(), V)
C_vis.conservativeResize(C_vis.rows() + F.rows(), 3)
colorM = igl.eigen.MatrixXd(F.rows(), C_vis.cols())
colorM.rowwiseSet(color)
C_vis.setBottomRows(F.rows(), colorM)
def update(viewer):
global V, F, T, W, slice_z, overlay
plane = igl.eigen.MatrixXd([0, 0, 1, -((1 - slice_z) * V.col(2).minCoeff() + slice_z * V.col(2).maxCoeff())])
V_vis = igl.eigen.MatrixXd()
F_vis = igl.eigen.MatrixXi()
J = igl.eigen.MatrixXi()
bary = igl.eigen.SparseMatrixd()
igl.slice_tets(V, T, plane, V_vis, F_vis, J, bary)
W_vis = igl.eigen.MatrixXd()
igl.slice(W, J, W_vis)
C_vis = igl.eigen.MatrixXd()
igl.parula(W_vis, False, C_vis)
if overlay == 1: # OVERLAY_INPUT
append_mesh(C_vis, F_vis, V_vis, V, F, igl.eigen.MatrixXd([[1., 0.894, 0.227]]))
elif overlay == 2: # OVERLAY_OUTPUT
append_mesh(C_vis, F_vis, V_vis, V, F, igl.eigen.MatrixXd([[0.8, 0.8, 0.8]]))
viewer.data.clear()
viewer.data.set_mesh(V_vis, F_vis)
viewer.data.set_colors(C_vis)
viewer.data.set_face_based(True)
def key_down(viewer, key, modifier):
global overlay, slice_z
if key == ord(' '):
overlay = (overlay + 1) % 3
elif key == ord('.'):
slice_z = min(slice_z + 0.01, 0.99)
elif key == ord(','):
slice_z = max(slice_z - 0.01, 0.01)
update(viewer)
return False
if __name__ == "__main__":
keys = {"space": "toggle showing input mesh, output mesh or slice through tet-mesh of convex hull",
". / ,": "push back/pull forward slicing plane"}
print_usage(keys)
V = igl.eigen.MatrixXd()
BC = igl.eigen.MatrixXd()
W = igl.eigen.MatrixXd()
T = igl.eigen.MatrixXi()
F = igl.eigen.MatrixXi()
G = igl.eigen.MatrixXi()
slice_z = 0.5
overlay = 0
# Load mesh: (V,T) tet-mesh of convex hull, F contains facets of input
# surface mesh _after_ self-intersection resolution
igl.readMESH(TUTORIAL_SHARED_PATH + "big-sigcat.mesh", V, T, F)
# Compute barycenters of all tets
igl.barycenter(V, T, BC)
# Compute generalized winding number at all barycenters
print("Computing winding number over all %i tets..." % T.rows())
igl.winding_number(V, F, BC, W)
# Extract interior tets
Wt = sum(W > 0.5)
CT = igl.eigen.MatrixXi(Wt, 4)
k = 0
for t in range(T.rows()):
if W[t] > 0.5:
CT.setRow(k, T.row(t))
k += 1
# find bounary facets of interior tets
igl.boundary_facets(CT, G)
# boundary_facets seem to be reversed...
G = G.rowwiseReverse()
# normalize
W = (W - W.minCoeff()) / (W.maxCoeff() - W.minCoeff())
# Plot the generated mesh
viewer = igl.viewer.Viewer()
update(viewer)
viewer.callback_key_down = key_down
viewer.launch()
+94
View File
@@ -0,0 +1,94 @@
import sys, os
# Add the igl library to the modules search path
sys.path.insert(0, os.getcwd() + "/../")
import pyigl as igl
from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
dependencies = ["copyleft", "viewer"]
check_dependencies(dependencies)
def key_down(viewer, key, modifier):
if key == ord('1'):
viewer.data.clear()
viewer.data.set_mesh(V, F)
elif key == ord('2'):
viewer.data.clear()
viewer.data.set_mesh(SV, SF)
elif key == ord('3'):
viewer.data.clear()
viewer.data.set_mesh(BV, BF)
return True
if __name__ == "__main__":
keys = {"1": "show original mesh",
"2": "show marching cubes contour of signed distance",
"3": "show marching cubes contour of indicator function"}
print_usage(keys)
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
# Read in inputs as double precision floating point meshes
igl.read_triangle_mesh(TUTORIAL_SHARED_PATH + "armadillo.obj", V, F)
# number of vertices on the largest side
s = 50
Vmin = V.colwiseMinCoeff()
Vmax = V.colwiseMaxCoeff()
h = (Vmax - Vmin).maxCoeff() / s
res = (s * ((Vmax - Vmin) / (Vmax - Vmin).maxCoeff())).castint()
def lerp(res, Vmin, Vmax, di, d):
return Vmin[d] + di / (res[d] - 1) * (Vmax[d] - Vmin[d])
# create grid
print("Creating grid...")
GV = igl.eigen.MatrixXd(res[0] * res[1] * res[2], 3)
for zi in range(res[2]):
z = lerp(res, Vmin, Vmax, zi, 2)
for yi in range(res[1]):
y = lerp(res, Vmin, Vmax, yi, 1)
for xi in range(res[0]):
x = lerp(res, Vmin, Vmax, xi, 0)
GV.setRow(xi + res[0] * (yi + res[1] * zi), igl.eigen.MatrixXd([[x, y, z]]))
# compute values
print("Computing distances...")
S = igl.eigen.MatrixXd()
B = igl.eigen.MatrixXd()
I = igl.eigen.MatrixXi()
C = igl.eigen.MatrixXd()
N = igl.eigen.MatrixXd()
igl.signed_distance(GV, V, F, igl.SIGNED_DISTANCE_TYPE_PSEUDONORMAL, S, I, C, N)
# Convert distances to binary inside-outside data --> aliasing artifacts
B = S.copy()
for e in range(B.rows()):
if B[e] > 0:
B[e] = 1
else:
if B[e] < 0:
B[e] = -1
else:
B[e] = 0
print("Marching cubes...")
SV = igl.eigen.MatrixXd()
BV = igl.eigen.MatrixXd()
SF = igl.eigen.MatrixXi()
BF = igl.eigen.MatrixXi()
igl.copyleft.marching_cubes(S, GV, res[0], res[1], res[2], SV, SF)
igl.copyleft.marching_cubes(B, GV, res[0], res[1], res[2], BV, BF)
# Plot the generated mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(SV, SF)
viewer.callback_key_down = key_down
viewer.launch()
+78
View File
@@ -0,0 +1,78 @@
import sys, os
# Add the igl library to the modules search path
sys.path.insert(0, os.getcwd() + "/../")
import pyigl as igl
from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
dependencies = ["embree", "viewer"]
check_dependencies(dependencies)
def key_down(viewer, key, modifier):
global facetwise, is_showing_reoriented, FF
if key == ord('F') or key == ord('f'):
facetwise = (facetwise + 1) % 2
elif key == ord('S') or key == ord('s'):
scramble_colors()
elif key == ord(' '):
is_showing_reoriented = ~is_showing_reoriented
viewer.data.clear()
viewer.data.set_mesh(V, FF[facetwise] if is_showing_reoriented else F)
viewer.data.set_colors(RGBcolors[facetwise])
return True
def scramble_colors():
global C, viewer, RGBcolors
for p in range(2):
R = igl.eigen.MatrixXi()
igl.randperm(C[p].maxCoeff() + 1, R)
C[p] = igl.slice(R, igl.eigen.MatrixXi(C[p]))
HSV = igl.eigen.MatrixXd(C[p].rows(), 3)
HSV.setCol(0, 360.0 * C[p].castdouble() / C[p].maxCoeff())
HSVright = igl.eigen.MatrixXd(HSV.rows(), 2)
HSVright.setConstant(1.0)
HSV.setRightCols(2, HSVright)
igl.hsv_to_rgb(HSV, RGBcolors[p])
viewer.data.set_colors(RGBcolors[facetwise])
if __name__ == "__main__":
keys = {"space": "toggle between original and reoriented faces",
"F,f": "toggle between patchwise and facetwise reorientation",
"S,s": "scramble colors"}
print_usage(keys)
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
C = [igl.eigen.MatrixXi(), igl.eigen.MatrixXi()]
RGBcolors = [igl.eigen.MatrixXd(), igl.eigen.MatrixXd()]
FF = [igl.eigen.MatrixXi(), igl.eigen.MatrixXi()]
is_showing_reoriented = False
facetwise = 0
igl.read_triangle_mesh(TUTORIAL_SHARED_PATH + "truck.obj", V, F)
# Compute patches
for p in range(2):
I = igl.eigen.MatrixXi()
igl.embree.reorient_facets_raycast(V, F, F.rows() * 100, 10, p == 1, False, False, I, C[p])
# apply reorientation
FF[p].conservativeResize(F.rows(), F.cols())
for i in range(I.rows()):
if I[i]:
FF[p].setRow(i, F.row(i).rowwiseReverse())
else:
FF[p].setRow(i, F.row(i))
# Plot the generated mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, FF[facetwise] if is_showing_reoriented else F)
viewer.data.set_face_based(True)
scramble_colors()
viewer.callback_key_down = key_down
viewer.launch()
+83
View File
@@ -0,0 +1,83 @@
import sys, os
# Add the igl library to the modules search path
from math import pi, cos
sys.path.insert(0, os.getcwd() + "/../")
import pyigl as igl
from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
dependencies = ["copyleft", "viewer"]
check_dependencies(dependencies)
def key_down(viewer, key, modifier):
global show_swept_volume, SV, SF, V, F
if key == ord(' '):
show_swept_volume = not show_swept_volume
viewer.data.clear()
if show_swept_volume:
viewer.data.set_mesh(SV, SF)
viewer.data.uniform_colors(igl.eigen.MatrixXd([0.2, 0.2, 0.2]), igl.eigen.MatrixXd([1.0, 1.0, 1.0]), igl.eigen.MatrixXd([1.0, 1.0, 1.0])) # TODO replace with constants from cpp
else:
viewer.data.set_mesh(V, F)
viewer.core.is_animating = not show_swept_volume
viewer.data.set_face_based(True)
return True
def pre_draw(viewer):
global show_swept_volume, V
if not show_swept_volume:
T = transform(0.25 * igl.get_seconds())
VT = V * T.matrix().block(0, 0, 3, 3).transpose()
trans = T.matrix().block(0, 3, 3, 1).transpose()
Vtrans = igl.eigen.MatrixXd(VT.rows(), VT.cols())
Vtrans.rowwiseSet(trans)
VT += Vtrans
viewer.data.set_vertices(VT)
viewer.data.compute_normals()
return False
# Define a rigid motion
def transform(t):
T = igl.eigen.Affine3d()
T.setIdentity()
T.rotate(t * 2 * pi, igl.eigen.MatrixXd([0, 1, 0]))
T.translate(igl.eigen.MatrixXd([0, 0.125 * cos(2 * pi * t), 0]))
return T
if __name__ == "__main__":
keys = {"space": "toggle between transforming original mesh and swept volume"}
print_usage(keys)
V = igl.eigen.MatrixXd()
SV = igl.eigen.MatrixXd()
VT = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
SF = igl.eigen.MatrixXi()
show_swept_volume = False
grid_size = 50
time_steps = 200
isolevel = 1
igl.read_triangle_mesh(TUTORIAL_SHARED_PATH + "bunny.off", V, F)
print("Computing swept volume...")
igl.copyleft.swept_volume(V, F, transform, time_steps, grid_size, isolevel, SV, SF)
print("...finished.")
# Plot the generated mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.data.set_face_based(True)
viewer.core.is_animating = not show_swept_volume
viewer.callback_pre_draw = pre_draw
viewer.callback_key_down = key_down
viewer.launch()
@@ -5,19 +5,12 @@ sys.path.insert(0, os.getcwd() + "/../")
import pyigl as igl
from shared import TUTORIAL_SHARED_PATH, check_dependencies
from shared import TUTORIAL_SHARED_PATH, check_dependencies, print_usage
dependencies = ["viewer"]
check_dependencies(dependencies)
# Mesh with per-face color
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
C = igl.eigen.MatrixXd()
viewer = igl.viewer.Viewer()
def mouse_down(viewer, a, b):
bc = igl.eigen.MatrixXd()
@@ -27,6 +20,7 @@ def mouse_down(viewer, a, b):
hit = igl.unproject_onto_mesh(coord, viewer.core.view * viewer.core.model,
viewer.core.proj, viewer.core.viewport, V, F, fid, bc)
if hit:
# paint hit red
C.setRow(fid[0, 0], igl.eigen.MatrixXd([[1, 0, 0]]))
viewer.data.set_colors(C)
return True
@@ -34,16 +28,25 @@ def mouse_down(viewer, a, b):
return False
print("Usage: [LeftMouseClick] to select a face")
if __name__ == "__main__":
keys = {"click": "Pick face on shape"}
print_usage(keys)
# Load a mesh in OFF format
igl.readOFF(TUTORIAL_SHARED_PATH + "fertility.off", V, F)
# Mesh with per-face color
V = igl.eigen.MatrixXd()
F = igl.eigen.MatrixXi()
C = igl.eigen.MatrixXd()
# Initialize white
C.setConstant(F.rows(), 3, 1.0)
# Load a mesh in OFF format
igl.readOFF(TUTORIAL_SHARED_PATH + "fertility.off", V, F)
viewer.data.set_mesh(V, F)
viewer.data.set_colors(C)
viewer.core.show_lines = False
viewer.callback_mouse_down = mouse_down
viewer.launch()
# Initialize white
C.setConstant(F.rows(), 3, 1.0)
# Show mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.data.set_colors(C)
viewer.core.show_lines = False
viewer.callback_mouse_down = mouse_down
viewer.launch()
+6
View File
@@ -14,3 +14,9 @@ def check_dependencies(deps):
if not all_available:
sys.exit(-1)
def print_usage(key_dict):
print("Usage:")
for k in key_dict.keys():
print("%s : %s" %(k, key_dict[k]))