1 | /* -*-c++-*- osgVisual - Copyright (C) 2009-2010 Torben Dannhauer |
---|
2 | * |
---|
3 | * This library is based on OpenSceneGraph, open source and may be redistributed and/or modified under |
---|
4 | * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or |
---|
5 | * (at your option) any later version. The full license is in LICENSE file |
---|
6 | * included with this distribution, and on the openscenegraph.org website. |
---|
7 | * |
---|
8 | * osgVisual requires for some proprietary modules a license from the correspondig manufacturer. |
---|
9 | * You have to aquire licenses for all used proprietary modules. |
---|
10 | * |
---|
11 | * This library is distributed in the hope that it will be useful, |
---|
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | * OpenSceneGraph Public License for more details. |
---|
15 | */ |
---|
16 | |
---|
17 | #include <manip_nodeTrackerSpaceMouse.h> |
---|
18 | |
---|
19 | |
---|
20 | |
---|
21 | using namespace osg; |
---|
22 | using namespace osgVisual; |
---|
23 | |
---|
24 | |
---|
25 | NodeTrackerSpaceMouse::NodeTrackerSpaceMouse(SpaceMouse* spacemouse) : _spaceMouse(spacemouse) |
---|
26 | { |
---|
27 | _trackerMode = NODE_CENTER_AND_ROTATION; |
---|
28 | _rotationMode = TRACKBALL; |
---|
29 | |
---|
30 | _distance = 1.0; |
---|
31 | |
---|
32 | _thrown = false; |
---|
33 | _autohoming = false; |
---|
34 | _ah_init = false; |
---|
35 | _distanceDependendAV = false; |
---|
36 | |
---|
37 | TZ=0; |
---|
38 | RX=0; |
---|
39 | RY=0; |
---|
40 | RZ=0; |
---|
41 | |
---|
42 | } |
---|
43 | |
---|
44 | |
---|
45 | NodeTrackerSpaceMouse::~NodeTrackerSpaceMouse() |
---|
46 | { |
---|
47 | } |
---|
48 | |
---|
49 | void NodeTrackerSpaceMouse::setTrackNode(osg::Node* node) |
---|
50 | { |
---|
51 | if (!node) |
---|
52 | { |
---|
53 | osg::notify(osg::NOTICE)<<"NodeTrackerSpaceMouse::setTrackNode(Node*): Unable to set tracked node due to null Node*"<<std::endl; |
---|
54 | return; |
---|
55 | } |
---|
56 | |
---|
57 | osg::NodePathList parentNodePaths = node->getParentalNodePaths(); |
---|
58 | |
---|
59 | if (!parentNodePaths.empty()) |
---|
60 | { |
---|
61 | osg::notify(osg::INFO)<<"NodeTrackerSpaceMouse::setTrackNode(Node*): Path set"<<std::endl; |
---|
62 | setTrackNodePath(parentNodePaths[0]); |
---|
63 | } |
---|
64 | else |
---|
65 | { |
---|
66 | osg::notify(osg::NOTICE)<<"NodeTrackerSpaceMouse::setTrackNode(Node*): Unable to set tracked node due to empty parental path."<<std::endl; |
---|
67 | } |
---|
68 | } |
---|
69 | |
---|
70 | osg::Node* NodeTrackerSpaceMouse::getTrackNode() |
---|
71 | { |
---|
72 | osg::NodePath nodePath; |
---|
73 | if (_trackNodePath.getNodePath(nodePath)) return nodePath.back(); |
---|
74 | else return 0; |
---|
75 | } |
---|
76 | |
---|
77 | const osg::Node* NodeTrackerSpaceMouse::getTrackNode() const |
---|
78 | { |
---|
79 | osg::NodePath nodePath; |
---|
80 | if (_trackNodePath.getNodePath(nodePath)) return nodePath.back(); |
---|
81 | else return 0; |
---|
82 | } |
---|
83 | |
---|
84 | void NodeTrackerSpaceMouse::setTrackerMode(TrackerMode mode) |
---|
85 | { |
---|
86 | _trackerMode = mode; |
---|
87 | } |
---|
88 | |
---|
89 | void NodeTrackerSpaceMouse::setRotationMode(RotationMode mode) |
---|
90 | { |
---|
91 | _rotationMode = mode; |
---|
92 | if (getAutoComputeHomePosition()) computeHomePosition(); |
---|
93 | } |
---|
94 | |
---|
95 | void NodeTrackerSpaceMouse::setNode(osg::Node* node) |
---|
96 | { |
---|
97 | _node = node; |
---|
98 | |
---|
99 | if (_node.get()) |
---|
100 | { |
---|
101 | const osg::BoundingSphere& boundingSphere=_node->getBound(); |
---|
102 | const float minimumDistanceScale = 0.001f; |
---|
103 | _minimumDistance = osg::clampBetween( |
---|
104 | float(boundingSphere._radius) * minimumDistanceScale, |
---|
105 | 0.00001f,1.0f); |
---|
106 | |
---|
107 | osg::notify(osg::INFO)<<"Setting Tracker manipulator _minimumDistance to "<<_minimumDistance<<std::endl; |
---|
108 | } |
---|
109 | if (getAutoComputeHomePosition()) computeHomePosition(); |
---|
110 | } |
---|
111 | |
---|
112 | const osg::Node* NodeTrackerSpaceMouse::getNode() const |
---|
113 | { |
---|
114 | return _node.get(); |
---|
115 | } |
---|
116 | |
---|
117 | |
---|
118 | osg::Node* NodeTrackerSpaceMouse::getNode() |
---|
119 | { |
---|
120 | return _node.get(); |
---|
121 | } |
---|
122 | |
---|
123 | |
---|
124 | void NodeTrackerSpaceMouse::home(const GUIEventAdapter& ,GUIActionAdapter& us) |
---|
125 | { |
---|
126 | if (getAutoComputeHomePosition()) computeHomePosition(); |
---|
127 | |
---|
128 | computePosition(_homeEye, _homeCenter, _homeUp); |
---|
129 | us.requestRedraw(); |
---|
130 | } |
---|
131 | |
---|
132 | void NodeTrackerSpaceMouse::computeHomePosition() |
---|
133 | { |
---|
134 | osg::NodePath nodePath; |
---|
135 | _trackNodePath.getNodePath(nodePath); |
---|
136 | |
---|
137 | osg::Node* node = nodePath.empty() ? getNode() : nodePath.back(); |
---|
138 | |
---|
139 | if(node) |
---|
140 | { |
---|
141 | const osg::BoundingSphere& boundingSphere=node->getBound(); |
---|
142 | |
---|
143 | setHomePosition(boundingSphere._center+osg::Vec3( 0.0,-3.5f * boundingSphere._radius,0.0f), |
---|
144 | boundingSphere._center, |
---|
145 | osg::Vec3(0.0f,0.0f,1.0f), |
---|
146 | _autoComputeHomePosition); |
---|
147 | } |
---|
148 | } |
---|
149 | |
---|
150 | |
---|
151 | |
---|
152 | void NodeTrackerSpaceMouse::init(const GUIEventAdapter& ,GUIActionAdapter& ) |
---|
153 | { |
---|
154 | flushMouseEventStack(); |
---|
155 | } |
---|
156 | |
---|
157 | |
---|
158 | void NodeTrackerSpaceMouse::getUsage(osg::ApplicationUsage& usage) const |
---|
159 | { |
---|
160 | usage.addKeyboardMouseBinding("SN Tracker: Space","Toggle camera auto homing"); |
---|
161 | usage.addKeyboardMouseBinding("SN Tracker: m","Toggle Nodetracker Mode"); |
---|
162 | usage.addKeyboardMouseBinding("SN Tracker: n","Toggle distance dependend angular velocity"); |
---|
163 | usage.addKeyboardMouseBinding("SN Tracker: +","When in stereo, increase the fusion distance"); |
---|
164 | usage.addKeyboardMouseBinding("SN Tracker: -","When in stereo, reduce the fusion distance"); |
---|
165 | } |
---|
166 | |
---|
167 | bool NodeTrackerSpaceMouse::handle(const GUIEventAdapter& ea,GUIActionAdapter& us) |
---|
168 | { |
---|
169 | switch(ea.getEventType()) |
---|
170 | { |
---|
171 | case(GUIEventAdapter::PUSH): |
---|
172 | { |
---|
173 | flushMouseEventStack(); |
---|
174 | addMouseEvent(ea); |
---|
175 | if (calcMovement()) us.requestRedraw(); |
---|
176 | us.requestContinuousUpdate(false); |
---|
177 | _thrown = false; |
---|
178 | return true; |
---|
179 | } |
---|
180 | |
---|
181 | case(GUIEventAdapter::RELEASE): |
---|
182 | { |
---|
183 | if (ea.getButtonMask()==0) |
---|
184 | { |
---|
185 | |
---|
186 | double timeSinceLastRecordEvent = _ga_t0.valid() ? (ea.getTime() - _ga_t0->getTime()) : DBL_MAX; |
---|
187 | if (timeSinceLastRecordEvent>0.02) flushMouseEventStack(); |
---|
188 | |
---|
189 | if (isMouseMoving()) |
---|
190 | { |
---|
191 | if (calcMovement()) |
---|
192 | { |
---|
193 | us.requestRedraw(); |
---|
194 | us.requestContinuousUpdate(true); |
---|
195 | _thrown = true; |
---|
196 | } |
---|
197 | } |
---|
198 | else |
---|
199 | { |
---|
200 | flushMouseEventStack(); |
---|
201 | addMouseEvent(ea); |
---|
202 | if (calcMovement()) us.requestRedraw(); |
---|
203 | us.requestContinuousUpdate(false); |
---|
204 | _thrown = false; |
---|
205 | } |
---|
206 | |
---|
207 | } |
---|
208 | else |
---|
209 | { |
---|
210 | flushMouseEventStack(); |
---|
211 | addMouseEvent(ea); |
---|
212 | if (calcMovement()) us.requestRedraw(); |
---|
213 | us.requestContinuousUpdate(false); |
---|
214 | _thrown = false; |
---|
215 | } |
---|
216 | return true; |
---|
217 | } |
---|
218 | |
---|
219 | case(GUIEventAdapter::DRAG): |
---|
220 | { |
---|
221 | addMouseEvent(ea); |
---|
222 | if (calcMovement()) us.requestRedraw(); |
---|
223 | us.requestContinuousUpdate(false); |
---|
224 | _thrown = false; |
---|
225 | return true; |
---|
226 | } |
---|
227 | |
---|
228 | case(GUIEventAdapter::MOVE): |
---|
229 | { |
---|
230 | return false; |
---|
231 | } |
---|
232 | |
---|
233 | case(GUIEventAdapter::KEYDOWN): |
---|
234 | if (ea.getKey()==' ') |
---|
235 | { |
---|
236 | if (_autohoming) |
---|
237 | _autohoming=false; |
---|
238 | else |
---|
239 | _autohoming=true; |
---|
240 | return true; |
---|
241 | } |
---|
242 | if (ea.getKey()=='m') |
---|
243 | { |
---|
244 | switch(_trackerMode) |
---|
245 | { |
---|
246 | case NODE_CENTER: _trackerMode=NODE_CENTER_AND_AZIM; |
---|
247 | break; |
---|
248 | case NODE_CENTER_AND_AZIM: _trackerMode=NODE_CENTER_AND_ROTATION; |
---|
249 | break; |
---|
250 | case NODE_CENTER_AND_ROTATION: _trackerMode=NODE_CENTER; |
---|
251 | break; |
---|
252 | default: _trackerMode = NODE_CENTER; |
---|
253 | break; |
---|
254 | }; |
---|
255 | return true; |
---|
256 | } |
---|
257 | if (ea.getKey()=='n') |
---|
258 | { |
---|
259 | if (_distanceDependendAV) |
---|
260 | _distanceDependendAV=false; |
---|
261 | else |
---|
262 | _distanceDependendAV=true; |
---|
263 | return true; |
---|
264 | } |
---|
265 | return false; |
---|
266 | case(GUIEventAdapter::FRAME): |
---|
267 | if (_thrown) |
---|
268 | { |
---|
269 | if (calcMovement()) us.requestRedraw(); |
---|
270 | } |
---|
271 | |
---|
272 | computeHomePosition(); |
---|
273 | computePosition(_homeEye, _homeCenter, _homeUp); |
---|
274 | if (calcMovementSpaceMouse()) |
---|
275 | us.requestRedraw(); |
---|
276 | |
---|
277 | return false; |
---|
278 | default: |
---|
279 | return false; |
---|
280 | } |
---|
281 | } |
---|
282 | |
---|
283 | |
---|
284 | bool NodeTrackerSpaceMouse::isMouseMoving() |
---|
285 | { |
---|
286 | if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; |
---|
287 | |
---|
288 | static const float velocity = 0.1f; |
---|
289 | |
---|
290 | float dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized(); |
---|
291 | float dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized(); |
---|
292 | float len = sqrtf(dx*dx+dy*dy); |
---|
293 | float dt = _ga_t0->getTime()-_ga_t1->getTime(); |
---|
294 | |
---|
295 | return (len>dt*velocity); |
---|
296 | } |
---|
297 | |
---|
298 | |
---|
299 | void NodeTrackerSpaceMouse::flushMouseEventStack() |
---|
300 | { |
---|
301 | _ga_t1 = NULL; |
---|
302 | _ga_t0 = NULL; |
---|
303 | } |
---|
304 | |
---|
305 | |
---|
306 | void NodeTrackerSpaceMouse::addMouseEvent(const GUIEventAdapter& ea) |
---|
307 | { |
---|
308 | _ga_t1 = _ga_t0; |
---|
309 | _ga_t0 = &ea; |
---|
310 | } |
---|
311 | |
---|
312 | void NodeTrackerSpaceMouse::setByMatrix(const osg::Matrixd& matrix) |
---|
313 | { |
---|
314 | osg::Vec3d eye,center,up; |
---|
315 | matrix.getLookAt(eye,center,up,_distance); |
---|
316 | computePosition(eye,center,up); |
---|
317 | } |
---|
318 | |
---|
319 | void NodeTrackerSpaceMouse::computeNodeCenterAndRotation(osg::Vec3d& nodeCenter, osg::Quat& nodeRotation) const |
---|
320 | { |
---|
321 | osg::Matrixd localToWorld, worldToLocal; |
---|
322 | osg::NodePath nodePath; |
---|
323 | if (_trackNodePath.getNodePath(nodePath)) |
---|
324 | { |
---|
325 | worldToLocal = osg::computeWorldToLocal(nodePath); |
---|
326 | localToWorld = osg::computeLocalToWorld(nodePath); |
---|
327 | nodeCenter = osg::Vec3d(nodePath.back()->getBound().center())*localToWorld; |
---|
328 | } |
---|
329 | else |
---|
330 | { |
---|
331 | nodeCenter = osg::Vec3d(0.0f,0.0f,0.0f)*localToWorld; |
---|
332 | } |
---|
333 | |
---|
334 | |
---|
335 | switch(_trackerMode) |
---|
336 | { |
---|
337 | case(NODE_CENTER_AND_AZIM): |
---|
338 | { |
---|
339 | CoordinateFrame coordinateFrame = getCoordinateFrame(nodeCenter); |
---|
340 | osg::Matrixd localToFrame(localToWorld*osg::Matrixd::inverse(coordinateFrame)); |
---|
341 | |
---|
342 | double azim = atan2(-localToFrame(0,1),localToFrame(0,0)); |
---|
343 | osg::Quat nodeRotationRelToFrame, rotationOfFrame; |
---|
344 | nodeRotationRelToFrame.makeRotate(-azim,0.0,0.0,1.0); |
---|
345 | rotationOfFrame = coordinateFrame.getRotate(); |
---|
346 | nodeRotation = nodeRotationRelToFrame*rotationOfFrame; |
---|
347 | break; |
---|
348 | } |
---|
349 | case(NODE_CENTER_AND_ROTATION): |
---|
350 | { |
---|
351 | // scale the matrix to get rid of any scales before we extract the rotation. |
---|
352 | double sx = 1.0/sqrt(localToWorld(0,0)*localToWorld(0,0) + localToWorld(1,0)*localToWorld(1,0) + localToWorld(2,0)*localToWorld(2,0)); |
---|
353 | double sy = 1.0/sqrt(localToWorld(0,1)*localToWorld(0,1) + localToWorld(1,1)*localToWorld(1,1) + localToWorld(2,1)*localToWorld(2,1)); |
---|
354 | double sz = 1.0/sqrt(localToWorld(0,2)*localToWorld(0,2) + localToWorld(1,2)*localToWorld(1,2) + localToWorld(2,2)*localToWorld(2,2)); |
---|
355 | localToWorld = localToWorld*osg::Matrixd::scale(sx,sy,sz); |
---|
356 | |
---|
357 | nodeRotation = localToWorld.getRotate(); |
---|
358 | break; |
---|
359 | } |
---|
360 | case(NODE_CENTER): |
---|
361 | default: |
---|
362 | { |
---|
363 | CoordinateFrame coordinateFrame = getCoordinateFrame(nodeCenter); |
---|
364 | nodeRotation = coordinateFrame.getRotate(); |
---|
365 | break; |
---|
366 | } |
---|
367 | } |
---|
368 | |
---|
369 | } |
---|
370 | |
---|
371 | |
---|
372 | osg::Matrixd NodeTrackerSpaceMouse::getMatrix() const |
---|
373 | { |
---|
374 | osg::Vec3d nodeCenter; |
---|
375 | osg::Quat nodeRotation; |
---|
376 | computeNodeCenterAndRotation(nodeCenter,nodeRotation); |
---|
377 | return osg::Matrixd::translate(0.0,0.0,_distance)*osg::Matrixd::rotate(_rotation)*osg::Matrixd::rotate(nodeRotation)*osg::Matrix::translate(nodeCenter); |
---|
378 | } |
---|
379 | |
---|
380 | osg::Matrixd NodeTrackerSpaceMouse::getInverseMatrix() const |
---|
381 | { |
---|
382 | osg::Vec3d nodeCenter; |
---|
383 | osg::Quat nodeRotation; |
---|
384 | computeNodeCenterAndRotation(nodeCenter,nodeRotation); |
---|
385 | return osg::Matrixd::translate(-nodeCenter)*osg::Matrixd::rotate(nodeRotation.inverse())*osg::Matrixd::rotate(_rotation.inverse())*osg::Matrixd::translate(0.0,0.0,-_distance); |
---|
386 | } |
---|
387 | |
---|
388 | void NodeTrackerSpaceMouse::computePosition(const osg::Vec3d& eye,const osg::Vec3d& center,const osg::Vec3d& up) |
---|
389 | { |
---|
390 | if (!_node) return; |
---|
391 | |
---|
392 | // compute rotation matrix |
---|
393 | osg::Vec3 lv(center-eye); |
---|
394 | _distance = lv.length(); |
---|
395 | |
---|
396 | osg::Matrixd lookat; |
---|
397 | lookat.makeLookAt(eye,center,up); |
---|
398 | |
---|
399 | _rotation = lookat.getRotate().inverse(); |
---|
400 | } |
---|
401 | |
---|
402 | bool NodeTrackerSpaceMouse::calcMovement() |
---|
403 | { |
---|
404 | // return if less then two events have been added. |
---|
405 | if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; |
---|
406 | |
---|
407 | double dx = _ga_t0->getXnormalized()-_ga_t1->getXnormalized(); |
---|
408 | double dy = _ga_t0->getYnormalized()-_ga_t1->getYnormalized(); |
---|
409 | |
---|
410 | |
---|
411 | float distance = sqrtf(dx*dx + dy*dy); |
---|
412 | // return if movement is too fast, indicating an error in event values or change in screen. |
---|
413 | if (distance>0.5) |
---|
414 | { |
---|
415 | return false; |
---|
416 | } |
---|
417 | |
---|
418 | // return if there is no movement. |
---|
419 | if (distance==0.0f) |
---|
420 | { |
---|
421 | return false; |
---|
422 | } |
---|
423 | |
---|
424 | osg::Vec3d nodeCenter; |
---|
425 | osg::Quat nodeRotation; |
---|
426 | computeNodeCenterAndRotation(nodeCenter, nodeRotation); |
---|
427 | |
---|
428 | unsigned int buttonMask = _ga_t1->getButtonMask(); |
---|
429 | |
---|
430 | if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) |
---|
431 | { |
---|
432 | |
---|
433 | if (_rotationMode==TRACKBALL) |
---|
434 | { |
---|
435 | |
---|
436 | // rotate camera. |
---|
437 | osg::Vec3 axis; |
---|
438 | double angle; |
---|
439 | |
---|
440 | double px0 = _ga_t0->getXnormalized(); |
---|
441 | double py0 = _ga_t0->getYnormalized(); |
---|
442 | |
---|
443 | double px1 = _ga_t1->getXnormalized(); |
---|
444 | double py1 = _ga_t1->getYnormalized(); |
---|
445 | |
---|
446 | |
---|
447 | trackball(axis,angle,px1,py1,px0,py0); |
---|
448 | |
---|
449 | osg::Quat new_rotate; |
---|
450 | new_rotate.makeRotate(angle,axis); |
---|
451 | |
---|
452 | _rotation = _rotation*new_rotate; |
---|
453 | } |
---|
454 | else |
---|
455 | { |
---|
456 | osg::Matrix rotation_matrix; |
---|
457 | rotation_matrix.makeRotate(_rotation); |
---|
458 | |
---|
459 | osg::Vec3d lookVector = -getUpVector(rotation_matrix); |
---|
460 | osg::Vec3d sideVector = getSideVector(rotation_matrix); |
---|
461 | osg::Vec3d upVector = getFrontVector(rotation_matrix); |
---|
462 | |
---|
463 | osg::Vec3d localUp(0.0f,0.0f,1.0f); |
---|
464 | |
---|
465 | osg::Vec3d forwardVector = localUp^sideVector; |
---|
466 | sideVector = forwardVector^localUp; |
---|
467 | |
---|
468 | forwardVector.normalize(); |
---|
469 | sideVector.normalize(); |
---|
470 | |
---|
471 | osg::Quat rotate_elevation; |
---|
472 | rotate_elevation.makeRotate(dy,sideVector); |
---|
473 | |
---|
474 | osg::Quat rotate_azim; |
---|
475 | rotate_azim.makeRotate(-dx,localUp); |
---|
476 | |
---|
477 | _rotation = _rotation * rotate_elevation * rotate_azim; |
---|
478 | |
---|
479 | } |
---|
480 | |
---|
481 | return true; |
---|
482 | |
---|
483 | } |
---|
484 | else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON || |
---|
485 | buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON)) |
---|
486 | { |
---|
487 | return true; |
---|
488 | } |
---|
489 | else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON) |
---|
490 | { |
---|
491 | |
---|
492 | // zoom model. |
---|
493 | |
---|
494 | double fd = _distance; |
---|
495 | double scale = 1.0f+dy; |
---|
496 | if (fd*scale>_minimumDistance) |
---|
497 | { |
---|
498 | |
---|
499 | _distance *= scale; |
---|
500 | |
---|
501 | } else |
---|
502 | { |
---|
503 | _distance = _minimumDistance; |
---|
504 | } |
---|
505 | |
---|
506 | return true; |
---|
507 | |
---|
508 | } |
---|
509 | |
---|
510 | return false; |
---|
511 | } |
---|
512 | |
---|
513 | bool NodeTrackerSpaceMouse::calcMovementSpaceMouse() |
---|
514 | { |
---|
515 | // TRACKBALL mode is not possible, because it uses the mouseevent, which does not happen with Spacemouse. |
---|
516 | |
---|
517 | double dTX, dTY, dTZ; // Only TZ is used later. |
---|
518 | _spaceMouse->getTranslations(dTX, dTY, dTZ); |
---|
519 | |
---|
520 | double dRX, dRY, dRZ; |
---|
521 | _spaceMouse->getRotations(dRX, dRY, dRZ); |
---|
522 | |
---|
523 | //OSG_NOTIFY( osg::INFO ) << "Recieved Spacemousevalues: dRX:" << dRX << ", dRY:" << dRY << ", dRZ:" << dRZ << ", dTX:" << dTX << std::endl; |
---|
524 | |
---|
525 | if(!_ah_init) |
---|
526 | { |
---|
527 | TZ=dTZ; |
---|
528 | RX=dRX; |
---|
529 | RY=dRY; |
---|
530 | RZ=dRZ; |
---|
531 | _ah_init=true; |
---|
532 | } |
---|
533 | |
---|
534 | if (_autohoming) // The factors are required to allow macroscopic movements. |
---|
535 | { |
---|
536 | TZ=dTZ*5; |
---|
537 | if (!_distanceDependendAV) |
---|
538 | { |
---|
539 | RX=dRX*100; |
---|
540 | RY=dRY*100; |
---|
541 | RZ=dRZ*100; |
---|
542 | } |
---|
543 | } |
---|
544 | else // NOT Autohoming |
---|
545 | { |
---|
546 | TZ+=dTZ; |
---|
547 | //OSG_NOTIFY( osg::INFO ) << "Stored Spacemousevalues: RX:" << RX << ", RY:" << RY << ", RZ:" << RZ << ", TX:" << TX << std::endl; |
---|
548 | if (_distanceDependendAV) |
---|
549 | { |
---|
550 | RX+=(dRX*800/TZ); |
---|
551 | RY+=(dRY*800/TZ); |
---|
552 | RZ+=(dRZ*800/TZ); |
---|
553 | } |
---|
554 | else |
---|
555 | { |
---|
556 | RX+=dRX; |
---|
557 | RY+=dRY; |
---|
558 | RZ+=dRZ; |
---|
559 | } |
---|
560 | } |
---|
561 | |
---|
562 | osg::Vec3d nodeCenter; |
---|
563 | osg::Quat nodeRotation; |
---|
564 | computeNodeCenterAndRotation(nodeCenter, nodeRotation); |
---|
565 | |
---|
566 | // ROTATION PART |
---|
567 | if (_rotationMode==TRACKBALL) |
---|
568 | { |
---|
569 | // return if less then two events have been added. |
---|
570 | if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false; |
---|
571 | |
---|
572 | // rotate camera. |
---|
573 | osg::Vec3 axis; |
---|
574 | double angle; |
---|
575 | |
---|
576 | double px0 = _ga_t0->getXnormalized(); |
---|
577 | double py0 = _ga_t0->getYnormalized(); |
---|
578 | |
---|
579 | double px1 = _ga_t1->getXnormalized(); |
---|
580 | double py1 = _ga_t1->getYnormalized(); |
---|
581 | |
---|
582 | |
---|
583 | trackball(axis,angle,px1,py1,px0,py0); |
---|
584 | |
---|
585 | osg::Quat new_rotate; |
---|
586 | new_rotate.makeRotate(angle,axis); |
---|
587 | |
---|
588 | _rotation = _rotation*new_rotate; |
---|
589 | } |
---|
590 | else |
---|
591 | { |
---|
592 | osg::Matrix rotation_matrix; |
---|
593 | rotation_matrix.makeRotate(_rotation); |
---|
594 | |
---|
595 | osg::Vec3d lookVector = -getUpVector(rotation_matrix); |
---|
596 | osg::Vec3d sideVector = getSideVector(rotation_matrix); |
---|
597 | osg::Vec3d upVector = getFrontVector(rotation_matrix); |
---|
598 | |
---|
599 | osg::Vec3d localUp(0.0f,0.0f,1.0f); |
---|
600 | |
---|
601 | osg::Vec3d forwardVector = localUp^sideVector; |
---|
602 | sideVector = forwardVector^localUp; |
---|
603 | |
---|
604 | forwardVector.normalize(); |
---|
605 | sideVector.normalize(); |
---|
606 | |
---|
607 | osg::Quat rotate_elevation; |
---|
608 | rotate_elevation.makeRotate(osg::DegreesToRadians(RX*90), sideVector); |
---|
609 | |
---|
610 | osg::Quat rotate_azim; |
---|
611 | rotate_azim.makeRotate(osg::DegreesToRadians(RY*90), localUp); |
---|
612 | |
---|
613 | _rotation = _rotation * rotate_elevation * rotate_azim; |
---|
614 | |
---|
615 | } |
---|
616 | |
---|
617 | // TRANSLATION PART |
---|
618 | double scale = 1.0f+TZ/100; |
---|
619 | if (_distance*scale>_minimumDistance) |
---|
620 | { |
---|
621 | |
---|
622 | _distance *= scale; |
---|
623 | |
---|
624 | } else |
---|
625 | { |
---|
626 | TZ = (_minimumDistance/_distance - 1)*100; // Reset TZ to the value f(_minimalDistance, _distance, scale-function). |
---|
627 | _distance = _minimumDistance; |
---|
628 | } |
---|
629 | return true; |
---|
630 | } |
---|
631 | |
---|
632 | void NodeTrackerSpaceMouse::clampOrientation() |
---|
633 | { |
---|
634 | } |
---|
635 | |
---|
636 | |
---|
637 | /* |
---|
638 | * This size should really be based on the distance from the center of |
---|
639 | * rotation to the point on the object underneath the mouse. That |
---|
640 | * point would then track the mouse as closely as possible. This is a |
---|
641 | * simple example, though, so that is left as an Exercise for the |
---|
642 | * Programmer. |
---|
643 | */ |
---|
644 | const float TRACKBALLSIZE = 0.8f; |
---|
645 | |
---|
646 | /* |
---|
647 | * Ok, simulate a track-ball. Project the points onto the virtual |
---|
648 | * trackball, then figure out the axis of rotation, which is the cross |
---|
649 | * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0) |
---|
650 | * Note: This is a deformed trackball-- is a trackball in the center, |
---|
651 | * but is deformed into a hyperbolic sheet of rotation away from the |
---|
652 | * center. This particular function was chosen after trying out |
---|
653 | * several variations. |
---|
654 | * |
---|
655 | * It is assumed that the arguments to this routine are in the range |
---|
656 | * (-1.0 ... 1.0) |
---|
657 | */ |
---|
658 | void NodeTrackerSpaceMouse::trackball(osg::Vec3& axis,double & angle, double p1x, double p1y, double p2x, double p2y) |
---|
659 | { |
---|
660 | /* |
---|
661 | * First, figure out z-coordinates for projection of P1 and P2 to |
---|
662 | * deformed sphere |
---|
663 | */ |
---|
664 | |
---|
665 | osg::Matrix rotation_matrix(_rotation); |
---|
666 | |
---|
667 | |
---|
668 | osg::Vec3d uv = osg::Vec3d(0.0,1.0,0.0)*rotation_matrix; |
---|
669 | osg::Vec3d sv = osg::Vec3d(1.0,0.0,0.0)*rotation_matrix; |
---|
670 | osg::Vec3d lv = osg::Vec3d(0.0,0.0,-1.0)*rotation_matrix; |
---|
671 | |
---|
672 | osg::Vec3d p1 = sv*p1x+uv*p1y-lv*tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y); |
---|
673 | osg::Vec3d p2 = sv*p2x+uv*p2y-lv*tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y); |
---|
674 | |
---|
675 | /* |
---|
676 | * Now, we want the cross product of P1 and P2 |
---|
677 | */ |
---|
678 | |
---|
679 | // Robert, |
---|
680 | // |
---|
681 | // This was the quick 'n' dirty fix to get the trackball doing the right |
---|
682 | // thing after fixing the Quat rotations to be right-handed. You may want |
---|
683 | // to do something more elegant. |
---|
684 | // axis = p1^p2; |
---|
685 | axis = p2^p1; |
---|
686 | axis.normalize(); |
---|
687 | |
---|
688 | /* |
---|
689 | * Figure out how much to rotate around that axis. |
---|
690 | */ |
---|
691 | double t = (p2-p1).length() / (2.0*TRACKBALLSIZE); |
---|
692 | |
---|
693 | /* |
---|
694 | * Avoid problems with out-of-control values... |
---|
695 | */ |
---|
696 | if (t > 1.0) t = 1.0; |
---|
697 | if (t < -1.0) t = -1.0; |
---|
698 | angle = inRadians(asin(t)); |
---|
699 | |
---|
700 | } |
---|
701 | |
---|
702 | |
---|
703 | /* |
---|
704 | * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet |
---|
705 | * if we are away from the center of the sphere. |
---|
706 | */ |
---|
707 | double NodeTrackerSpaceMouse::tb_project_to_sphere(double r, double x, double y) |
---|
708 | { |
---|
709 | float d, t, z; |
---|
710 | |
---|
711 | d = sqrt(x*x + y*y); |
---|
712 | /* Inside sphere */ |
---|
713 | if (d < r * 0.70710678118654752440) |
---|
714 | { |
---|
715 | z = sqrt(r*r - d*d); |
---|
716 | } /* On hyperbola */ |
---|
717 | else |
---|
718 | { |
---|
719 | t = r / 1.41421356237309504880; |
---|
720 | z = t*t / d; |
---|
721 | } |
---|
722 | return z; |
---|
723 | } |
---|