Merge branch 'python_bindings' of https://github.com/s-koch/libigl
# Conflicts: # python/CMakeLists.txt
This commit is contained in:
Executable
+112
@@ -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()
|
||||
Executable
+94
@@ -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()
|
||||
Executable
+78
@@ -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()
|
||||
Executable
+83
@@ -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()
|
||||
@@ -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]))
|
||||
|
||||
Reference in New Issue
Block a user