00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "domUtils.h"
00024 #include "manipulatedCameraFrame.h"
00025 #include "qglviewer.h"
00026
00027 #if QT_VERSION >= 0x040000
00028 # include <QMouseEvent>
00029 #endif
00030
00031 using namespace qglviewer;
00032 using namespace std;
00033
00039 ManipulatedCameraFrame::ManipulatedCameraFrame()
00040 : driveSpeed_(0.0), flyUpVector_(0.0, 1.0, 0.0)
00041 {
00042 setFlySpeed(0.0);
00043 removeFromMouseGrabberPool();
00044
00045 connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate()));
00046 }
00047
00049 ManipulatedCameraFrame& ManipulatedCameraFrame::operator=(const ManipulatedCameraFrame& mcf)
00050 {
00051 ManipulatedFrame::operator=(mcf);
00052
00053 setFlySpeed(mcf.flySpeed());
00054 setFlyUpVector(mcf.flyUpVector());
00055
00056 return *this;
00057 }
00058
00060 ManipulatedCameraFrame::ManipulatedCameraFrame(const ManipulatedCameraFrame& mcf)
00061 : ManipulatedFrame(mcf)
00062 {
00063 removeFromMouseGrabberPool();
00064 connect(&flyTimer_, SIGNAL(timeout()), SLOT(flyUpdate()));
00065 (*this)=(mcf);
00066 }
00067
00069
00073 void ManipulatedCameraFrame::spin()
00074 {
00075 rotateAroundPoint(spinningQuaternion(), revolveAroundPoint());
00076 }
00077
00078 #ifndef DOXYGEN
00079
00081 void ManipulatedCameraFrame::flyUpdate()
00082 {
00083 static Vec flyDisp(0.0, 0.0, 0.0);
00084 switch (action_)
00085 {
00086 case QGLViewer::MOVE_FORWARD:
00087 flyDisp.z = -flySpeed();
00088 translate(localInverseTransformOf(flyDisp));
00089 break;
00090 case QGLViewer::MOVE_BACKWARD:
00091 flyDisp.z = flySpeed();
00092 translate(localInverseTransformOf(flyDisp));
00093 break;
00094 case QGLViewer::DRIVE:
00095 flyDisp.z = flySpeed() * driveSpeed_;
00096 translate(localInverseTransformOf(flyDisp));
00097 break;
00098 default:
00099 break;
00100 }
00101
00102
00103
00104 Q_EMIT manipulated();
00105 }
00106 #endif
00107
00110 void ManipulatedCameraFrame::updateFlyUpVector()
00111 {
00112 flyUpVector_ = inverseTransformOf(Vec(0.0, 1.0, 0.0));
00113 }
00114
00116
00118
00132 QDomElement ManipulatedCameraFrame::domElement(const QString& name, QDomDocument& document) const
00133 {
00134 QDomElement e = ManipulatedFrame::domElement(name, document);
00135 QDomElement mcp = document.createElement("ManipulatedCameraParameters");
00136 mcp.setAttribute("flySpeed", QString::number(flySpeed()));
00137 mcp.appendChild(flyUpVector().domElement("flyUpVector", document));
00138 e.appendChild(mcp);
00139 return e;
00140 }
00141
00146 void ManipulatedCameraFrame::initFromDOMElement(const QDomElement& element)
00147 {
00148
00149
00150
00151 ManipulatedFrame::initFromDOMElement(element);
00152
00153 QDomElement child=element.firstChild().toElement();
00154 while (!child.isNull())
00155 {
00156 if (child.tagName() == "ManipulatedCameraParameters")
00157 {
00158 setFlySpeed(DomUtils::floatFromDom(child, "flySpeed", flySpeed()));
00159
00160 QDomElement schild=child.firstChild().toElement();
00161 while (!schild.isNull())
00162 {
00163 if (schild.tagName() == "flyUpVector")
00164 setFlyUpVector(Vec(schild));
00165
00166 schild = schild.nextSibling().toElement();
00167 }
00168 }
00169 child = child.nextSibling().toElement();
00170 }
00171 }
00172
00173
00175
00177
00178 #ifndef DOXYGEN
00179
00180 void ManipulatedCameraFrame::startAction(int ma, bool withConstraint)
00181 {
00182 ManipulatedFrame::startAction(ma, withConstraint);
00183
00184 switch (action_)
00185 {
00186 case QGLViewer::MOVE_FORWARD:
00187 case QGLViewer::MOVE_BACKWARD:
00188 case QGLViewer::DRIVE:
00189 #if QT_VERSION >= 0x040000
00190 flyTimer_.setSingleShot(false);
00191 #endif
00192 flyTimer_.start(10);
00193 break;
00194 default:
00195 break;
00196 }
00197 }
00198 #endif
00199
00204 void ManipulatedCameraFrame::mouseMoveEvent(QMouseEvent* const event, Camera* const camera)
00205 {
00206
00207 switch (action_)
00208 {
00209 case QGLViewer::TRANSLATE:
00210 {
00211 const QPoint delta = prevPos_ - event->pos();
00212 Vec trans(static_cast<float>(delta.x()), static_cast<float>(-delta.y()), 0.0);
00213
00214 switch (camera->type())
00215 {
00216 case Camera::PERSPECTIVE :
00217 trans *= 2.0 * tan(camera->fieldOfView()/2.0) *
00218 fabs((camera->frame()->coordinatesOf(revolveAroundPoint())).z) / camera->screenHeight();
00219 break;
00220 case Camera::ORTHOGRAPHIC :
00221 {
00222 GLdouble w,h;
00223 camera->getOrthoWidthHeight(w, h);
00224 trans[0] *= 2.0 * w / camera->screenWidth();
00225 trans[1] *= 2.0 * h / camera->screenHeight();
00226 break;
00227 }
00228 }
00229 translate(inverseTransformOf(translationSensitivity()*trans));
00230 break;
00231 }
00232
00233 case QGLViewer::MOVE_FORWARD:
00234 {
00235 Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera);
00236 rotate(rot);
00237
00238
00239
00240 break;
00241 }
00242
00243 case QGLViewer::MOVE_BACKWARD:
00244 {
00245 Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera);
00246 rotate(rot);
00247
00248
00249 break;
00250 }
00251
00252 case QGLViewer::DRIVE:
00253 {
00254 Quaternion rot = turnQuaternion(event->x(), camera);
00255 rotate(rot);
00256
00257 driveSpeed_ = 0.01 * (event->y() - pressPos_.y());
00258 break;
00259 }
00260
00261 case QGLViewer::ZOOM:
00262 {
00263
00264 const float coef = qMax(fabsf((camera->frame()->coordinatesOf(camera->revolveAroundPoint())).z), 0.2f*camera->sceneRadius());
00265 Vec trans(0.0, 0.0, -coef * (event->y() - prevPos_.y()) / camera->screenHeight());
00266 translate(inverseTransformOf(trans));
00267 break;
00268 }
00269
00270 case QGLViewer::LOOK_AROUND:
00271 {
00272 Quaternion rot = pitchYawQuaternion(event->x(), event->y(), camera);
00273 rotate(rot);
00274 break;
00275 }
00276
00277 case QGLViewer::ROTATE:
00278 {
00279 Vec trans = camera->projectedCoordinatesOf(revolveAroundPoint());
00280 Quaternion rot = deformedBallQuaternion(event->x(), event->y(), trans[0], trans[1], camera);
00281
00282 computeMouseSpeed(event);
00283 setSpinningQuaternion(rot);
00284 spin();
00285 break;
00286 }
00287
00288 case QGLViewer::SCREEN_ROTATE:
00289 {
00290 Vec trans = camera->projectedCoordinatesOf(revolveAroundPoint());
00291
00292 const float angle = atan2(event->y() - trans[1], event->x() - trans[0]) - atan2(prevPos_.y()-trans[1], prevPos_.x()-trans[0]);
00293
00294 Quaternion rot(Vec(0.0, 0.0, 1.0), angle);
00295
00296 computeMouseSpeed(event);
00297 setSpinningQuaternion(rot);
00298 spin();
00299 updateFlyUpVector();
00300 break;
00301 }
00302
00303 case QGLViewer::ROLL:
00304 {
00305 const float angle = M_PI * (event->x() - prevPos_.x()) / camera->screenWidth();
00306 Quaternion rot(Vec(0.0, 0.0, 1.0), angle);
00307 rotate(rot);
00308 setSpinningQuaternion(rot);
00309 updateFlyUpVector();
00310 break;
00311 }
00312
00313 case QGLViewer::SCREEN_TRANSLATE:
00314 {
00315 Vec trans;
00316 int dir = mouseOriginalDirection(event);
00317 if (dir == 1)
00318 trans.setValue(static_cast<float>(prevPos_.x() - event->x()), 0.0, 0.0);
00319 else if (dir == -1)
00320 trans.setValue(0.0, static_cast<float>(event->y() - prevPos_.y()), 0.0);
00321
00322 switch (camera->type())
00323 {
00324 case Camera::PERSPECTIVE :
00325 trans *= 2.0 * tan(camera->fieldOfView()/2.0) *
00326 fabs((camera->frame()->coordinatesOf(revolveAroundPoint())).z) / camera->screenHeight();
00327 break;
00328 case Camera::ORTHOGRAPHIC :
00329 {
00330 GLdouble w,h;
00331 camera->getOrthoWidthHeight(w, h);
00332 trans[0] *= 2.0 * w / camera->screenWidth();
00333 trans[1] *= 2.0 * h / camera->screenHeight();
00334 break;
00335 }
00336 }
00337
00338 translate(inverseTransformOf(translationSensitivity()*trans));
00339 break;
00340 }
00341
00342 case QGLViewer::ZOOM_ON_REGION:
00343 case QGLViewer::NO_MOUSE_ACTION:
00344 break;
00345 }
00346
00347 if (action_ != QGLViewer::NO_MOUSE_ACTION)
00348 {
00349 prevPos_ = event->pos();
00350 if (action_ != QGLViewer::ZOOM_ON_REGION)
00351
00352
00353 Q_EMIT manipulated();
00354 }
00355 }
00356
00357
00360 void ManipulatedCameraFrame::mouseReleaseEvent(QMouseEvent* const event, Camera* const camera)
00361 {
00362 if ((action_ == QGLViewer::MOVE_FORWARD) || (action_ == QGLViewer::MOVE_BACKWARD) || (action_ == QGLViewer::DRIVE))
00363 flyTimer_.stop();
00364
00365 if (action_ == QGLViewer::ZOOM_ON_REGION)
00366 camera->fitScreenRegion(QRect(pressPos_, event->pos()));
00367
00368 ManipulatedFrame::mouseReleaseEvent(event, camera);
00369 }
00370
00377 void ManipulatedCameraFrame::wheelEvent(QWheelEvent* const event, Camera* const camera)
00378 {
00379
00380 switch (action_)
00381 {
00382 case QGLViewer::ZOOM:
00383 {
00384 const float wheelSensitivityCoef = 8E-4f;
00385
00386 const float coef = qMax(fabsf((camera->frame()->coordinatesOf(camera->revolveAroundPoint())).z), 0.2f*camera->sceneRadius());
00387 Vec trans(0.0, 0.0, coef * event->delta() * wheelSensitivity() * wheelSensitivityCoef);
00388 translate(inverseTransformOf(trans));
00389 Q_EMIT manipulated();
00390 break;
00391 }
00392 case QGLViewer::MOVE_FORWARD:
00393 case QGLViewer::MOVE_BACKWARD:
00394
00395 translate(inverseTransformOf(Vec(0.0, 0.0, 0.2*flySpeed()*event->delta())));
00396 Q_EMIT manipulated();
00397 break;
00398 default:
00399 break;
00400 }
00401
00402
00403 if (previousConstraint_)
00404 setConstraint(previousConstraint_);
00405
00406
00407
00408
00409
00410 const int finalDrawAfterWheelEventDelay = 400;
00411
00412
00413 #if QT_VERSION >= 0x040000
00414 flyTimer_.setSingleShot(true);
00415 flyTimer_.start(finalDrawAfterWheelEventDelay);
00416 #else
00417 flyTimer_.start(finalDrawAfterWheelEventDelay, true);
00418 #endif
00419
00420
00421
00422
00423 action_ = QGLViewer::NO_MOUSE_ACTION;
00424 }
00425
00427
00429 Quaternion ManipulatedCameraFrame::turnQuaternion(int x, const Camera* const camera)
00430 {
00431 return Quaternion(Vec(0.0, 1.0, 0.0), rotationSensitivity()*(prevPos_.x()-x)/camera->screenWidth());
00432 }
00433
00436 Quaternion ManipulatedCameraFrame::pitchYawQuaternion(int x, int y, const Camera* const camera)
00437 {
00438 const Quaternion rotX(Vec(1.0, 0.0, 0.0), rotationSensitivity()*(prevPos_.y()-y)/camera->screenHeight());
00439 const Quaternion rotY(transformOf(flyUpVector()), rotationSensitivity()*(prevPos_.x()-x)/camera->screenWidth());
00440 return rotY * rotX;
00441 }