00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00040
00041 #include <algorithm>
00042 #include <limits>
00043 #include <pcl/apps/point_cloud_editor/common.h>
00044 #include <pcl/apps/point_cloud_editor/trackball.h>
00045
00046 TrackBall::TrackBall() : quat_(1.0f), origin_x_(0), origin_y_(0), origin_z_(0)
00047 {
00048 radius_sqr_ = (TRACKBALL_RADIUS_SCALE * static_cast<float>(WINDOW_WIDTH)) *
00049 (TRACKBALL_RADIUS_SCALE * static_cast<float>(WINDOW_WIDTH));
00050 }
00051
00052 TrackBall::TrackBall(const TrackBall ©) :
00053 quat_(copy.quat_), origin_x_(copy.origin_x_), origin_y_(copy.origin_y_),
00054 origin_z_(copy.origin_z_), radius_sqr_(copy.radius_sqr_)
00055 {
00056
00057 }
00058
00059 TrackBall::~TrackBall()
00060 {
00061
00062 }
00063
00064 TrackBall&
00065 TrackBall::operator=(const TrackBall &rhs)
00066 {
00067 quat_ = rhs.quat_;
00068 origin_x_ = rhs.origin_x_;
00069 origin_y_ = rhs.origin_y_;
00070 origin_z_ = rhs.origin_z_;
00071 radius_sqr_ = rhs.radius_sqr_;
00072 return *this;
00073 }
00074
00075 void
00076 TrackBall::start(int s_x, int s_y)
00077 {
00078 getPointFromScreenPoint(s_x, s_y, origin_x_, origin_y_, origin_z_);
00079 }
00080
00081 void
00082 normalize(float x, float y, float z, float &nx, float &ny, float &nz)
00083 {
00084 float inv_len = 1.0f / std::sqrt(x * x + y * y + z * z);
00085 nx = x * inv_len;
00086 ny = y * inv_len;
00087 nz = z * inv_len;
00088 }
00089
00090 boost::math::quaternion<float>
00091 normalizeQuaternion(const boost::math::quaternion<float> &q)
00092 {
00093 float w = q.R_component_1();
00094 float x = q.R_component_2();
00095 float y = q.R_component_3();
00096 float z = q.R_component_4();
00097 float inv_len = 1.0f / std::sqrt(w * w + x * x + y * y + z * z);
00098 return boost::math::quaternion<float>(w * inv_len, x * inv_len, y * inv_len,
00099 z * inv_len);
00100 }
00101
00102 boost::math::quaternion<float>
00103 quaternionFromAngleAxis(float angle, float x, float y, float z)
00104 {
00105 float s = std::sin(0.5f * angle);
00106 float qw = std::cos(0.5f * angle);
00107 float qx = x * s;
00108 float qy = y * s;
00109 float qz = z * s;
00110 return normalizeQuaternion(boost::math::quaternion<float>(qw, qx, qy, qz));
00111 }
00112
00113 boost::math::quaternion<float>
00114 multiplyQuaternion(const boost::math::quaternion<float> &lhs,
00115 const boost::math::quaternion<float> &rhs)
00116 {
00117 float lw = lhs.R_component_1();
00118 float lx = lhs.R_component_2();
00119 float ly = lhs.R_component_3();
00120 float lz = lhs.R_component_4();
00121
00122 float rw = rhs.R_component_1();
00123 float rx = rhs.R_component_2();
00124 float ry = rhs.R_component_3();
00125 float rz = rhs.R_component_4();
00126
00127 float tw = lw * rw - lx * rx - ly * ry - lz * rz;
00128 float tx = lw * rx + lx * rw - ly * rz + lz * ry;
00129 float ty = lw * ry + lx * rz + ly * rw - lz * rx;
00130 float tz = lw * rz - lx * ry + ly * rx + lz * rw;
00131
00132 return boost::math::quaternion<float>(tw, tx, ty, tz);
00133 }
00134
00135 void
00136 TrackBall::update(int s_x, int s_y)
00137 {
00138 float cur_x, cur_y, cur_z;
00139 getPointFromScreenPoint(s_x, s_y, cur_x, cur_y, cur_z);
00140
00141 float d_x = cur_x - origin_x_;
00142 float d_y = cur_y - origin_y_;
00143 float d_z = cur_z - origin_z_;
00144
00145 float dot = d_x * d_x + d_y * d_y + d_z * d_z;
00146 if (dot < std::numeric_limits<float>::epsilon())
00147 {
00148 quat_ = boost::math::quaternion<float>(1.0f);
00149 return;
00150 }
00151 float nc_x, nc_y, nc_z;
00152 float no_x, no_y, no_z;
00153 normalize(cur_x, cur_y, cur_z, nc_x, nc_y, nc_z);
00154 normalize(origin_x_, origin_y_, origin_z_, no_x, no_y, no_z);
00155
00156
00157 float angle = std::acos(nc_x * no_x + nc_y * no_y + nc_z * no_z);
00158
00159
00160 float cross_x = nc_y * no_z - nc_z * no_y;
00161 float cross_y = nc_z * no_x - nc_x * no_z;
00162 float cross_z = nc_x * no_y - nc_y * no_x;
00163
00164
00165 normalize(cross_x, cross_y, cross_z, nc_x, nc_y, nc_z);
00166
00167 quat_ = quaternionFromAngleAxis(angle, nc_x, nc_y, nc_z);
00168 if (quat_.R_component_1() != quat_.R_component_1())
00169 quat_ = boost::math::quaternion<float>(1.0f);
00170
00171 origin_x_ = cur_x;
00172 origin_y_ = cur_y;
00173 origin_z_ = cur_z;
00174 }
00175
00176 void
00177 TrackBall::getRotationMatrix(float (&rot)[MATRIX_SIZE])
00178 {
00179
00180
00181
00182 float a = quat_.R_component_1();
00183 float b = quat_.R_component_2();
00184 float c = quat_.R_component_3();
00185 float d = quat_.R_component_4();
00186
00187 float aa = a*a;
00188 float ab = a*b;
00189 float ac = a*c;
00190 float ad = a*d;
00191 float bb = b*b;
00192 float bc = b*c;
00193 float bd = b*d;
00194 float cc = c*c;
00195 float cd = c*d;
00196 float dd = d*d;
00197
00198 setIdentity(rot);
00199 float n = aa + bb + cc + dd;
00200
00201 if (n <= std::numeric_limits<float>::epsilon())
00202 return;
00203
00204
00205 rot[0] = (aa + bb - cc - dd);
00206 rot[1] = 2 * (-ad + bc);
00207 rot[2] = 2 * (ac + bd);
00208 rot[MATRIX_SIZE_DIM+0] = 2 * (ad + bc);
00209 rot[MATRIX_SIZE_DIM+1] = (aa - bb + cc - dd);
00210 rot[MATRIX_SIZE_DIM+2] = 2 * (-ab + cd);
00211 rot[2*MATRIX_SIZE_DIM+0] = 2 * (-ac + bd);
00212 rot[2*MATRIX_SIZE_DIM+1] = 2 * (ab + cd);
00213 rot[2*MATRIX_SIZE_DIM+2] = (aa - bb - cc + dd);
00214 }
00215
00216 void
00217 TrackBall::reset()
00218 {
00219 quat_ = boost::math::quaternion<float>(1.0f);
00220 }
00221
00222 void
00223 TrackBall::getPointFromScreenPoint(int s_x, int s_y,
00224 float &x, float &y, float &z)
00225 {
00226
00227
00228 x = static_cast<float>(s_x) - (static_cast<float>(WINDOW_WIDTH) * 0.5f);
00229 y = (static_cast<float>(WINDOW_HEIGHT) * 0.5f) - static_cast<float>(s_y);
00230 float d = x * x + y * y;
00231 if (d > 0.5f * radius_sqr_)
00232 {
00233
00234 z = (0.5f * radius_sqr_) / std::sqrt(d);
00235 return;
00236 }
00237
00238 z = std::sqrt(radius_sqr_ - d);
00239 }
00240