plot_camera.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import pyglet.gl as pgl
  2. from sympy.plotting.pygletplot.plot_rotation import get_spherical_rotatation
  3. from sympy.plotting.pygletplot.util import get_model_matrix, model_to_screen, \
  4. screen_to_model, vec_subs
  5. class PlotCamera:
  6. min_dist = 0.05
  7. max_dist = 500.0
  8. min_ortho_dist = 100.0
  9. max_ortho_dist = 10000.0
  10. _default_dist = 6.0
  11. _default_ortho_dist = 600.0
  12. rot_presets = {
  13. 'xy': (0, 0, 0),
  14. 'xz': (-90, 0, 0),
  15. 'yz': (0, 90, 0),
  16. 'perspective': (-45, 0, -45)
  17. }
  18. def __init__(self, window, ortho=False):
  19. self.window = window
  20. self.axes = self.window.plot.axes
  21. self.ortho = ortho
  22. self.reset()
  23. def init_rot_matrix(self):
  24. pgl.glPushMatrix()
  25. pgl.glLoadIdentity()
  26. self._rot = get_model_matrix()
  27. pgl.glPopMatrix()
  28. def set_rot_preset(self, preset_name):
  29. self.init_rot_matrix()
  30. if preset_name not in self.rot_presets:
  31. raise ValueError(
  32. "%s is not a valid rotation preset." % preset_name)
  33. r = self.rot_presets[preset_name]
  34. self.euler_rotate(r[0], 1, 0, 0)
  35. self.euler_rotate(r[1], 0, 1, 0)
  36. self.euler_rotate(r[2], 0, 0, 1)
  37. def reset(self):
  38. self._dist = 0.0
  39. self._x, self._y = 0.0, 0.0
  40. self._rot = None
  41. if self.ortho:
  42. self._dist = self._default_ortho_dist
  43. else:
  44. self._dist = self._default_dist
  45. self.init_rot_matrix()
  46. def mult_rot_matrix(self, rot):
  47. pgl.glPushMatrix()
  48. pgl.glLoadMatrixf(rot)
  49. pgl.glMultMatrixf(self._rot)
  50. self._rot = get_model_matrix()
  51. pgl.glPopMatrix()
  52. def setup_projection(self):
  53. pgl.glMatrixMode(pgl.GL_PROJECTION)
  54. pgl.glLoadIdentity()
  55. if self.ortho:
  56. # yep, this is pseudo ortho (don't tell anyone)
  57. pgl.gluPerspective(
  58. 0.3, float(self.window.width)/float(self.window.height),
  59. self.min_ortho_dist - 0.01, self.max_ortho_dist + 0.01)
  60. else:
  61. pgl.gluPerspective(
  62. 30.0, float(self.window.width)/float(self.window.height),
  63. self.min_dist - 0.01, self.max_dist + 0.01)
  64. pgl.glMatrixMode(pgl.GL_MODELVIEW)
  65. def _get_scale(self):
  66. return 1.0, 1.0, 1.0
  67. def apply_transformation(self):
  68. pgl.glLoadIdentity()
  69. pgl.glTranslatef(self._x, self._y, -self._dist)
  70. if self._rot is not None:
  71. pgl.glMultMatrixf(self._rot)
  72. pgl.glScalef(*self._get_scale())
  73. def spherical_rotate(self, p1, p2, sensitivity=1.0):
  74. mat = get_spherical_rotatation(p1, p2, self.window.width,
  75. self.window.height, sensitivity)
  76. if mat is not None:
  77. self.mult_rot_matrix(mat)
  78. def euler_rotate(self, angle, x, y, z):
  79. pgl.glPushMatrix()
  80. pgl.glLoadMatrixf(self._rot)
  81. pgl.glRotatef(angle, x, y, z)
  82. self._rot = get_model_matrix()
  83. pgl.glPopMatrix()
  84. def zoom_relative(self, clicks, sensitivity):
  85. if self.ortho:
  86. dist_d = clicks * sensitivity * 50.0
  87. min_dist = self.min_ortho_dist
  88. max_dist = self.max_ortho_dist
  89. else:
  90. dist_d = clicks * sensitivity
  91. min_dist = self.min_dist
  92. max_dist = self.max_dist
  93. new_dist = (self._dist - dist_d)
  94. if (clicks < 0 and new_dist < max_dist) or new_dist > min_dist:
  95. self._dist = new_dist
  96. def mouse_translate(self, x, y, dx, dy):
  97. pgl.glPushMatrix()
  98. pgl.glLoadIdentity()
  99. pgl.glTranslatef(0, 0, -self._dist)
  100. z = model_to_screen(0, 0, 0)[2]
  101. d = vec_subs(screen_to_model(x, y, z), screen_to_model(x - dx, y - dy, z))
  102. pgl.glPopMatrix()
  103. self._x += d[0]
  104. self._y += d[1]