1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
# -*- coding: utf-8 -*-
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.
from __future__ import division
import numpy as np
from .perspective import Base3DRotationCamera
class TurntableCamera(Base3DRotationCamera):
""" 3D camera class that orbits around a center point while
maintaining a view on a center point.
For this camera, the ``scale_factor`` indicates the zoom level, and
the ``center`` indicates the position to put at the center of the
view.
Parameters
----------
fov : float
Field of view. Zero (default) means orthographic projection.
elevation : float
Elevation angle in degrees. Positive angles place the camera
above the cente point, negative angles place the camera below
the center point.
azimuth : float
Azimuth angle in degrees. Zero degrees places the camera on the
positive x-axis, pointing in the negative x direction.
roll : float
Roll angle in degrees
distance : float | None
The distance of the camera from the rotation point (only makes sense
if fov > 0). If None (default) the distance is determined from the
scale_factor and fov.
translate_speed : float
Scale factor on translation speed when moving the camera center point.
**kwargs : dict
Keyword arguments to pass to `BaseCamera`.
Notes
-----
Interaction:
* LMB: orbits the view around its center point.
* RMB or scroll: change scale_factor (i.e. zoom level)
* SHIFT + LMB: translate the center point
* SHIFT + RMB: change FOV
"""
_state_props = Base3DRotationCamera._state_props + ('elevation',
'azimuth', 'roll')
def __init__(self, fov=45.0, elevation=30.0, azimuth=30.0, roll=0.0,
distance=None, translate_speed=1.0, **kwargs):
super(TurntableCamera, self).__init__(fov=fov, **kwargs)
# Set camera attributes
self.azimuth = azimuth
self.elevation = elevation
self.roll = roll # interaction not implemented yet
self.distance = distance # None means auto-distance
self.translate_speed = translate_speed
@property
def elevation(self):
""" The angle of the camera in degrees above the horizontal (x, z)
plane.
"""
return self._elevation
@elevation.setter
def elevation(self, elev):
elev = float(elev)
self._elevation = min(90, max(-90, elev))
self.view_changed()
@property
def azimuth(self):
""" The angle of the camera in degrees around the y axis. An angle of
0 places the camera within the (y, z) plane.
"""
return self._azimuth
@azimuth.setter
def azimuth(self, azim):
azim = float(azim)
while azim < -180:
azim += 360
while azim > 180:
azim -= 360
self._azimuth = azim
self.view_changed()
@property
def roll(self):
""" The angle of the camera in degrees around the z axis. An angle of
0 places puts the camera upright.
"""
return self._roll
@roll.setter
def roll(self, roll):
roll = float(roll)
while roll < -180:
roll += 360
while roll > 180:
roll -= 360
self._roll = roll
self.view_changed()
def orbit(self, azim, elev):
""" Orbits the camera around the center position.
Parameters
----------
azim : float
Angle in degrees to rotate horizontally around the center point.
elev : float
Angle in degrees to rotate vertically around the center point.
"""
self.azimuth += azim
self.elevation = np.clip(self.elevation + elev, -90, 90)
self.view_changed()
def _update_rotation(self, event):
"""Update rotation parmeters based on mouse movement"""
p1 = event.mouse_event.press_event.pos
p2 = event.mouse_event.pos
if self._event_value is None:
self._event_value = self.azimuth, self.elevation
self.azimuth = self._event_value[0] - (p2 - p1)[0] * 0.5
self.elevation = self._event_value[1] + (p2 - p1)[1] * 0.5
def _rotate_tr(self):
"""Rotate the transformation matrix based on camera parameters"""
up, forward, right = self._get_dim_vectors()
self.transform.rotate(self.elevation, -right)
self.transform.rotate(self.azimuth, up)
def _dist_to_trans(self, dist):
"""Convert mouse x, y movement into x, y, z translations"""
rae = np.array([self.roll, self.azimuth, self.elevation]) * np.pi / 180
sro, saz, sel = np.sin(rae)
cro, caz, cel = np.cos(rae)
d0, d1 = dist[0], dist[1]
dx = (+ d0 * (cro * caz + sro * sel * saz)
+ d1 * (sro * caz - cro * sel * saz)) * self.translate_speed
dy = (+ d0 * (cro * saz - sro * sel * caz)
+ d1 * (sro * saz + cro * sel * caz)) * self.translate_speed
dz = (- d0 * sro * cel + d1 * cro * cel) * self.translate_speed
return dx, dy, dz
|