Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
ManipulatorNode.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $Author$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49
50
51
52
53 //=============================================================================
54 //
55 // CLASS ManipulatorNode - IMPLEMENTATION
56 //
57 //=============================================================================
58
59
60 //== INCLUDES =================================================================
61
62
63 #include "ManipulatorNode.hh"
64
65
66 //== NAMESPACES ===============================================================
67
68
69 namespace ACG {
70 namespace SceneGraph {
71
72
73 //== IMPLEMENTATION ==========================================================
74
75
76 const Vec4f cylinder_color (0.8f, 0.4f, 0.4f, 1.0f);
77 const Vec4f sphere_color (0.8f, 0.4f, 0.4f, 1.0f);
78 const Vec4f select_color (1.0f, 0.1f, 0.1f, 1.0f);
79 const float SCALE_CONST = 5.0f;
80
81
82 //----------------------------------------------------------------------------
83
84
85 ManipulatorNode::
86 ManipulatorNode( BaseNode* _parent, const std::string& _name )
87 : TransformNode(_parent, _name),
88 draw_cylinder_(false),
89 direction_(1.0,0.0,0.0),
90 cylinder_(0),
91 cylinder_radius_(1),
92 cylinder_height_(10),
93 cylinder_slices_(30),
94 cylinder_stacks_(10),
95 cylinder_clicked_(false),
96 sphere_clicked_(false),
97 touched_(false)
98 {
99 }
100
101
102 //----------------------------------------------------------------------------
103
104
105 ManipulatorNode::
106 ~ManipulatorNode()
107 {
108 if (cylinder_)
109 delete cylinder_;
110 }
111
112
113 //----------------------------------------------------------------------------
114
115
116 void
117 ManipulatorNode::
118 setIdentity()
119 {
120 direction_ = rotation().transform_vector( direction_ );
121 TransformNode::setIdentity();
122 }
123
124
125 //----------------------------------------------------------------------------
126
127
128 void
129 ManipulatorNode::
130 setup_cylinder_system(GLState& _state)
131 {
132 _state.translate(center()[0], center()[1], center()[2]);
133 _state.mult_matrix(inverse_scale (), scale ()); // Adapt scaling
134
135 // rotation axis & angle
136 Vec3d z(0.0, 0.0, 1.0);
137 double scal_prod = (direction_ | z);
138 Vec3d axis = z % direction_;
139 double norm = axis.norm();
140 double angle;
141
142 if (norm > FLT_MIN)
143 {
144 axis /= norm;
145 if (scal_prod > 1.0) scal_prod = 1.0;
146 if (scal_prod < -1.0) scal_prod = -1.0;
147 angle = 180.0 / M_PI * acos(scal_prod);
148 }
149 else
150 {
151 axis = Vec3d(1.0, 0.0, 0.0);
152 angle = (scal_prod > 0.0) ? 0.0 : 180.0;
153 }
154
155 _state.rotate(angle, axis[0], axis[1], axis[2]);
156 }
157
158
159 void
160 ManipulatorNode::
161 setup_sphere_system(GLState& _state)
162 {
163 setup_cylinder_system(_state);
164
165 _state.translate(0, 0, cylinder_height_+ 2*cylinder_radius_);
166 }
167
168
169 //----------------------------------------------------------------------------
170
171
172 void
173 ManipulatorNode::draw(GLState& _state, const DrawModes::DrawMode& /* _drawMode */ )
174 {
175 if (draw_cylinder_)
176 {
177 ACG::GLState::enable(GL_LIGHTING);
178 ACG::GLState::shadeModel(GL_FLAT);
179
180
181 // backup colors
182 Vec4f backup_diffuse = _state.diffuse_color();
183 Vec4f backup_specular = _state.specular_color();
184
185
186 // draw cylinder
187
188 if (!cylinder_)
189 {
190 cylinder_ = new GLCylinder(cylinder_slices_, cylinder_stacks_, cylinder_radius_, false, false);
191 }
192
193 _state.push_modelview_matrix();
194 setup_cylinder_system(_state);
195
196 if( cylinder_clicked_)
197 {
198 _state.set_diffuse_color(select_color * 0.6f);
199 _state.set_specular_color(select_color * 0.8f);
200 }
201 else
202 {
203 _state.set_diffuse_color(cylinder_color * 0.6f);
204 _state.set_specular_color(cylinder_color * 0.8f);
205 }
206
207 // Zylinder in die X-Achse
208 /*glPushMatrix();
209 glLoadIdentity();
210 glRotatef(-90, 0.0, 1.0, 0.0);*/
211
212 ACG::GLState::shadeModel(GL_SMOOTH);
213 cylinder_->setBottomRadius(cylinder_radius_);
214 cylinder_->setTopRadius(cylinder_radius_);
215 cylinder_->draw(_state, cylinder_height_);
216
217 //glPopMatrix();
218
219
220 // BIG wireframe sphere
221 if( sphere_clicked_)
222 {
223 _state.set_diffuse_color(select_color * 0.6f);
224 _state.set_specular_color(select_color * 0.0f);
225 ACG::GLState::shadeModel(GL_SMOOTH);
226 glutWireSphere(cylinder_height_+4*cylinder_radius_, 20, 20);
227 }
228
229 _state.pop_modelview_matrix();
230
231
232
233
234 // draw sphere
235
236 _state.push_modelview_matrix();
237 setup_sphere_system(_state);
238
239 if( sphere_clicked_)
240 {
241 _state.set_diffuse_color(select_color * 0.6f);
242 _state.set_specular_color(select_color * 0.8f);
243 }
244 else
245 {
246 _state.set_diffuse_color(sphere_color * 0.6f);
247 _state.set_specular_color(sphere_color * 0.8f);
248 }
249
250 ACG::GLState::shadeModel(GL_SMOOTH);
251 glutSolidSphere(2*cylinder_radius_, 20, 20);
252
253 _state.pop_modelview_matrix();
254
255
256
257
258 // restore
259 _state.set_diffuse_color(backup_diffuse);
260 _state.set_specular_color(backup_specular);
261 }
262 }
263
264
265 //----------------------------------------------------------------------------
266
267
268 void
269 ManipulatorNode::mouseEvent(GLState& _state, QMouseEvent* _event)
270 {
271 Vec3d oldPoint3D;
272 Vec2i newPoint2D(_event->pos().x(), _event->pos().y());
273 Vec3d newPoint3D;
274 double new_axis_hit;
275
276
277 switch (_event->type())
278 {
279 case QEvent::MouseButtonPress:
280 {
281 // hit sphere ?
282 sphere_clicked_ = hitSphere(_state, newPoint2D);
283
284 // hit cylinder ?
285 cylinder_clicked_ = mapToCylinder(_state, newPoint2D, new_axis_hit);
286
287 // If the user clicked on the manipulator, remember it
288 if ( sphere_clicked_ || cylinder_clicked_)
289 touched_ = true;
290
291 // select only sphere or cylinder
292 if(sphere_clicked_ && cylinder_clicked_)
293 cylinder_clicked_ = false;
294
295 oldPoint2D_ = newPoint2D;
296 break;
297 }
298
299
300 case QEvent::MouseButtonRelease:
301 {
302 sphere_clicked_ = false;
303 cylinder_clicked_ = false;
304 break;
305 }
306
307
308 case QEvent::MouseButtonDblClick:
309 {
310 draw_cylinder_ = !draw_cylinder_;
311 break;
312 }
313
314
315 case QEvent::MouseMove:
316 {
317 // IF sphere clicked rotate or change direction
318 if(sphere_clicked_)
319 {
320 bool hit0 = mapToSphere(_state, newPoint2D, newPoint3D);
321 bool hit1 = mapToSphere(_state, oldPoint2D_, oldPoint3D);
322
323
324 if (hit0 && hit1)
325 {
326 // change direction
327 if(_event->modifiers() & Qt::ShiftModifier)
328 {
329
330 // calculate new cylinder direction
331 direction_.normalize();
332 newPoint3D.normalize();
333 oldPoint3D.normalize();
334
335 direction_ += newPoint3D - oldPoint3D;
336
337 }
338 // rotate
339 else
340 {
341 Vec3d axis = oldPoint3D % newPoint3D;
342 double cos_angle = ( oldPoint3D | newPoint3D );
343
344 if (fabs(cos_angle) < 1.0)
345 rotate(acos(cos_angle)*180.0/M_PI, axis);
346 }
347 }
348 else sphere_clicked_ = false;
349 }
350
351
352 // cylinder clicked change scaling or change translation
353 if(cylinder_clicked_)
354 {
355 double old_axis_hit;
356
357 mapToCylinder(_state, oldPoint2D_, old_axis_hit);
358 mapToCylinder(_state, newPoint2D, new_axis_hit);
359
360 // scale
361 if(_event->modifiers() & Qt::ShiftModifier)
362 {
363 scale(1.0 + (new_axis_hit - old_axis_hit) /
364 (cylinder_height_ * SCALE_CONST));
365 }
366
367 // twist
368 else if(_event->modifiers() & (Qt::ControlModifier |
369 Qt::AltModifier))
370 {
371 rotate( 45.0 * (new_axis_hit-old_axis_hit) / cylinder_height_,
372 direction_);
373
374 }
375
376 // translate
377 else
378 {
379 translate(new_axis_hit - old_axis_hit);
380 }
381 }
382
383 break;
384 }
385
386 default: // avoid warning
387 break;
388 }
389
390
391 // save old Point
392 oldPoint2D_ = newPoint2D;
393 }
394
395
396 //----------------------------------------------------------------------------
397
398
399 bool ManipulatorNode::hitSphere( GLState& _state,
400 const Vec2i& _v2)
401 {
402 // Qt -> GL coordinate systems
403 unsigned int x = _v2[0];
404 unsigned int y = _state.context_height() - _v2[1];
405
406
407 // get ray from eye through pixel, in sphere coords
408 Vec3d origin, direction;
409
410 _state.set_updateGL(false);
411 _state.push_modelview_matrix();
412
413 setup_sphere_system(_state);
414 _state.scale(2*cylinder_radius_);
415
416 _state.viewing_ray(x, y, origin, direction);
417
418 _state.pop_modelview_matrix();
419 _state.set_updateGL(true);
420
421
422
423 // calc sphere-ray intersection
424 // (sphere is centered at origin, has radius 1)
425 double a = direction.sqrnorm(),
426 b = 2.0 * (origin | direction),
427 c = origin.sqrnorm() - 1.0,
428 d = b*b - 4.0*a*c;
429
430 return (d >= 0.0);
431 }
432
433
434 //----------------------------------------------------------------------------
435
436
437 bool
438 ManipulatorNode::mapToSphere( GLState& _state,
439 const Vec2i& _v2,
440 Vec3d& _v3 )
441 {
442 // Qt -> GL coordinate systems
443 unsigned int x = _v2[0];
444 unsigned int y = _state.context_height() - _v2[1];
445
446
447
448 // get ray from eye through pixel (trackball coords)
449 // *no* rotation, points have to be in world coords
450 Vec3d origin, direction;
451
452 _state.set_updateGL(false);
453 _state.push_modelview_matrix();
454
455 _state.translate(center()[0], center()[1], center()[2]);
456 _state.mult_matrix(inverse_scale (), scale ());
457 _state.scale(cylinder_height_ + 4*cylinder_radius_);
458
459 _state.viewing_ray(x, y, origin, direction);
460
461 _state.pop_modelview_matrix();
462 _state.set_updateGL(true);
463
464
465
466 // calc sphere-ray intersection
467 // (sphere is centered at origin, has radius 1)
468 double a = direction.sqrnorm(),
469 b = 2.0 * (origin | direction),
470 c = origin.sqrnorm() - 1.0,
471 d = b*b - 4.0*a*c,
472 t;
473
474 if (d < 0.0) return false;
475 else if (d == 0.0) t = -b / (2.0*a);
476 else
477 {
478 a = 1.0 / (2.0*a);
479 d = sqrt(d);
480 double t1 = (-b - d) * a;
481 double t2 = (-b + d) * a;
482 t = (t1 < t2) ? t1 : t2;
483 }
484
485
486
487 // map back to world coords
488 _v3 = origin + direction*t;
489
490 return true;
491 }
492
493
494 //----------------------------------------------------------------------------
495
496
497 bool
498 ManipulatorNode::mapToCylinder(GLState& _state,
499 const Vec2i& _v1,
500 double& _axis_hit)
501 {
502 // Qt -> GL coordinate systems
503 unsigned int x = _v1[0];
504 unsigned int y = _state.context_height() - _v1[1];
505
506
507 // get ray from eye through pixel (cylinder coords)
508 Vec3d origin, direction;
509
510 _state.set_updateGL(false);
511 _state.push_modelview_matrix();
512
513 setup_cylinder_system(_state);
514
515 _state.viewing_ray(x, y, origin, direction);
516
517 _state.pop_modelview_matrix();
518 _state.set_updateGL(true);
519
520
521
522 // get cylinder axis ray: it's in its own coord system!
523 const Vec3d origin2(0,0,0), direction2(0,0,1);
524
525
526 // compute pseude-intersection
527 Vec3d normal = (direction % direction2).normalize();
528 Vec3d vd = ((origin2 - origin) % direction);
529 _axis_hit = (normal | vd);
530
531 double orthodistance = std::abs( ( origin2 - origin ) | normal);
532
533
534 // hit cylinder ?
535 return((orthodistance < cylinder_radius_) &&
536 (_axis_hit >= 0) &&
537 (_axis_hit <= cylinder_height_));
538 }
539
540
541 //----------------------------------------------------------------------------
542
543
544 void ManipulatorNode::pick(GLState& _state, PickTarget _target) {
545 if (_target == PICK_FACE || _target == PICK_ANYTHING) {
546 if (draw_cylinder_) {
547
548 _state.pick_set_maximum(2);
549
550 // cylinder
551 _state.push_modelview_matrix();
552 setup_cylinder_system(_state);
553 _state.pick_set_name(0);
554 cylinder_->setBottomRadius(cylinder_radius_);
555 cylinder_->setTopRadius(cylinder_radius_);
556 cylinder_->draw(_state, cylinder_height_);
557 _state.pop_modelview_matrix();
558
559 // sphere
560 _state.push_modelview_matrix();
561 setup_sphere_system(_state);
562 _state.pick_set_name(1);
563 glutSolidSphere(2* cylinder_radius_ , 20, 20);
564 _state.pop_modelview_matrix();
565 }
566 }
567 }
568
569
570 //----------------------------------------------------------------------------
571
572
573 void
574 ManipulatorNode::set_direction(Vec3d& _v)
575 {
576 direction_ = inverse_rotation().transform_vector(_v.normalize());
577 }
578
579
580 //----------------------------------------------------------------------------
581
582
583 Vec3d
584 ManipulatorNode::direction() const
585 {
586 return rotation().transform_vector(direction_);
587 }
588
589
590
591 //=============================================================================
592 } // namespace SceneGraph
593 } // namespace ACG
594 //=============================================================================
ACG::SceneGraph::ManipulatorNode::direction
Vec3d direction() const
Definition: ManipulatorNode.cc:584
ACG::GLState::scale
void scale(double _s)
scale by (_s, _s, _s)
Definition: GLState.hh:753
ACG::SceneGraph::ManipulatorNode::translate
void translate(double _s)
translate in cylinder direction
Definition: ManipulatorNode.hh:138
ACG
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
ACG::Vec2i
VectorT< signed int, 2 > Vec2i
Definition: VectorT.hh:104
ACG::SceneGraph::ACG::GLState::enable
static void enable(GLenum _cap)
replaces glEnable, but supports locking
ACG::GLState::context_height
int context_height() const
get gl context height
Definition: GLState.hh:833
ACG::SceneGraph::BaseNode
Definition: BaseNode.hh:135
ACG::GLState::pick_set_name
void pick_set_name(unsigned int _idx)
sets the current name/color (like glLoadName(_idx))
Definition: GLState.cc:1057
ACG::SceneGraph::ManipulatorNode::~ManipulatorNode
~ManipulatorNode()
Destructor.
Definition: ManipulatorNode.cc:106
ACG::SceneGraph::PickTarget
PickTarget
What target to use for picking.
Definition: BaseNode.hh:99
ACG::GLState::pick_set_maximum
bool pick_set_maximum(unsigned int _idx)
Set the maximal number of primitives/components of your object.
Definition: GLState.cc:1047
ACG::SceneGraph::PICK_FACE
picks faces (should be implemented for all nodes)
Definition: BaseNode.hh:104
ACG::SceneGraph::PICK_ANYTHING
pick any of the prior targets (should be implemented for all nodes)
Definition: BaseNode.hh:110
ACG::GLState::translate
void translate(double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
translate by (_x, _y, _z)
Definition: GLState.cc:531
ACG::GLState::rotate
void rotate(double _angle, double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
rotate around axis (_x, _y, _z) by _angle
Definition: GLState.cc:562
ACG::SceneGraph::TransformNode::inverse_scale
const GLMatrixd & inverse_scale() const
return inverse scale matrix
Definition: TransformNode.hh:185
ACG::SceneGraph::ACG::GLState::shadeModel
static void shadeModel(GLenum _mode)
replaces glShadeModel, supports locking
ACG::Vec3d
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
ACG::Matrix4x4T::transform_vector
VectorT< T, 3 > transform_vector(const VectorT< T, 3 > &_v) const
transform vector (x',y',z',0) = A * (x,y,z,0)
Definition: Matrix4x4T.cc:225
ACG::GLState
Definition: GLState.hh:220
ACG::GLState::set_diffuse_color
void set_diffuse_color(const Vec4f &_col)
set diffuse color
Definition: GLState.cc:720
ACG::SceneGraph::ManipulatorNode::touched_
bool touched_
if the manipulator is cklicked with a mouse, this flag will be set to true
Definition: ManipulatorNode.hh:191
ACG::SceneGraph::TransformNode::rotate
void rotate(double _angle, const Vec3d &_axis)
Definition: TransformNode.cc:143
ACG::SceneGraph::ManipulatorNode::pick
void pick(GLState &_state, PickTarget _target)
picking
Definition: ManipulatorNode.cc:544
ACG::SceneGraph::ManipulatorNode::ManipulatorNode
ManipulatorNode(BaseNode *_parent=0, const std::string &_name="<ManipulatorNode>")
Default constructor.
Definition: ManipulatorNode.cc:86
ACG::GLState::push_modelview_matrix
void push_modelview_matrix()
push modelview matrix
Definition: GLState.cc:1006
ACG::SceneGraph::ManipulatorNode::setIdentity
virtual void setIdentity()
Definition: ManipulatorNode.cc:118
ACG::SceneGraph::TransformNode::center
const Vec3d & center() const
get center
Definition: TransformNode.hh:121
ACG::SceneGraph::DrawModes::DrawMode
Specifies a DrawMode.
Definition: DrawModes.hh:294
ACG::GLState::mult_matrix
void mult_matrix(const GLMatrixd &_m, const GLMatrixd &_inv_m, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply by a given transformation matrix
Definition: GLState.cc:612
ACG::GLState::specular_color
const Vec4f & specular_color() const
get specular color
Definition: GLState.hh:944
OpenMesh::VectorT< float, 4 >
ACG::SceneGraph::TransformNode::scale
const GLMatrixd & scale() const
return scale matrix
Definition: TransformNode.hh:181
ACG::SceneGraph::TransformNode::inverse_rotation
const GLMatrixd & inverse_rotation() const
return inverse rotation matrix
Definition: TransformNode.hh:172
ACG::GLState::pop_modelview_matrix
void pop_modelview_matrix()
pop modelview matrix
Definition: GLState.cc:1022
ACG::GLState::set_updateGL
void set_updateGL(bool _b)
should GL matrices be updated after each matrix operation
Definition: GLState.hh:242
ACG::SceneGraph::ManipulatorNode::mouseEvent
virtual void mouseEvent(GLState &_state, QMouseEvent *_event)
get mouse events
Definition: ManipulatorNode.cc:269
ACG::SceneGraph::TransformNode::rotation
const GLMatrixd & rotation() const
return rotation matrix
Definition: TransformNode.hh:168
ACG::GLState::set_specular_color
void set_specular_color(const Vec4f &_col)
set specular color
Definition: GLState.cc:735
ACG::SceneGraph::TransformNode
Definition: TransformNode.hh:95
ACG::SceneGraph::ManipulatorNode::draw
void draw(GLState &_state, const DrawModes::DrawMode &_drawMode)
draw the cylinder (if enabled)
Definition: ManipulatorNode.cc:173
ACG::GLCylinder
Definition: GLPrimitives.hh:216
ACG::SceneGraph::ManipulatorNode::set_direction
void set_direction(Vec3d &_v)
Definition: ManipulatorNode.cc:574
ACG::SceneGraph::TransformNode::setIdentity
virtual void setIdentity()
Definition: TransformNode.cc:118
ACG::GLState::viewing_ray
void viewing_ray(int _x, int _y, Vec3d &_origin, Vec3d &_direction) const
Definition: GLState.cc:926
ACG::GLState::diffuse_color
const Vec4f & diffuse_color() const
get diffuse color
Definition: GLState.hh:939