test_sph_harm2.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. """
  2. Morph one shape into another using spherical harmonics package shtools.
  3. In this example we morph a sphere into a octahedron and vice-versa.
  4. """
  5. import numpy as np
  6. from vedo import settings, Plotter, Points, Sphere, cos, dataurl, mag, sin, Mesh
  7. try:
  8. import pyshtools
  9. print(__doc__)
  10. except ModuleNotFoundError:
  11. print("Please install pyshtools to run this example")
  12. print("Follow instructions at https://shtools.oca.eu/shtools")
  13. exit(0)
  14. ##########################################################
  15. N = 100 # number of sample points on the unit sphere
  16. lmax = 15 # maximum degree of the sph. harm. expansion
  17. rbias = 0.5 # subtract a constant average value
  18. x0 = [0, 0, 0] # set object at this position
  19. ##########################################################
  20. def makeGrid(shape, N):
  21. rmax = 2.0 # line length
  22. agrid, pts = [], []
  23. for th in np.linspace(0, np.pi, N, endpoint=True):
  24. lats = []
  25. for ph in np.linspace(0, 2 * np.pi, N, endpoint=True):
  26. p = np.array([sin(th) * cos(ph), sin(th) * sin(ph), cos(th)]) * rmax
  27. intersections = shape.intersect_with_line([0, 0, 0], p)
  28. if len(intersections):
  29. value = mag(intersections[0])
  30. lats.append(value - rbias)
  31. pts.append(intersections[0])
  32. else:
  33. lats.append(rmax - rbias)
  34. pts.append(p)
  35. agrid.append(lats)
  36. agrid = np.array(agrid)
  37. actor = Points(pts, c="k", alpha=0.4, r=1)
  38. return agrid, actor
  39. def morph(clm1, clm2, t, lmax):
  40. """Interpolate linearly the two sets of sph harm. coeeficients."""
  41. clm = (1 - t) * clm1 + t * clm2
  42. grid_reco = clm.expand(lmax=lmax) # cut "high frequency" components
  43. agrid_reco = grid_reco.to_array()
  44. pts = []
  45. for i, longs in enumerate(agrid_reco):
  46. ilat = grid_reco.lats()[i]
  47. for j, value in enumerate(longs):
  48. ilong = grid_reco.lons()[j]
  49. th = np.deg2rad(90 - ilat)
  50. ph = np.deg2rad(ilong)
  51. r = value + rbias
  52. p = np.array([sin(th) * cos(ph), sin(th) * sin(ph), cos(th)]) * r
  53. pts.append(p)
  54. return pts
  55. settings.use_depth_peeling = True
  56. plt = Plotter(shape=[2, 2], axes=3, interactive=0)
  57. shape1 = Sphere(alpha=0.2)
  58. shape2 = Mesh(dataurl + "icosahedron.vtk").normalize().linewidth(1)
  59. plt += shape2
  60. agrid1, actorpts1 = makeGrid(shape1, N)
  61. plt.at(0).show(shape1, actorpts1)
  62. agrid2, actorpts2 = makeGrid(shape2, N)
  63. plt.at(1).show(shape2, actorpts2)
  64. plt.camera.Zoom(1.2)
  65. clm1 = pyshtools.SHGrid.from_array(agrid1).expand()
  66. clm2 = pyshtools.SHGrid.from_array(agrid2).expand()
  67. # clm1.plot_spectrum2d() # plot the value of the sph harm. coefficients
  68. # clm2.plot_spectrum2d()
  69. for t in np.arange(0, 1, 0.005):
  70. act21 = Points(morph(clm2, clm1, t, lmax), c="r", r=4)
  71. act12 = Points(morph(clm1, clm2, t, lmax), c="g", r=4)
  72. plt.at(2).show(act21, resetcam=False)
  73. plt.at(3).show(act12)
  74. plt.azimuth(2)
  75. plt.interactive().close()