205_Laplacian.py 2.4 KB

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