plot_camera.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. try:
  31. r = self.rot_presets[preset_name]
  32. except AttributeError:
  33. raise ValueError(
  34. "%s is not a valid rotation preset." % preset_name)
  35. try:
  36. self.euler_rotate(r[0], 1, 0, 0)
  37. self.euler_rotate(r[1], 0, 1, 0)
  38. self.euler_rotate(r[2], 0, 0, 1)
  39. except AttributeError:
  40. pass
  41. def reset(self):
  42. self._dist = 0.0
  43. self._x, self._y = 0.0, 0.0
  44. self._rot = None
  45. if self.ortho:
  46. self._dist = self._default_ortho_dist
  47. else:
  48. self._dist = self._default_dist
  49. self.init_rot_matrix()
  50. def mult_rot_matrix(self, rot):
  51. pgl.glPushMatrix()
  52. pgl.glLoadMatrixf(rot)
  53. pgl.glMultMatrixf(self._rot)
  54. self._rot = get_model_matrix()
  55. pgl.glPopMatrix()
  56. def setup_projection(self):
  57. pgl.glMatrixMode(pgl.GL_PROJECTION)
  58. pgl.glLoadIdentity()
  59. if self.ortho:
  60. # yep, this is pseudo ortho (don't tell anyone)
  61. pgl.gluPerspective(
  62. 0.3, float(self.window.width)/float(self.window.height),
  63. self.min_ortho_dist - 0.01, self.max_ortho_dist + 0.01)
  64. else:
  65. pgl.gluPerspective(
  66. 30.0, float(self.window.width)/float(self.window.height),
  67. self.min_dist - 0.01, self.max_dist + 0.01)
  68. pgl.glMatrixMode(pgl.GL_MODELVIEW)
  69. def _get_scale(self):
  70. return 1.0, 1.0, 1.0
  71. def apply_transformation(self):
  72. pgl.glLoadIdentity()
  73. pgl.glTranslatef(self._x, self._y, -self._dist)
  74. if self._rot is not None:
  75. pgl.glMultMatrixf(self._rot)
  76. pgl.glScalef(*self._get_scale())
  77. def spherical_rotate(self, p1, p2, sensitivity=1.0):
  78. mat = get_spherical_rotatation(p1, p2, self.window.width,
  79. self.window.height, sensitivity)
  80. if mat is not None:
  81. self.mult_rot_matrix(mat)
  82. def euler_rotate(self, angle, x, y, z):
  83. pgl.glPushMatrix()
  84. pgl.glLoadMatrixf(self._rot)
  85. pgl.glRotatef(angle, x, y, z)
  86. self._rot = get_model_matrix()
  87. pgl.glPopMatrix()
  88. def zoom_relative(self, clicks, sensitivity):
  89. if self.ortho:
  90. dist_d = clicks * sensitivity * 50.0
  91. min_dist = self.min_ortho_dist
  92. max_dist = self.max_ortho_dist
  93. else:
  94. dist_d = clicks * sensitivity
  95. min_dist = self.min_dist
  96. max_dist = self.max_dist
  97. new_dist = (self._dist - dist_d)
  98. if (clicks < 0 and new_dist < max_dist) or new_dist > min_dist:
  99. self._dist = new_dist
  100. def mouse_translate(self, x, y, dx, dy):
  101. pgl.glPushMatrix()
  102. pgl.glLoadIdentity()
  103. pgl.glTranslatef(0, 0, -self._dist)
  104. z = model_to_screen(0, 0, 0)[2]
  105. d = vec_subs(screen_to_model(x, y, z), screen_to_model(x - dx, y - dy, z))
  106. pgl.glPopMatrix()
  107. self._x += d[0]
  108. self._y += d[1]