205_Laplacian.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. from __future__ import print_function
  2. # Add the igl library to the modules search path
  3. import sys, os
  4. sys.path.insert(0, os.getcwd() + "/../")
  5. import pyigl as igl
  6. import math
  7. global V
  8. global U
  9. global F
  10. global L
  11. V = igl.eigen.MatrixXd()
  12. U = igl.eigen.MatrixXd()
  13. F = igl.eigen.MatrixXi()
  14. L = igl.eigen.SparseMatrixd()
  15. viewer = igl.viewer.Viewer()
  16. # Load a mesh in OFF format
  17. igl.readOFF("../../tutorial/shared/cow.off", V, F)
  18. # Compute Laplace-Beltrami operator: #V by #V
  19. igl.cotmatrix(V,F,L)
  20. # Alternative construction of same Laplacian
  21. G = igl.eigen.SparseMatrixd()
  22. K = igl.eigen.SparseMatrixd()
  23. # Gradient/Divergence
  24. igl.grad(V,F,G);
  25. # Diagonal per-triangle "mass matrix"
  26. dblA = igl.eigen.MatrixXd()
  27. igl.doublearea(V,F,dblA)
  28. # Place areas along diagonal #dim times
  29. T = (dblA.replicate(3,1)*0.5).asDiagonal() * 1
  30. # Laplacian K built as discrete divergence of gradient or equivalently
  31. # discrete Dirichelet energy Hessian
  32. temp = -G.transpose()
  33. K = -G.transpose() * T * G
  34. print("|K-L|: ",(K-L).norm())
  35. def key_pressed(viewer, key, modifier):
  36. global V
  37. global U
  38. global F
  39. global L
  40. if key == ord('r') or key == ord('R'):
  41. U = V;
  42. elif key == ord(' '):
  43. # Recompute just mass matrix on each step
  44. M = igl.eigen.SparseMatrixd()
  45. igl.massmatrix(U,F,igl.MASSMATRIX_TYPE_BARYCENTRIC,M);
  46. # Solve (M-delta*L) U = M*U
  47. S = (M - 0.001*L)
  48. solver = igl.eigen.SimplicialLLTsparse(S)
  49. U = solver.solve(M*U)
  50. # Compute centroid and subtract (also important for numerics)
  51. dblA = igl.eigen.MatrixXd()
  52. igl.doublearea(U,F,dblA)
  53. print(dblA.sum())
  54. area = 0.5*dblA.sum()
  55. BC = igl.eigen.MatrixXd()
  56. igl.barycenter(U,F,BC)
  57. centroid = igl.eigen.MatrixXd([[0.0,0.0,0.0]])
  58. for i in range(0,BC.rows()):
  59. centroid += 0.5*dblA[i,0]/area*BC.row(i)
  60. U -= centroid.replicate(U.rows(),1)
  61. # Normalize to unit surface area (important for numerics)
  62. U = U / math.sqrt(area)
  63. else:
  64. return False
  65. # Send new positions, update normals, recenter
  66. viewer.data.set_vertices(U)
  67. viewer.data.compute_normals()
  68. viewer.core.align_camera_center(U,F)
  69. return True
  70. # Use original normals as pseudo-colors
  71. N = igl.eigen.MatrixXd()
  72. igl.per_vertex_normals(V,F,N)
  73. C = N.rowwiseNormalized()*0.5+0.5;
  74. # Initialize smoothing with base mesh
  75. U = V
  76. viewer.data.set_mesh(U, F)
  77. viewer.data.set_colors(C)
  78. viewer.callback_key_pressed = key_pressed
  79. print("Press [space] to smooth.")
  80. print("Press [r] to reset.")
  81. viewer.launch()