static void simulate_trackball(quat *q, GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y) { if (p1x == p2x && p1y == p2y) { quat_identity(q); } else { quat p1, p2, a, d; float p1z, p2z; float s, t; p1z = project_to_sphere(p1x, p1y); quat_assign(&p1, 0.0, p1x, p1y, p1z); p2z = project_to_sphere(p2x, p2y); quat_assign(&p2, 0.0, p2x, p2y, p2z); quat_mul(&a, &p1, &p2); a.w = 0.0; s = quat_norm(&a); quat_div_real(&a, &a, s); quat_sub(&d, &p1, &p2); t = quat_norm(&d) / (2.0 * R * ROOT_2_INV); if (t > 1.0) t = 1.0; quat_assign(q, cos(asin(t)), a.x * t, a.y * t, a.z * t); } }
void trackball:: rotate(double fx, double fy, double tx, double ty) { scm::math::vec3d start(fx, fy, project_to_sphere(fx, fy)); scm::math::vec3d end(tx, ty, project_to_sphere(tx, ty)); scm::math::vec3d diff(end - start); double diff_len = scm::math::length(diff); scm::math::vec3d rot_axis(cross(start, end)); double rot_angle = 2.0 * asin(scm::math::clamp(diff_len/(2.0 * radius_), -1.0, 1.0)); scm::math::mat4d tmp(scm::math::mat4d::identity()); scm::math::mat4d tmp_dolly(scm::math::mat4d::identity()); scm::math::mat4d tmp_dolly_inv(scm::math::mat4d::identity()); scm::math::translate(tmp_dolly, 0.0, 0.0, dolly_); scm::math::translate(tmp_dolly_inv, 0.0, 0.0, -dolly_); scm::math::rotate(tmp, scm::math::rad2deg(rot_angle), rot_axis); transform_ = tmp_dolly * tmp * tmp_dolly_inv * transform_; }