diff options
-rw-r--r-- | src/math/axis.cc | 17 | ||||
-rw-r--r-- | src/math/axis.h | 3 | ||||
-rw-r--r-- | src/render/camera.cc | 86 |
3 files changed, 38 insertions, 68 deletions
diff --git a/src/math/axis.cc b/src/math/axis.cc index 4d752bf..aa35d92 100644 --- a/src/math/axis.cc +++ b/src/math/axis.cc @@ -74,6 +74,23 @@ void Axis::change_roll(const float angle) { axis_vector[1].assign(up); } +// perform a rotation about an arbitrary axis +/* notes: + http://mathworld.wolfram.com/RotationFormula.html +*/ +void Axis::rotate(Vector3f const &normal, float angle) +{ + float cosa = cosf(angle); + float sina = sinf(angle); + + for (size_t i =0; i < 3; i++) { + axis_vector[i] = + axis_vector[i]*cosa + + normal * dotproduct(normal, axis_vector[i]) * (1 - cosa) + + crossproduct(axis_vector[i], normal)*sina; + } +} + /* Axis const Axis::transpose() { diff --git a/src/math/axis.h b/src/math/axis.h index d011675..1422564 100644 --- a/src/math/axis.h +++ b/src/math/axis.h @@ -48,6 +48,9 @@ public: /// change roll, rotate around forward vector (positive is left) void change_roll(const float angle); + /// rotation about an arbitrary axis + void rotate(Vector3f const &normal, float angle); + private: Vector3f axis_vector[3]; }; diff --git a/src/render/camera.cc b/src/render/camera.cc index e37fd0d..c35cb3c 100644 --- a/src/render/camera.cc +++ b/src/render/camera.cc @@ -186,79 +186,29 @@ void Camera::frame(float seconds) distance = core::localcontrol()->radius(); if (mode() == Track) { - float cosangle; - float angle; - float side; - float u; - //const float camspeed = 90.0f * seconds; // 180 degrees per second - - math::Vector3f n; - math::Vector3f p; - - // camera axis: pitch - - // project target_axis.up() into the plane with axis->left() normal - n = camera_axis.left(); - p = target_axis.up(); - u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); - p = target_axis.up() + u * n; - - side = camera_axis.forward().x * p.x + - camera_axis.forward().y * p.y + - camera_axis.forward().z * p.z; - - if ((fabs(side) - MIN_DELTA > 0)) { - - cosangle = math::dotproduct(p, camera_axis.up()); - if (fabs(cosangle) + MIN_DELTA < 1 ) { - angle = acos(cosangle) * 180.0f / M_PI; - angle = math::sgnf(side) * angle * seconds; - camera_axis.change_pitch(-angle); - } - } - // camera axis: direction - - // project target_axis.forward() into the plane with axis.up() normal - n = camera_axis.up(); - p = target_axis.forward(); - u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); - p = target_axis.forward() + u * n; - - side = camera_axis.left().x * p.x + - camera_axis.left().y * p.y + - camera_axis.left().z * p.z; - - if ((fabs(side) - MIN_DELTA > 0)) { - - cosangle = math::dotproduct(p, camera_axis.forward()); - if (fabs(cosangle) + MIN_DELTA < 1 ) { - angle = acos(cosangle) * 180.0f / M_PI; - angle = math::sgnf(side) * angle * seconds; - camera_axis.change_direction(angle); - } + float cosangle; // cosine of an angle + float angle; // angle in radians + math::Vector3f n; // normal of a plane + + // camera axis: pitch & direction + + n.assign(math::crossproduct(camera_axis.forward(), target_axis.forward())); + if (n.lengthsquared() > MIN_DELTA) { + n.normalize(); + cosangle = math::dotproduct(camera_axis.forward(), target_axis.forward()); + angle = acos(cosangle); // * 180.0f / M_PI; + camera_axis.rotate(n, -angle * seconds); } // camera axis: roll - // project target_axis.up() into the plane with axis.forward() normal - n = camera_axis.forward(); - p = target_axis.up(); - u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); - p = target_axis.up() + u * n; - - side = camera_axis.left().x * p.x + - camera_axis.left().y * p.y + - camera_axis.left().z * p.z; - - if ((fabs(side) - MIN_DELTA > 0)) { - - cosangle = math::dotproduct(p, camera_axis.up()); - if (fabs(cosangle) + MIN_DELTA < 1 ) { - angle = acos(cosangle) * 180.0f / M_PI; - angle = math::sgnf(side) * angle * seconds; - camera_axis.change_roll(angle); - } + n.assign(math::crossproduct(camera_axis.left(), target_axis.left())); + if (n.lengthsquared() > MIN_DELTA) { + n.normalize(); + cosangle = math::dotproduct(camera_axis.left(), target_axis.left()); + angle = acos(cosangle); // * 180.0f / M_PI; + camera_axis.rotate(n, -angle * seconds); } if (core::localcontrol()->model()) { |