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
TranslationManipulatorNode.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 TranslationManipulatorNode - IMPLEMENTATION
56 //
57 //=============================================================================
58
59
60 //== INCLUDES =================================================================
61
62
63 #include "TranslationManipulatorNode.hh"
64
65 #include <ACG/GL/IRenderer.hh>
66
67 #include <Math_Tools/Math_Tools.hh>
68
69 //== NAMESPACES ===============================================================
70
71
72 namespace ACG {
73 namespace SceneGraph {
74
75
76 //== IMPLEMENTATION ==========================================================
77
78 // How many pixels should the cursor be away from the dragging center
79 // for the translation operation to affect the geometry's position
80 #define SNAP_PIXEL_TOLERANCE 30
81
82 // Node colors (normal, over, clicked, occluded normal, occluded over, occluded clicked)
83
84 const Vec4f colors[4][6] = {
85 // origin
86 {
87 // normal
88 Vec4f(0.2f,0.2f,0.2f,1.0f), Vec4f(0.5f,0.5f,0.5f,1.0f), Vec4f(0.8f,0.8f,0.8f,1.0f),
89 // occluded
90 Vec4f(0.2f,0.2f,0.2f,0.2f), Vec4f(0.5f,0.5f,0.5f,0.4f), Vec4f(0.8f,0.8f,0.8f,0.6f)
91 },
92 // X
93 {
94 // normal
95 Vec4f(0.2f,0.0f,0.0f,1.0f), Vec4f(0.5f,0.0f,0.0f,1.0f), Vec4f(0.8f,0.0f,0.0f,1.0f),
96 // occluded
97 Vec4f(0.3f,0.1f,0.1f,0.2f), Vec4f(0.5f,0.2f,0.2f,0.4f), Vec4f(0.8f,0.4f,0.4f,0.6f)
98 },
99 // Y
100 {
101 // normal
102 Vec4f(0.0f,0.2f,0.0f,1.0f), Vec4f(0.0f,0.5f,0.0f,1.0f), Vec4f(0.0f,0.8f,0.0f,1.0f),
103 // occluded
104 Vec4f(0.1f,0.3f,0.1f,0.2f), Vec4f(0.2f,0.5f,0.2f,0.4f), Vec4f(0.4f,0.8f,0.4f,0.6f)
105 },
106 // Z
107 {
108 // normal
109 Vec4f(0.0f,0.0f,0.2f,1.0f), Vec4f(0.0f,0.0f,0.5f,1.0f), Vec4f(0.0f,0.0f,0.8f,1.0f),
110 // occluded
111 Vec4f(0.1f,0.1f,0.3f,0.2f), Vec4f(0.2f,0.2f,0.5f,0.4f), Vec4f(0.4f,0.4f,0.8f,0.6f)
112 }
113 };
114
115
116 //----------------------------------------------------------------------------
117
118 TranslationManipulatorNode::Element::Element () :
119 active_target_color_ (0.0, 0.0, 0.0, 1.0),
120 active_current_color_ (0.0, 0.0, 0.0, 1.0),
121 inactive_target_color_ (0.0, 0.0, 0.0, 1.0),
122 inactive_current_color_ (0.0, 0.0, 0.0, 1.0),
123 clicked_ (false),
124 over_ (false)
125 {
126 }
127
128 //----------------------------------------------------------------------------
129
130 TranslationManipulatorNode::
131 TranslationManipulatorNode( BaseNode* _parent, const std::string& _name )
132 : TransformNode(_parent, _name),
133 touched_(false),
134 draw_manipulator_(false),
135 dirX_(1.0,0.0,0.0),
136 dirY_(0.0,1.0,0.0),
137 dirZ_(0.0,0.0,1.0),
138 axisBottom_(0),
139 axisCenter_(0),
140 axisTop_(0),
141 circle_(0),
142 sphere_(0),
143 manipulator_radius_(20.0),
144 manipulator_height_(20),
145 set_manipulator_radius_(1.0),
146 set_manipulator_height_(1.0),
147 manipulator_slices_(10),
148 manipulator_stacks_(10),
149 any_axis_clicked_(false),
150 any_top_clicked_(false),
151 outer_ring_clicked_(false),
152 any_axis_over_(false),
153 any_top_over_(false),
154 outer_ring_over_(false),
155 resize_current_ (0.0),
156 mode_ (TranslationRotation),
157 ignoreTime_ (false),
158 dragging_(false),
159 auto_size_(TranslationManipulatorNode::Never),
160 auto_size_length_(1.0),
161 activeRotations_(ALL_AXIS)
162 {
163 localTransformation_.identity();
164
165 // Create GLPrimitives
166 axisBottom_ = new ACG::GLCone(manipulator_slices_, manipulator_stacks_,
167 (1.0 - resize_current_) * manipulator_radius_,
168 (1.0 + resize_current_) * manipulator_radius_, false, true);
169 axisCenter_ = new ACG::GLCone(manipulator_slices_, manipulator_stacks_,
170 (1.0 - resize_current_) * manipulator_radius_,
171 (1.0 + resize_current_) * manipulator_radius_, false, true);
172 axisTop_ = new ACG::GLCone(manipulator_slices_, manipulator_stacks_,
173 (1.0 - resize_current_) * manipulator_radius_,
174 (1.0 + resize_current_) * manipulator_radius_, false, true);
175
176 sphere_ = new ACG::GLSphere(manipulator_slices_, manipulator_stacks_);
177 circle_ = new ACG::GLDisk(30, 30, 2.0f*manipulator_height_ - manipulator_height_/4.0f, 2.0f*manipulator_height_);
178
179 setTraverseMode( BaseNode::ChildrenFirst );
180
181 updateTargetColors ();
182 for (unsigned int i = 0; i < TranslationManipulatorNode::NumElements; i++)
183 {
184 element_[i].active_current_color_ = element_[i].active_target_color_;
185 element_[i].inactive_current_color_ = element_[i].inactive_target_color_;
186 }
187 /*
188 setMultipassNode(0);
189 multipassNodeSetActive(2,true);
190
191 setMultipassStatus(0);
192 multipassStatusSetActive(1,true);
193 multipassStatusSetActive(2,true);*/
194
195 }
196
197
198 //----------------------------------------------------------------------------
199
200 TranslationManipulatorNode::~TranslationManipulatorNode() {
201
202 delete axisBottom_;
203 delete axisCenter_;
204 delete axisTop_;
205
206 delete sphere_;
207
208 delete circle_;
209 }
210
211
212 //----------------------------------------------------------------------------
213
214
215 void
216 TranslationManipulatorNode::
217 setIdentity()
218 {
219 TransformNode::setIdentity();
220 }
221
222
223 //----------------------------------------------------------------------------
224 void
225 TranslationManipulatorNode::
226 update_manipulator_system(GLState& _state)
227 {
228 _state.translate(center()[0], center()[1], center()[2]); // Follow translation of parent node
229 _state.mult_matrix(inverse_scale (), scale ()); // Adapt scaling
230
231 update_rotation(_state);
232 updateSize (_state);
233 }
234
235 //----------------------------------------------------------------------------
236 // Local rotation of the manipulator
237 void
238 TranslationManipulatorNode::update_rotation(GLState& _state){
239
240 // Get global transformation
241 glMatrixMode(GL_MODELVIEW);
242 GLMatrixd model = _state.modelview();
243
244 // revert global transformation as we want to use our own
245 model *= inverse_rotation();
246
247 // apply local transformation to adjust our coordinate system
248 model *= localTransformation_;
249
250 // And update current matrix
251 _state.set_modelview(model);
252
253 }
254
255 //----------------------------------------------------------------------------
256
257 void TranslationManipulatorNode::updateTargetColors ()
258 {
259 // reset all color to default values
260 element_[Origin].active_target_color_ = colors[0][0];
261 element_[XAxis].active_target_color_ = colors[1][0];
262 element_[YAxis].active_target_color_ = colors[2][0];
263 element_[ZAxis].active_target_color_ = colors[3][0];
264 element_[XTop].active_target_color_ = colors[1][0];
265 element_[YTop].active_target_color_ = colors[2][0];
266 element_[ZTop].active_target_color_ = colors[3][0];
267 element_[XRing].active_target_color_ = colors[1][0];
268 element_[YRing].active_target_color_ = colors[2][0];
269 element_[ZRing].active_target_color_ = colors[3][0];
270
271 element_[Origin].inactive_target_color_ = colors[0][3];
272 element_[XAxis].inactive_target_color_ = colors[1][3];
273 element_[YAxis].inactive_target_color_ = colors[2][3];
274 element_[ZAxis].inactive_target_color_ = colors[3][3];
275 element_[XTop].inactive_target_color_ = colors[1][3];
276 element_[YTop].inactive_target_color_ = colors[2][3];
277 element_[ZTop].inactive_target_color_ = colors[3][3];
278 element_[XRing].inactive_target_color_ = colors[1][3];
279 element_[YRing].inactive_target_color_ = colors[2][3];
280 element_[ZRing].inactive_target_color_ = colors[3][3];
281
282
283 // blending is enabled for ring so we have to set alpha correctly
284 element_[XRing].active_target_color_[3] = 1.0;
285 element_[YRing].active_target_color_[3] = 1.0;
286 element_[ZRing].active_target_color_[3] = 1.0;
287
288 // hide rings in resize mode
289 if (mode_ == Resize || mode_ == Place)
290 for (unsigned int i = 0; i < 3; i++)
291 {
292 element_[XRing + i].active_target_color_[3] = 0.0;
293 element_[XRing + i].inactive_target_color_[3] = 0.0;
294 }
295
296 // set colors according to current (clicked/over/none) state
297 if(element_[Origin].clicked_){
298 element_[Origin].active_target_color_ = colors[0][2];
299 element_[Origin].inactive_target_color_ = colors[0][5];
300 for (unsigned int i = 1; i < NumElements - 3; i++)
301 {
302 element_[i].active_target_color_ = (colors[0][2] * 0.5) + (colors[((i-1)%3) + 1][2] * 0.5);
303 element_[i].inactive_target_color_ = (colors[0][5] * 0.5) + (colors[((i-1)%3) + 1][5] * 0.5);
304 }
305 return;
306 } else if(element_[Origin].over_){
307 element_[Origin].active_target_color_ = colors[0][1];
308 element_[Origin].inactive_target_color_ = colors[0][4];
309 for (unsigned int i = 1; i < NumElements - 3; i++)
310 {
311 element_[i].active_target_color_ = (colors[0][1] * 0.5) + (colors[((i-1)%3) + 1][1] * 0.5);
312 element_[i].inactive_target_color_ = (colors[0][4] * 0.5) + (colors[((i-1)%3) + 1][4] * 0.5);
313 }
314 return;
315 }
316
317 for (unsigned int i = 0; i < 3; i++)
318 if (element_[i + XTop].clicked_)
319 {
320 element_[i + XTop].active_target_color_ = colors[i+1][2];
321 element_[i + XTop].inactive_target_color_ = colors[i+1][5];
322 if (mode_ != TranslationRotation)
323 {
324 element_[i + XAxis].active_target_color_ = colors[i+1][2];
325 element_[i + XAxis].inactive_target_color_ = colors[i+1][5];
326 }
327 if (mode_ != Resize) {
328 element_[i + XRing].active_target_color_ = colors[i+1][2];
329 element_[i + XRing].inactive_target_color_ = colors[i+1][5];
330 }
331 return;
332 } else if (element_[i + XTop].over_)
333 {
334 element_[i + XTop].active_target_color_ = colors[i+1][1];
335 element_[i + XTop].inactive_target_color_ = colors[i+1][4];
336 if (mode_ != TranslationRotation)
337 {
338 element_[i + XAxis].active_target_color_ = colors[i+1][1];
339 element_[i + XAxis].inactive_target_color_ = colors[i+1][4];
340 }
341 if (mode_ != Resize) {
342 element_[i + XRing].active_target_color_ = colors[i+1][1];
343 element_[i + XRing].inactive_target_color_ = colors[i+1][4];
344 }
345 return;
346 }
347
348 for (unsigned int i = 0; i < 3; i++)
349 if (element_[i + XAxis].clicked_)
350 {
351 element_[i + XTop].active_target_color_ = colors[i+1][2];
352 element_[i + XTop].inactive_target_color_ = colors[i+1][5];
353 element_[i + XAxis].active_target_color_ = colors[i+1][2];
354 element_[i + XAxis].inactive_target_color_ = colors[i+1][5];
355 if (mode_ == LocalRotation) {
356 element_[i + XRing].active_target_color_ = colors[i+1][2];
357 element_[i + XRing].inactive_target_color_ = colors[i+1][5];
358 }
359 return;
360 } else if (element_[i + XAxis].over_)
361 {
362 element_[i + XTop].active_target_color_ = colors[i+1][1];
363 element_[i + XTop].inactive_target_color_ = colors[i+1][4];
364 element_[i + XAxis].active_target_color_ = colors[i+1][1];
365 element_[i + XAxis].inactive_target_color_ = colors[i+1][4];
366 if (mode_ == LocalRotation) {
367 element_[i + XRing].active_target_color_ = colors[i+1][1];
368 element_[i + XRing].inactive_target_color_ = colors[i+1][4];
369 }
370 return;
371 }
372
373 if (mode_ != Resize) {
374 for (unsigned int i = 0; i < 3; i++) {
375 if (element_[i + XRing].clicked_)
376 {
377 element_[i + XRing].active_target_color_ = colors[i+1][2];
378 element_[i + XRing].inactive_target_color_ = colors[i+1][5];
379 return;
380 } else if (element_[i + XRing].over_)
381 {
382 element_[i + XRing].active_target_color_ = colors[i+1][1];
383 element_[i + XRing].inactive_target_color_ = colors[i+1][4];
384 return;
385 }
386 }
387 }
388
389 }
390
391 //----------------------------------------------------------------------------
392
393 bool TranslationManipulatorNode::updateCurrentColors (GLState& _state)
394 {
395 bool rv = false;
396
397 float value = (float)_state.msSinceLastRedraw () / 1000.0;
398
399 if (ignoreTime_)
400 {
401 value = 0;
402 ignoreTime_ = false;
403 }
404
405 for (unsigned int i = 0; i < NumElements; i++)
406 {
407 Vec4f diff = element_[i].active_target_color_ -
408 element_[i].active_current_color_;
409
410 for (unsigned int j = 0; j < 4; j++)
411 if (diff[j] > value)
412 diff[j] = value;
413 else if (diff[j] < -value)
414 diff[j] = -value;
415
416 element_[i].active_current_color_ += diff;
417
418 diff = element_[i].inactive_target_color_ -
419 element_[i].inactive_current_color_;
420
421 for (unsigned int j = 0; j < 4; j++)
422 if (diff[j] > value)
423 diff[j] = value;
424 else if (diff[j] < -value)
425 diff[j] = -value;
426
427 element_[i].inactive_current_color_ += diff;
428
429 rv |= element_[i].active_target_color_ != element_[i].active_current_color_ ||
430 element_[i].inactive_target_color_ != element_[i].inactive_current_color_;
431 }
432
433 float diff = ((mode_ == Resize) ? 1.0 : 0.0) - resize_current_;
434
435 if (diff > value)
436 diff = value;
437 else if (diff < -value)
438 diff = -value;
439
440 resize_current_ += diff;
441 rv |= resize_current_ != ((mode_ == Resize) ? 1.0 : 0.0);
442
443 return rv;
444 }
445
446 //----------------------------------------------------------------------------
447
448 void TranslationManipulatorNode::drawManipulator (GLState& _state, bool _active)
449 {
450 glPushAttrib(GL_ENABLE_BIT );
451 ACG::GLState::disable( GL_CULL_FACE );
452
453 // Save modelview matrix
454 _state.push_modelview_matrix();
455
456 //================================================================================================
457 // Sphere
458 //================================================================================================
459
460 // ACG::GLState::disable(GL_ALPHA_TEST);
461 // ACG::GLState::enable(GL_BLEND);
462 // ACG::GLState::enable(GL_CULL_FACE);
463 // glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
464 // ACG::GLState::enable(GL_COLOR_MATERIAL);
465 //
466 // ACG::GLState::blendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_DST_ALPHA);
467 //
468 // glColor4f( 1.0,0.0,0.0,0.3);
469 // gluSphere( axis_, manipulator_height_ * 1.5 , manipulator_slices_ * 2, manipulator_stacks_ * 2);
470 // ACG::GLState::disable(GL_COLOR_MATERIAL);
471 //
472 //
473 // ACG::GLState::enable(GL_ALPHA_TEST);
474 // ACG::GLState::disable(GL_BLEND);
475
476 //================================================================================================
477 // Z-Axis
478 //================================================================================================
479 // gluCylinder draws into z direction so z-Axis first
480
481 if (_active)
482 {
483 _state.set_diffuse_color(element_[ZAxis].active_current_color_);
484 _state.set_specular_color(element_[ZAxis].active_current_color_);
485 } else {
486 _state.set_diffuse_color(element_[ZAxis].inactive_current_color_);
487 _state.set_specular_color(element_[ZAxis].inactive_current_color_);
488 }
489
490 // Draw Bottom of z-axis
491 axisBottom_->setBottomRadius((1.0 - resize_current_) * manipulator_radius_);
492 axisBottom_->setTopRadius((1.0 + resize_current_) * manipulator_radius_);
493 axisBottom_->draw(_state, manipulator_height_/2.0);
494
495 // Draw center of z-axis
496 _state.translate(0.0, 0.0, manipulator_height_/2);
497
498 axisCenter_->setBottomRadius(manipulator_radius_);
499 axisCenter_->setTopRadius(manipulator_radius_);
500 axisCenter_->draw(_state, manipulator_height_/2.0);
501
502
503 // Draw Top of z-axis
504 if (_active)
505 {
506 _state.set_diffuse_color(element_[ZTop].active_current_color_);
507 _state.set_specular_color(element_[ZTop].active_current_color_);
508 } else {
509 _state.set_diffuse_color(element_[ZTop].inactive_current_color_);
510 _state.set_specular_color(element_[ZTop].inactive_current_color_);
511 }
512
513 _state.translate(0.0, 0.0, manipulator_height_/2);
514 axisTop_->setBottomRadius(manipulator_radius_*2.0);
515 axisTop_->setTopRadius(0.0);
516 axisTop_->draw(_state, manipulator_height_/2.0);
517 _state.translate(0.0, 0.0, -manipulator_height_);
518
519 //================================================================================================
520 // Y-Axis
521 //================================================================================================
522 _state.rotate(-90, 1.0, 0.0, 0.0);
523 if (_active)
524 {
525 _state.set_diffuse_color(element_[YAxis].active_current_color_);
526 _state.set_specular_color(element_[YAxis].active_current_color_);
527 } else {
528 _state.set_diffuse_color(element_[YAxis].inactive_current_color_);
529 _state.set_specular_color(element_[YAxis].inactive_current_color_);
530 }
531
532 // Draw Bottom of y-axis
533 axisBottom_->setBottomRadius((1.0 - resize_current_) * manipulator_radius_);
534 axisBottom_->setTopRadius((1.0 + resize_current_) * manipulator_radius_);
535 axisBottom_->draw(_state, manipulator_height_/2.0);
536
537 // Draw center of y-axis
538 _state.translate(0.0, 0.0, manipulator_height_/2);
539
540 axisCenter_->setBottomRadius(manipulator_radius_);
541 axisCenter_->setTopRadius(manipulator_radius_);
542 axisCenter_->draw(_state, manipulator_height_/2.0);
543
544
545 // Draw Top of y-axis
546 if (_active)
547 {
548 _state.set_diffuse_color(element_[YTop].active_current_color_);
549 _state.set_specular_color(element_[YTop].active_current_color_);
550 } else {
551 _state.set_diffuse_color(element_[YTop].inactive_current_color_);
552 _state.set_specular_color(element_[YTop].inactive_current_color_);
553 }
554
555 _state.translate(0.0, 0.0, manipulator_height_/2);
556 axisTop_->setBottomRadius(manipulator_radius_*2.0);
557 axisTop_->setTopRadius(0.0);
558 axisTop_->draw(_state, manipulator_height_/2.0);
559 _state.translate(0.0, 0.0, -manipulator_height_);
560
561
562 //================================================================================================
563 // X-Axis
564 //================================================================================================
565 _state.rotate(90, 0.0, 1.0, 0.0);
566 if (_active)
567 {
568 _state.set_diffuse_color(element_[XAxis].active_current_color_);
569 _state.set_specular_color(element_[XAxis].active_current_color_);
570 } else {
571 _state.set_diffuse_color(element_[XAxis].inactive_current_color_);
572 _state.set_specular_color(element_[XAxis].inactive_current_color_);
573 }
574
575 // Draw Bottom of x-axis
576 axisBottom_->setBottomRadius((1.0 - resize_current_) * manipulator_radius_);
577 axisBottom_->setTopRadius((1.0 + resize_current_) * manipulator_radius_);
578 axisBottom_->draw(_state, manipulator_height_/2.0);
579
580 // Draw center of x-axis
581 _state.translate(0.0, 0.0, manipulator_height_/2);
582
583 axisCenter_->setBottomRadius(manipulator_radius_);
584 axisCenter_->setTopRadius(manipulator_radius_);
585 axisCenter_->draw(_state, manipulator_height_/2.0);
586
587
588 // Draw Top of x-axis
589 if (_active)
590 {
591 _state.set_diffuse_color(element_[XTop].active_current_color_);
592 _state.set_specular_color(element_[XTop].active_current_color_);
593 } else {
594 _state.set_diffuse_color(element_[XTop].inactive_current_color_);
595 _state.set_specular_color(element_[XTop].inactive_current_color_);
596 }
597
598 _state.translate(0.0, 0.0, manipulator_height_/2);
599 axisTop_->setBottomRadius(manipulator_radius_*2.0);
600 axisTop_->setTopRadius(0.0);
601 axisTop_->draw(_state, manipulator_height_/2.0);
602 _state.translate(0.0, 0.0, -manipulator_height_);
603
604 //=================================================================================================
605 // Sphere
606 //=================================================================================================
607 if (_active)
608 {
609 _state.set_diffuse_color(element_[Origin].active_current_color_);
610 _state.set_specular_color(element_[Origin].active_current_color_);
611 } else {
612 _state.set_diffuse_color(element_[Origin].inactive_current_color_);
613 _state.set_specular_color(element_[Origin].inactive_current_color_);
614 }
615
616 sphere_->draw(_state, manipulator_radius_*2);
617
618 //=================================================================================================
619 // Outer-Rings
620 //=================================================================================================
621
622 ACG::GLState::enable (GL_BLEND);
623 glPushAttrib(GL_LIGHTING_BIT);
624 ACG::GLState::disable(GL_LIGHTING);
625
626 // update circle size
627 circle_->setInnerRadius(2.0f*manipulator_height_ - manipulator_height_/4.0f);
628 circle_->setOuterRadius(2.0f*manipulator_height_);
629
630 if ( activeRotations_ & X_AXIS) {
631 if (_active)
632 {
633 _state.set_diffuse_color(element_[XRing].active_current_color_);
634 _state.set_ambient_color(element_[XRing].active_current_color_);
635 _state.set_color(element_[XRing].active_current_color_);
636
637 } else {
638 _state.set_diffuse_color(element_[XRing].inactive_current_color_);
639 _state.set_ambient_color(element_[XRing].inactive_current_color_);
640 _state.set_color(element_[XRing].inactive_current_color_);
641
642 }
643
644 circle_->draw(_state);
645 }
646
647
648 _state.rotate(90, 0.0, 1.0, 0.0);
649 if ( activeRotations_ & Y_AXIS) {
650 if (_active)
651 {
652 _state.set_diffuse_color(element_[YRing].active_current_color_);
653 _state.set_ambient_color(element_[YRing].active_current_color_);
654 _state.set_color(element_[YRing].active_current_color_);
655
656 } else {
657 _state.set_diffuse_color(element_[YRing].inactive_current_color_);
658 _state.set_ambient_color(element_[YRing].inactive_current_color_);
659 _state.set_color(element_[YRing].inactive_current_color_);
660
661 }
662
663 circle_->draw(_state);
664 }
665
666 _state.rotate(90, 1.0, 0.0, 0.0);
667 if ( activeRotations_ & Z_AXIS) {
668 if (_active)
669 {
670 _state.set_diffuse_color(element_[ZRing].active_current_color_);
671 _state.set_ambient_color(element_[ZRing].active_current_color_);
672 _state.set_color(element_[ZRing].active_current_color_);
673
674 } else {
675 _state.set_diffuse_color(element_[ZRing].inactive_current_color_);
676 _state.set_ambient_color(element_[ZRing].inactive_current_color_);
677 _state.set_color(element_[ZRing].inactive_current_color_);
678
679 }
680
681 circle_->draw(_state);
682 }
683
684 glPopAttrib(); // ENABLE_BIT
685 glPopAttrib(); // LIGHTING_BIT
686
687
688 _state.pop_modelview_matrix();
689 }
690
691 //----------------------------------------------------------------------------
692
693
694 void
695 TranslationManipulatorNode::draw(GLState& _state, const DrawModes::DrawMode& /* _drawMode */ )
696 {
697 GLenum prev_depth = _state.depthFunc();
698
699 if (draw_manipulator_) {
700
701 // Store lighting bits and enable lighting
702 glPushAttrib(GL_LIGHTING_BIT);
703 ACG::GLState::enable(GL_LIGHTING);
704 ACG::GLState::shadeModel(GL_SMOOTH);
705
706 // Store original depth status
707 glPushAttrib(GL_DEPTH_BUFFER_BIT);
708
709
710 // Alpha Test things
711 glPushAttrib(GL_COLOR_BUFFER_BIT);
712
713 glPushAttrib(GL_ENABLE_BIT);
714
715 // backup colors
716 Vec4f backup_diffuse = _state.diffuse_color();
717 Vec4f backup_specular = _state.specular_color();
718
719
720 // Correctly align nodes local coordinate system
721 update_manipulator_system(_state);
722
723 updateTargetColors ();
724 if (updateCurrentColors (_state))
725 setDirty ();
726
727 ACG::GLState::enable(GL_DEPTH_TEST);
728 ACG::GLState::depthFunc(GL_GREATER);
729 glDepthMask(GL_FALSE);
730 ACG::GLState::enable (GL_BLEND);
731 ACG::GLState::blendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
732 drawManipulator(_state, false);
733 ACG::GLState::disable (GL_BLEND);
734
735 ACG::GLState::depthFunc(GL_LEQUAL);
736 glDepthMask(GL_TRUE);
737 drawManipulator(_state, true);
738
739 // Restore old attributes and modelview
740 glPopAttrib();
741 glPopAttrib();
742 glPopAttrib();
743 glPopAttrib();
744
745 // restore active colors
746 _state.set_diffuse_color(backup_diffuse);
747 _state.set_specular_color(backup_specular);
748
749 ACG::GLState::depthFunc(prev_depth);
750 }
751 }
752
753 //----------------------------------------------------------------------------
754
755 GLMatrixd TranslationManipulatorNode::computeWorldMatrix()
756 {
757 GLMatrixd world;
758 world.identity();
759
760 world.translate(center()[0], center()[1], center()[2]); // Follow translation of parent node
761 world *= inverse_scale();
762
763 // revert global transformation as we want to use our own
764 world *= inverse_rotation();
765
766 // apply local transformation to adjust our coordinate system
767 world *= localTransformation_;
768
769 return world;
770 }
771
772 //----------------------------------------------------------------------------
773
774 void TranslationManipulatorNode::getRenderObjects(IRenderer* _renderer,
775 GLState& _state,
776 const DrawModes::DrawMode& _drawMode,
777 const Material* _mat)
778 {
779 if (draw_manipulator_)
780 {
781 RenderObject ro;
782 ro.initFromState(&_state);
783
784 // compute model-view matrix for the center of manipulator
785 ro.modelview *= computeWorldMatrix();
786 updateSize(_state);
787
788 updateTargetColors ();
789 if (updateCurrentColors (_state))
790 setDirty ();
791
792
793 // unlit, use emissive color only
794 ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
795 ro.shaderDesc.vertexColors = false;
796 ro.shaderDesc.clearTextures();
797
798 // we need the scene zbuffer for the transparent overdraw effect
799 // -> defer as long as possible
800 ro.priority = 1000;
801
802 // 1st pass
803 // draw occluded areas on top via alpha blending
804 ro.depthTest = true;
805 ro.depthFunc = GL_GREATER;
806 ro.depthWrite = false;
807
808 ro.blending = true;
809 ro.blendSrc = GL_SRC_ALPHA;
810 ro.blendDest = GL_ONE_MINUS_SRC_ALPHA;
811 ro.alpha = 0.5f;
812
813 addManipulatorToRenderer(_renderer, &ro, false);
814
815 // 2nd pass
816 // draw rest as usual
817 ro.priority = 1001;
818 ro.blending = false;
819 ro.depthFunc = GL_LEQUAL;
820 ro.depthWrite = true;
821 addManipulatorToRenderer(_renderer, &ro, true);
822 }
823 }
824
825 //----------------------------------------------------------------------------
826
827 void TranslationManipulatorNode::addAxisToRenderer (IRenderer* _renderer, RenderObject* _baseRO, bool _active, int _axis)
828 {
829 assert(_axis >= XAxis && _axis - 3 >= 0 && _axis <= ZAxis);
830
831 for (int i = 0; i < 3; ++i)
832 _baseRO->emissive[i] = _active ? element_[_axis].active_current_color_[i] : element_[_axis].inactive_current_color_[i];
833
834 // Draw Bottom
835 axisBottom_->setBottomRadius((1.0 - resize_current_) * manipulator_radius_);
836 axisBottom_->setTopRadius((1.0 + resize_current_) * manipulator_radius_);
837 axisBottom_->addToRenderer(_renderer, _baseRO, manipulator_height_/2.0f);
838
839 // Draw center
840 _baseRO->modelview.translate(0.0, 0.0, manipulator_height_/2);
841
842 axisCenter_->setBottomRadius(manipulator_radius_);
843 axisCenter_->setTopRadius(manipulator_radius_);
844 axisCenter_->addToRenderer(_renderer, _baseRO, manipulator_height_/2.0f);
845
846
847 // Draw top
848
849 // _axis - 3 computes id of axis-top in 'Elements' enum
850 for (int i = 0; i < 3; ++i)
851 _baseRO->emissive[i] = _active ? (element_[_axis-3].active_current_color_[i]) : (element_[_axis-3].inactive_current_color_[i]);
852
853 _baseRO->modelview.translate(0.0, 0.0, manipulator_height_/2);
854 axisTop_->setBottomRadius(manipulator_radius_*2.0);
855 axisTop_->setTopRadius(0.0);
856 axisTop_->addToRenderer(_renderer, _baseRO, manipulator_height_/2.0f);
857 _baseRO->modelview.translate(0.0, 0.0, -manipulator_height_);
858
859 }
860
861 //----------------------------------------------------------------------------
862
863 void TranslationManipulatorNode::addManipulatorToRenderer (IRenderer* _renderer, RenderObject* _baseRO, bool _active)
864 {
865 _baseRO->culling = false;
866
867 GLMatrixd oldModelview = _baseRO->modelview;
868
869 //================================================================================================
870 // Z-Axis
871 //================================================================================================
872 // gluCylinder draws into z direction so z-Axis first
873
874 addAxisToRenderer(_renderer, _baseRO, _active, ZAxis);
875
876 //================================================================================================
877 // Y-Axis
878 //================================================================================================
879
880 _baseRO->modelview.rotate(-90, 1.0, 0.0, 0.0);
881 addAxisToRenderer(_renderer, _baseRO, _active, YAxis);
882
883 //================================================================================================
884 // X-Axis
885 //================================================================================================
886
887 _baseRO->modelview.rotate(90, 0.0, 1.0, 0.0);
888 addAxisToRenderer(_renderer, _baseRO, _active, XAxis);
889
890 //=================================================================================================
891 // Sphere
892 //=================================================================================================
893
894 for (int i = 0; i < 3; ++i)
895 _baseRO->emissive[i] = _active ? (element_[Origin].active_current_color_[i]) : (element_[Origin].inactive_current_color_[i]);
896
897 sphere_->addToRenderer(_renderer, _baseRO, manipulator_radius_ * 2.0f);
898
899 //=================================================================================================
900 // Outer-Rings
901 //=================================================================================================
902
903 // _baseRO->blending = true;
904
905 // update circle size
906 circle_->setInnerRadius(2.0f*manipulator_height_ - manipulator_height_/4.0f);
907 circle_->setOuterRadius(2.0f*manipulator_height_);
908
909 if ( activeRotations_ & X_AXIS)
910 {
911 for (int i = 0; i < 3; ++i)
912 _baseRO->emissive[i] = _active ? (element_[XRing].active_current_color_[i]) : (element_[XRing].inactive_current_color_[i]);
913
914 circle_->addToRenderer_primitive(_renderer, _baseRO);
915 }
916
917
918 _baseRO->modelview.rotate(90, 0.0, 1.0, 0.0);
919 if ( activeRotations_ & Y_AXIS)
920 {
921 for (int i = 0; i < 3; ++i)
922 _baseRO->emissive[i] = _active ? (element_[YRing].active_current_color_[i]) : (element_[YRing].inactive_current_color_[i]);
923 circle_->addToRenderer_primitive(_renderer, _baseRO);
924 }
925
926 _baseRO->modelview.rotate(90, 1.0, 0.0, 0.0);
927 if ( activeRotations_ & Z_AXIS)
928 {
929 for (int i = 0; i < 3; ++i)
930 _baseRO->emissive[i] = _active ? (element_[ZRing].active_current_color_[i]) : (element_[ZRing].inactive_current_color_[i]);
931 circle_->addToRenderer_primitive(_renderer, _baseRO);
932 }
933
934 _baseRO->modelview = oldModelview;
935 }
936
937 //----------------------------------------------------------------------------
938
939 // void
940 // TranslationManipulatorNode::leave(GLState& _state, const DrawModes::DrawMode& /* _drawMode */ )
941 // {
942
943 // }
944
945 //----------------------------------------------------------------------------
946
947 void
948 TranslationManipulatorNode::mouseEvent(GLState& _state, QMouseEvent* _event)
949 {
950 if (!draw_manipulator_)
951 return; // Avoid transformation of object while transformator is invisible
952
953 Vec3d oldPoint3D;
954 Vec2i newPoint2D(_event->pos().x(), _event->pos().y());
955 Vec3d newPoint3D;
956 bool rot[3], trans[3];
957 unsigned int i;
958 bool lockOldPoint = false;
959
960 updateSize(_state);
961
962 switch (_event->type()) {
963
964 // If mouse is pressed check if any part of the manipulator is hit and store that state
965 case QEvent::MouseButtonPress: {
966 for (i = 0; i < NumElements; i++)
967 element_[i].clicked_ = false;
968
969 // Start dragging process
970 if (!dragging_) {
971 draggingOrigin3D_ = center();
972 dragging_ = true;
973 }
974
975 // hit origin ?
976 if ((mode_ != LocalRotation) && (mode_ != Rotation))
977 element_[Origin].clicked_ = hitSphere(_state, newPoint2D);
978 else
979 element_[Origin].clicked_ = false;
980
981 // hit any top ?
982 any_top_clicked_ = mapToCylinderTop(_state, newPoint2D, Click);
983
984 // hit any axis ?
985 any_axis_clicked_ = mapToCylinder(_state, newPoint2D, Click);
986
987 // hit one of the outer rings ?
988 if (mode_ != Resize)
989 outer_ring_clicked_ = mapToSphere(_state, newPoint2D, newPoint3D, Click);
990 else
991 outer_ring_clicked_ = false;
992
993 // origin has been hit, ignore all other parts
994 if (element_[Origin].clicked_) {
995 for (i = 1; i < NumElements; i++)
996 element_[i].clicked_ = false;
997 any_axis_clicked_ = false;
998 any_top_clicked_ = false;
999 outer_ring_clicked_ = false;
1000 } else if (any_top_clicked_) { // tops override the axes
1001 for (i = XAxis; i < NumElements; i++)
1002 element_[i].clicked_ = false;
1003 any_axis_clicked_ = false;
1004 outer_ring_clicked_ = false;
1005 } else if (any_axis_clicked_) { // axes have been hit, disable rest ... should not be required
1006 for (i = XRing; i < NumElements; i++)
1007 element_[i].clicked_ = false;
1008 outer_ring_clicked_ = false;
1009 } else if (outer_ring_clicked_) { // Nothing except the outer ring has been hit
1010 for (i = 0; i < XRing; i++)
1011 element_[i].clicked_ = false;
1012 any_axis_clicked_ = false;
1013 any_top_clicked_ = false;
1014 }
1015
1016 // Reset local transformation:
1017 if ( (_event->modifiers() & Qt::ControlModifier) && (_event->modifiers() & Qt::AltModifier) ) {
1018 localTransformation_.identity();
1019 }
1020
1021 oldPoint2D_ = newPoint2D;
1022 currentScale_ = Vec3d(1.0, 1.0, 1.0);
1023 ignoreTime_ = true;
1024
1025 touched_ = element_[Origin].clicked_
1026 || any_top_clicked_
1027 || any_axis_clicked_
1028 || outer_ring_clicked_;
1029 break;
1030 }
1031
1032 // Reset all states as we stopped manipulating
1033 case QEvent::MouseButtonRelease: {
1034
1035 for (i = 0; i < NumElements; i++) {
1036 if (element_[i].clicked_)
1037 touched_ = true;
1038 element_[i].clicked_ = false;
1039 }
1040
1041 touched_ = touched_
1042 || any_top_clicked_
1043 || any_axis_clicked_
1044 || outer_ring_clicked_;
1045
1046 any_axis_clicked_ = false;
1047 any_top_clicked_ = false;
1048 outer_ring_clicked_ = false;
1049 ignoreTime_ = true;
1050 dragging_ = false;
1051 break;
1052 }
1053
1054 case QEvent::MouseButtonDblClick: {
1055 draw_manipulator_ = !draw_manipulator_;
1056 break;
1057 }
1058
1059 // All real manipulation is done here
1060 case QEvent::MouseMove: {
1061 if (!draw_manipulator_) {
1062 touched_ = false;
1063 return; // Avoid manipulation if manipulator is invisible
1064 }
1065
1066 // Get pressed modifiers
1067 Qt::KeyboardModifiers mods = Qt::ShiftModifier | Qt::ControlModifier;
1068
1069 for (i = 0; i < NumElements; i++)
1070 element_[i].over_ = false;
1071 any_axis_over_ = false;
1072 any_top_over_ = false;
1073 outer_ring_over_ = false;
1074
1075 if (!(element_[Origin].clicked_ || any_top_clicked_ || any_axis_clicked_ || outer_ring_clicked_)) {
1076 // over origin ?
1077 if ((mode_ != LocalRotation) && (mode_ != Rotation))
1078 element_[Origin].over_ = hitSphere(_state, newPoint2D);
1079 else
1080 element_[Origin].over_ = false;
1081
1082
1083 // over any top ?
1084 if (mode_ != Place) {
1085 any_top_over_ = mapToCylinderTop(_state, newPoint2D, Over);
1086 }
1087
1088 // over any axis ?
1089 if (mode_ != Place) {
1090 any_axis_over_ = mapToCylinder(_state, newPoint2D, Over);
1091 }
1092
1093 // over one of the outer rings ?
1094 if (mode_ != Resize) {
1095 outer_ring_over_ = mapToSphere(_state, newPoint2D, newPoint3D, Over);
1096 } else {
1097 outer_ring_over_ = false;
1098 }
1099
1100 // origin has been hit, ignore all other parts
1101 if (element_[Origin].over_) {
1102 for (i = 1; i < NumElements; i++)
1103 element_[i].over_ = false;
1104 any_axis_over_ = false;
1105 any_top_over_ = false;
1106 outer_ring_over_ = false;
1107 } else if (any_top_over_) { // tops override the axes
1108 for (i = XAxis; i < NumElements; i++)
1109 element_[i].over_ = false;
1110 any_axis_over_ = false;
1111 outer_ring_over_ = false;
1112 } else if (any_axis_over_) { // axes have been hit, disable rest ... should not be required
1113 for (i = XRing; i < NumElements; i++)
1114 element_[i].over_ = false;
1115 outer_ring_over_ = false;
1116 } else if (outer_ring_over_) { // Nothing except the outer ring has been hit
1117 for (i = 0; i < XRing; i++)
1118 element_[i].over_ = false;
1119 any_axis_over_ = false;
1120 any_top_over_ = false;
1121 }
1122 }
1123
1124 // set action for the different modes
1125 switch (mode_) {
1126 case Rotation:
1127 for (i = 0; i < 3; i++) {
1128 rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_;
1129 trans[i] = false;
1130 }
1131 break;
1132 case TranslationRotation:
1133 for (i = 0; i < 3; i++) {
1134 rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_;
1135 trans[i] = element_[XAxis + i].clicked_;
1136 }
1137 break;
1138 case LocalRotation:
1139 for (i = 0; i < 3; i++) {
1140 rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_ || element_[XAxis + i].clicked_;
1141 trans[i] = false;
1142 }
1143 break;
1144 case Place:
1145 break;
1146 case Resize:
1147 for (i = 0; i < 3; i++) {
1148 rot[i] = false;
1149 trans[i] = element_[XTop + i].clicked_ || element_[XAxis + i].clicked_;
1150 }
1151 break;
1152 }
1153
1154 // If origin was clicked on
1155 if (element_[Origin].clicked_) {
1156
1157 // translate along screen plane ( unproject to get world coords for translation and apply them )
1158
1159 Vec3d d = _state.project(center());
1160 Vec3d d_origin = _state.project(draggingOrigin3D_);
1161
1162 // Snap back to origin position if mouse cursor
1163 // is near enough
1164 if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1165 && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1166 && (_event->modifiers() & Qt::AltModifier) ) {
1167 newPoint2D = oldPoint2D_;
1168 Vec3d backtrans = draggingOrigin3D_ - center();
1169 if (mode_ != Resize) {
1170 translate(backtrans);
1171 }
1172 }
1173
1174 // translate along screen plane ( unproject to get world coords for translation and apply them )
1175 Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1176 Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1177 Vec3d ntrans = newvec - oldvec;
1178
1179 if (mode_ != Resize)
1180 translate(ntrans);
1181 else {
1182 // revert last scale
1183 scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1184 double positive = -1;
1185 if (newPoint2D[0] - oldPoint2D_[0] + oldPoint2D_[1] - newPoint2D[1] > 0)
1186 positive = 1;
1187
1188 Vec2d div = Vec2d(newPoint2D[0], newPoint2D[1]) - Vec2d(oldPoint2D_[0], oldPoint2D_[1]);
1189
1190 double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1191 scaleValue *= positive;
1192 currentScale_ += Vec3d(scaleValue, scaleValue, scaleValue);
1193
1194 scale(currentScale_);
1195 }
1196
1197 touched_ = true;
1198 }
1199
1200 // x axis clicked apply translation along axis
1201 if (trans[0]) {
1202
1203 mapToCylinder(_state, oldPoint2D_);
1204 mapToCylinder(_state, newPoint2D);
1205
1206 // translate
1207 // Get screen coordinates of current mouse position and unproject them
1208 // into world coordinates. Project onto selected axis and apply resulting
1209 // vector as translation
1210
1211 Vec3d d = _state.project(center());
1212 Vec3d d_origin = _state.project(draggingOrigin3D_);
1213
1214 // Snap back to origin position if mouse cursor
1215 // is near enough
1216 if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1217 && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1218 && (_event->modifiers() & Qt::AltModifier) ) {
1219 newPoint2D = oldPoint2D_;
1220 Vec3d backtrans = draggingOrigin3D_ - center();
1221 if (mode_ != Resize) {
1222 translate(backtrans);
1223 }
1224 }
1225 Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1226 Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1227 Vec3d ntrans = newvec - oldvec;
1228
1229 // project to current direction
1230 ntrans = (ntrans | directionX()) * directionX();
1231
1232 if (mode_ == Resize) {
1233 //scaling
1234 double positive = -1;
1235 if ((directionX() | ntrans) > 0)
1236 positive = 1;
1237
1238 if (currentScale_[0] < 0)
1239 positive *= -1;
1240
1241 Vec3d proj = _state.project(ntrans + oldvec);
1242
1243 Vec2d div = Vec2d(proj[0], proj[1]) - Vec2d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
1244
1245 double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1246 scaleValue *= positive;
1247
1248 // revert last scale
1249 GLMatrixd m = localTransformation_;
1250 GLMatrixd mi = localTransformation_;
1251 mi.invert();
1252
1253 m.scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1254 m *= mi;
1255
1256 scale(m);
1257
1258 currentScale_ += Vec3d(scaleValue, 0.0, 0.0);
1259
1260 m = localTransformation_;
1261 m.scale(currentScale_);
1262 m *= mi;
1263
1264 scale(m);
1265 } else
1266 //translation
1267 translate(ntrans);
1268
1269 touched_ = true;
1270 }
1271
1272 // y axis clicked change translation along axis
1273 if (trans[1]) {
1274
1275 mapToCylinder(_state, oldPoint2D_);
1276 mapToCylinder(_state, newPoint2D);
1277
1278 // translate
1279 // Get screen coordinates of current mouse position and unproject them
1280 // into world coordinates. Project onto selected axis and apply resulting
1281 // vector as translation
1282
1283 Vec3d d = _state.project(center());
1284 Vec3d d_origin = _state.project(draggingOrigin3D_);
1285
1286 // Snap back to origin position if mouse cursor
1287 // is near enough
1288 if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1289 && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1290 && (_event->modifiers() & Qt::AltModifier) ) {
1291 newPoint2D = oldPoint2D_;
1292 Vec3d backtrans = draggingOrigin3D_ - center();
1293 if (mode_ != Resize) {
1294 translate(backtrans);
1295 }
1296 }
1297 Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1298 Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1299 Vec3d ntrans = newvec - oldvec;
1300
1301 // project to current direction
1302 ntrans = (ntrans | directionY()) * directionY();
1303
1304 if (mode_ == Resize) {
1305 //scaling
1306 double positive = -1;
1307 if ((directionY() | ntrans) > 0)
1308 positive = 1;
1309
1310 if (currentScale_[1] < 0)
1311 positive *= -1;
1312
1313 Vec3d proj = _state.project(ntrans + oldvec);
1314
1315 Vec2d div = Vec2d(proj[0], proj[1]) - Vec2d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
1316
1317 double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1318 scaleValue *= positive;
1319
1320 // revert last scale
1321 GLMatrixd m = localTransformation_;
1322 GLMatrixd mi = localTransformation_;
1323 mi.invert();
1324
1325 m.scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1326 m *= mi;
1327
1328 scale(m);
1329
1330 currentScale_ += Vec3d(0.0, scaleValue, 0.0);
1331
1332 m = localTransformation_;
1333 m.scale(currentScale_);
1334 m *= mi;
1335
1336 scale(m);
1337
1338 } else
1339 //translation
1340 translate(ntrans);
1341
1342 touched_ = true;
1343 }
1344
1345 // z axis clicked change translation along axis
1346 if (trans[2]) {
1347
1348 mapToCylinder(_state, oldPoint2D_);
1349 mapToCylinder(_state, newPoint2D);
1350
1351 // translate
1352 // Get screen coordinates of current mouse position and unproject them
1353 // into world coordinates. Project onto selected axis and apply resulting
1354 // vector as translation
1355
1356 Vec3d d = _state.project(center());
1357 Vec3d d_origin = _state.project(draggingOrigin3D_);
1358
1359 // Snap back to origin position if mouse cursor
1360 // is near enough
1361 if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1362 && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1363 && (_event->modifiers() & Qt::AltModifier) ) {
1364 newPoint2D = oldPoint2D_;
1365 Vec3d backtrans = draggingOrigin3D_ - center();
1366 if (mode_ != Resize) {
1367 translate(backtrans);
1368 }
1369 }
1370 Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1371 Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1372 Vec3d ntrans = newvec - oldvec;
1373
1374 // project to current direction
1375 ntrans = (ntrans | directionZ()) * directionZ();
1376
1377 if (mode_ == Resize) {
1378 //scaling
1379 double positive = -1;
1380 if ((directionZ() | ntrans) > 0)
1381 positive = 1;
1382
1383 if (currentScale_[2] < 0)
1384 positive *= -1;
1385
1386 Vec3d proj = _state.project(ntrans + oldvec);
1387
1388 Vec2d div = Vec2d(proj[0], proj[1]) - Vec2d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
1389
1390 double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1391 scaleValue *= positive;
1392
1393 // revert last scale
1394 GLMatrixd m = localTransformation_;
1395 GLMatrixd mi = localTransformation_;
1396 mi.invert();
1397
1398 m.scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1399 m *= mi;
1400
1401 scale(m);
1402
1403 currentScale_ += Vec3d(0.0, 0.0, scaleValue);
1404
1405 m = localTransformation_;
1406 m.scale(currentScale_);
1407 m *= mi;
1408
1409 scale(m);
1410
1411 } else
1412 //translation
1413 translate(ntrans);
1414
1415 touched_ = true;
1416 }
1417
1418 // x top clicked: rotate around x axis
1419 if (rot[0] && (activeRotations_ & X_AXIS)) {
1420
1421 mapToCylinder(_state, oldPoint2D_);
1422 mapToCylinder(_state, newPoint2D);
1423
1424 Vec2i dist = oldPoint2D_ - newPoint2D;
1425 int rotation = 0;
1426
1427 // Rasterize movement if shift is pressed
1428 if (_event->modifiers() == mods) {
1429 if (abs(dist[1]) < (int) (_state.viewport_height() / 16)) {
1430 rotation = 0;
1431 lockOldPoint = true;
1432 } else {
1433 // Rotate exactly 45 degrees
1434 if (dist[1] < 0)
1435 rotation = -45;
1436 else
1437 rotation = 45;
1438 ;
1439 }
1440 } else {
1441 rotation = dist[1];
1442 }
1443
1444 // Shift has been pressed
1445 // Rotate manipulator but not parent node
1446 if (mode_ == LocalRotation) {
1447
1448 // Update only local rotation
1449 localTransformation_.rotate(-rotation, directionX(), ACG::MULT_FROM_LEFT);
1450
1451 } else {
1452 // Rotate parent node but not manipulator
1453 _state.push_modelview_matrix();
1454 _state.translate(center()[0], center()[1], center()[2]);
1455 update_rotation(_state);
1456
1457 rotate(rotation, directionX());
1458
1459 _state.pop_modelview_matrix();
1460 }
1461
1462 touched_ = true;
1463 }
1464
1465 // y top clicked: rotate around y axis
1466 // or outer ring on zx axis has been clicked
1467 if (rot[1] && (activeRotations_ & Y_AXIS)) {
1468
1469 mapToCylinder(_state, oldPoint2D_);
1470 mapToCylinder(_state, newPoint2D);
1471
1472 Vec2i dist = oldPoint2D_ - newPoint2D;
1473 int rotation = 0;
1474
1475 // Rasterize movement if shift is pressed
1476 if (_event->modifiers() == mods) {
1477 if (abs(dist[1]) < (int) (_state.viewport_width() / 16)) {
1478 rotation = 0;
1479 lockOldPoint = true;
1480 } else {
1481 // Rotate exactly 45 degrees
1482 if (dist[1] < 0)
1483 rotation = -45;
1484 else
1485 rotation = 45;
1486 ;
1487 }
1488 } else {
1489 rotation = dist[1];
1490 }
1491
1492 if (mode_ == LocalRotation) {
1493
1494 // Update only local rotation
1495 localTransformation_.rotate(-rotation, directionY(), ACG::MULT_FROM_LEFT);
1496
1497 } else {
1498 _state.push_modelview_matrix();
1499 _state.translate(center()[0], center()[1], center()[2]);
1500
1501 rotate(rotation, directionY());
1502
1503 _state.pop_modelview_matrix();
1504 }
1505
1506 touched_ = true;
1507 }
1508
1509 // z top clicked: rotate around z axis
1510 if (rot[2] && (activeRotations_ & Z_AXIS)) {
1511
1512 mapToCylinder(_state, oldPoint2D_);
1513 mapToCylinder(_state, newPoint2D);
1514
1515 Vec2i dist = oldPoint2D_ - newPoint2D;
1516
1517 int rotation = 0;
1518
1519 // Rasterize movement if shift is pressed
1520 if (_event->modifiers() == mods) {
1521 if (abs(dist[1]) < (int) (_state.viewport_width() / 16)) {
1522 rotation = 0;
1523 lockOldPoint = true;
1524 } else {
1525 // Rotate exactly 45 degrees
1526 if (dist[1] < 0)
1527 rotation = 45;
1528 else
1529 rotation = -45;
1530 ;
1531 }
1532 } else {
1533 rotation = -dist[1];
1534 }
1535
1536 if (mode_ == LocalRotation) {
1537
1538 // Update only local rotation
1539 localTransformation_.rotate(-rotation, directionZ(), ACG::MULT_FROM_LEFT); // (dist[0]+dist[1])/2
1540
1541 } else {
1542 _state.push_modelview_matrix();
1543 _state.translate(center()[0], center()[1], center()[2]);
1544
1545 rotate(rotation, directionZ());
1546
1547 _state.pop_modelview_matrix();
1548 }
1549
1550 touched_ = true;
1551 }
1552
1553 break;
1554 }
1555
1556 default: // avoid warning
1557 break;
1558 }
1559
1560 setDirty();
1561
1562 // save old Point
1563 if (!lockOldPoint)
1564 oldPoint2D_ = newPoint2D;
1565 }
1566
1567
1568 //----------------------------------------------------------------------------
1569
1571 bool TranslationManipulatorNode::hitSphere( GLState& _state,
1572 const Vec2i& _v2)
1573 {
1574 // Qt -> GL coordinate systems
1575 unsigned int x = _v2[0];
1576 unsigned int y = _state.context_height() - _v2[1];
1577
1578
1579 // get ray from eye through pixel, in sphere coords
1580 Vec3d origin, direction;
1581
1582 _state.set_updateGL(false);
1583 _state.push_modelview_matrix();
1584
1585 update_manipulator_system(_state);
1586 _state.scale(2*manipulator_radius_);
1587
1588 _state.viewing_ray(x, y, origin, direction);
1589
1590 _state.pop_modelview_matrix();
1591 _state.set_updateGL(true);
1592
1593
1594
1595 // calc sphere-ray intersection
1596 // (sphere is centered at origin, has radius 1)
1597 double a = direction.sqrnorm(),
1598 b = 2.0 * (origin | direction),
1599 c = origin.sqrnorm() - 1.0,
1600 d = b*b - 4.0*a*c;
1601
1602 return (d >= 0.0);
1603 }
1604
1605
1606 //------------------------------------------------------------------------------------
1607
1608
1610
1611 bool TranslationManipulatorNode::hitOuterSphere( GLState& _state,
1612 const Vec2i& _v2)
1613 {
1614 // Qt -> GL coordinate systems
1615 unsigned int x = _v2[0];
1616 unsigned int y = _state.context_height() - _v2[1];
1617
1618
1619 // get ray from eye through pixel, in sphere coords
1620 Vec3d origin, direction;
1621
1622 _state.set_updateGL(false);
1623 _state.push_modelview_matrix();
1624
1625 update_manipulator_system(_state);
1626 _state.scale(manipulator_height_+4*manipulator_radius_);
1627
1628 _state.viewing_ray(x, y, origin, direction);
1629
1630 _state.pop_modelview_matrix();
1631 _state.set_updateGL(true);
1632
1633
1634 // calc sphere-ray intersection
1635 // (sphere is centered at origin, has radius 1)
1636 double a = direction.sqrnorm(),
1637 b = 2.0 * (origin | direction),
1638 c = origin.sqrnorm() - 1.0,
1639 d = b*b - 4.0*a*c;
1640
1641 return (d >= 0.0);
1642 }
1643
1644
1645 //------------------------------------------------------------------------------------
1646
1647
1650 bool
1651 TranslationManipulatorNode::mapToCylinder( GLState& _state,
1652 const Vec2i& _v1,
1653 StateUpdates _updateStates )
1654 {
1655 // Qt -> GL coordinate systems
1656 unsigned int x = _v1[0];
1657 unsigned int y = _state.context_height() - _v1[1];
1658
1659
1660 // get ray from eye through pixel (cylinder coords)
1661 Vec3d originX, directionX;
1662 Vec3d originY, directionY;
1663 Vec3d originZ, directionZ;
1664
1665 _state.set_updateGL(false);
1666 _state.push_modelview_matrix();
1667
1668 // Now that we have 3 different axes we have to test intersection with each of them
1669 // Z-Axis:
1670 update_manipulator_system(_state);
1671 _state.viewing_ray(x, y, originZ, directionZ);
1672
1673 // Y-Axis:
1674 _state.rotate(-90, 1.0, 0.0, 0.0);
1675 _state.viewing_ray(x, y, originY, directionY);
1676
1677 // X-Axis:
1678 _state.rotate(90, 0.0, 1.0, 0.0);
1679 _state.viewing_ray(x, y, originX, directionX);
1680
1681 _state.pop_modelview_matrix();
1682 _state.set_updateGL(true);
1683
1684
1685 // get cylinder axis ray: it's in its own coord system!
1686 // Viewing ray function unprojects screen coordinates thorugh inverse viewport, projection and modelview
1687 // such that we end in local coordinate system of the manipulator.
1688 // local transformation of the manipulator is included in update_manipulator_system which applies the
1689 // local transformation to the current glstate used by viewing_ray
1690 const Vec3d origin2(0,0,0),
1691 cylinderAxis(0.0, 0.0, 1.0); // Always same but we change the coordinate system for the viewer
1692
1693
1694 // compute pseude-intersection (x axis)
1695 Vec3d normalX = (directionX % cylinderAxis).normalize();
1696 Vec3d vdX = ((origin2 - originX) % directionX);
1697 double axis_hitX = (normalX | vdX);
1698 double orthodistanceX = std::abs( ( origin2 - originX ) | normalX);
1699
1700 // compute pseude-intersection (y axis)
1701 Vec3d normalY = (directionY % cylinderAxis).normalize();
1702 Vec3d vdY = ((origin2 - originY) % directionY);
1703 double axis_hitY = (normalY | vdY);
1704 double orthodistanceY = std::abs( ( origin2 - originY ) | normalY);
1705
1706 // compute pseude-intersection (z axis)
1707 Vec3d normalZ = (directionZ % cylinderAxis).normalize();
1708 Vec3d vdZ = ((origin2 - originZ) % directionZ);
1709 double axis_hitZ = (normalZ | vdZ);
1710 double orthodistanceZ = std::abs( ( origin2 - originZ ) | normalZ);
1711
1712 if ( _updateStates == None )
1713 return false;
1714
1715 if ( ( orthodistanceX < manipulator_radius_ ) &&
1716 ( axis_hitX >= 0 ) &&
1717 ( axis_hitX <= manipulator_height_ ) )
1718 {
1719
1720 // z axis has been hit
1721 if ( _updateStates == Click)
1722 element_[XAxis].clicked_ = true;
1723 else
1724 element_[XAxis].over_ = true;
1725
1726 } else if ( ( orthodistanceY < manipulator_radius_ ) &&
1727 ( axis_hitY >= 0 ) &&
1728 ( axis_hitY <= manipulator_height_))
1729 {
1730
1731 // y axis has been hit
1732 if ( _updateStates == Click)
1733 element_[YAxis].clicked_ = true;
1734 else
1735 element_[YAxis].over_ = true;
1736
1737 } else if ( ( orthodistanceZ < manipulator_radius_ ) &&
1738 ( axis_hitZ >= 0 ) &&
1739 ( axis_hitZ <= manipulator_height_ ) )
1740 {
1741 // x axis has been hit
1742 if ( _updateStates == Click)
1743 element_[ZAxis].clicked_ = true;
1744 else
1745 element_[ZAxis].over_ = true;
1746
1747 }
1748
1749 if ( _updateStates == Click)
1750 return (element_[XAxis].clicked_ || element_[YAxis].clicked_ || element_[ZAxis].clicked_);
1751
1752 return (element_[XAxis].over_ || element_[YAxis].over_ || element_[ZAxis].over_);
1753 }
1754
1755
1756 //----------------------------------------------------------------------------
1759 // This method treats the top as cylinder
1760 // TODO: Adapt intersection test to cone shape
1761 bool
1762 TranslationManipulatorNode::mapToCylinderTop( GLState& _state,
1763 const Vec2i& _v1,
1764 StateUpdates _updateStates )
1765 {
1766 // Qt -> GL coordinate systems
1767 unsigned int x = _v1[0];
1768 unsigned int y = _state.context_height() - _v1[1];
1769
1770
1771 // get ray from eye through pixel (cylinder coords)
1772 Vec3d originX, directionX;
1773 Vec3d originY, directionY;
1774 Vec3d originZ, directionZ;
1775
1776 _state.set_updateGL(false);
1777 _state.push_modelview_matrix();
1778
1779 // Z-Axis:
1780 update_manipulator_system(_state);
1781 _state.translate( 0.0, 0.0, manipulator_height_);
1782 _state.viewing_ray(x, y, originZ, directionZ);
1783 _state.translate( 0.0, 0.0, -manipulator_height_);
1784
1785 // Y-Axis:
1786 _state.rotate(-90, 1.0, 0.0, 0.0);
1787 _state.translate(0.0, 0.0 , manipulator_height_ );
1788 _state.viewing_ray(x, y, originY, directionY);
1789 _state.translate(0.0, 0.0, -manipulator_height_);
1790
1791 // X-Axis:
1792 _state.rotate(90, 0.0, 1.0, 0.0);
1793 _state.translate(0.0, 0.0, manipulator_height_);
1794 _state.viewing_ray(x, y, originX, directionX);
1795 _state.translate(0.0, 0.0, -manipulator_height_);
1796
1797 _state.pop_modelview_matrix();
1798 _state.set_updateGL(true);
1799
1800
1801 // get cylinder axis ray: it's in its own coord system!
1802 // Viewing ray function unprojects screen coordinates thorugh inverse viewport, projection and modelview
1803 // such that we end in local coordinate system of the manipulator.
1804 // local transformation of the manipulator is included in update_manipulator_system which applies the
1805 // local transformation to the current glstate used by viewing_ray
1806 const Vec3d origin2(0,0,0),
1807 cylinderAxis(0.0, 0.0, 1.0);
1808
1809 // compute pseude-intersection (x axis)
1810 Vec3d normalX = (directionX % cylinderAxis).normalize();
1811 Vec3d vdX = ((origin2 - originX) % directionX );
1812 double axis_hitX = (normalX | vdX);
1813 double orthodistanceX = std::abs( ( origin2 - originX ) | normalX);
1814
1815 // compute pseude-intersection (y axis)
1816 Vec3d normalY = (directionY % cylinderAxis).normalize();
1817 Vec3d vdY = ((origin2 - originY) % directionY);
1818 double axis_hitY = (normalY | vdY);
1819 double orthodistanceY = std::abs( ( origin2 - originY ) | normalY);
1820
1821 // compute pseude-intersection (z axis)
1822 Vec3d normalZ = (directionZ % cylinderAxis).normalize();
1823 Vec3d vdZ = ((origin2 - originZ) % directionZ);
1824 double axis_hitZ = (normalZ | vdZ);
1825 double orthodistanceZ = std::abs( ( origin2 - originZ ) | normalZ);
1826
1827 if ( _updateStates == None )
1828 return false;
1829
1830 // TODO: Work with cones :
1831
1832 if ( ( orthodistanceX < manipulator_radius_ * 2.0 ) &&
1833 ( axis_hitX >= 0.0 ) &&
1834 ( axis_hitX <= manipulator_height_ / 2.0 ) )
1835 {
1836
1837 // z top has been hit
1838 if ( _updateStates == Click)
1839 element_[XTop].clicked_ = true;
1840 else
1841 element_[XTop].over_ = true;
1842
1843 } else if ( ( orthodistanceY < manipulator_radius_ * 2.0 ) &&
1844 ( axis_hitY >= 0.0 ) &&
1845 ( axis_hitY <= manipulator_height_ / 2.0 ) )
1846 {
1847
1848 // y top has been hit
1849 if ( _updateStates == Click)
1850 element_[YTop].clicked_ = true;
1851 else
1852 element_[YTop].over_ = true;
1853
1854 } else if ( ( orthodistanceZ < manipulator_radius_ * 2.0 ) &&
1855 ( axis_hitZ >= 0.0 ) &&
1856 ( axis_hitZ <= manipulator_height_ / 2.0 ) )
1857 {
1858
1859 // x top has been hit
1860 if ( _updateStates == Click)
1861 element_[ZTop].clicked_ = true;
1862 else
1863 element_[ZTop].over_ = true;
1864
1865 }
1866
1867 if ( _updateStates == Click)
1868 return (element_[XTop].clicked_ || element_[YTop].clicked_ || element_[ZTop].clicked_);
1869 return (element_[XTop].over_ || element_[YTop].over_ || element_[ZTop].over_);
1870 }
1871
1872 //----------------------------------------------------------------------------
1873
1877 bool
1878 TranslationManipulatorNode::mapToSphere( GLState& _state,
1879 const Vec2i& _v2,
1880 Vec3d& _v3,
1881 StateUpdates _updateStates)
1882 {
1883 // Qt -> GL coordinate systems
1884 unsigned int x = _v2[0];
1885 unsigned int y = _state.context_height() - _v2[1];
1886
1887 // get ray from eye through pixel
1888 Vec3d originXY, directionXY,
1889 originYZ, directionYZ,
1890 originZX, directionZX;
1891
1892 _state.set_updateGL(false);
1893 _state.push_modelview_matrix();
1894
1895 update_manipulator_system(_state);
1896
1897 _state.viewing_ray(x, y, originXY, directionXY);
1898 _state.rotate(90, 0.0, 1.0, 0.0);
1899 _state.viewing_ray(x, y, originYZ, directionYZ);
1900 _state.rotate(90, 1.0, 0.0, 0.0);
1901 _state.viewing_ray(x, y, originZX, directionZX);
1902
1903 _state.pop_modelview_matrix();
1904 _state.set_updateGL(true);
1905
1906 // origin + direction * t = (x, y, 0) <=> t = -origin_z / direction_z
1907 // => Point on xy-plane p = (origin_x + direction_x*t, origin_y + direction_y*t, 0)
1908 double t1 = -originXY[2]/directionXY[2];
1909 Vec3d hitPointXY = originXY + directionXY*t1;
1910
1911 double t2 = -originYZ[2]/directionYZ[2];
1912 Vec3d hitPointYZ = originYZ + directionYZ*t2;
1913
1914 double t3 = -originZX[2]/directionZX[2];
1915 Vec3d hitPointZX = originZX + directionZX*t3;
1916
1917 // Depth test: Take nearest object
1918 bool t1_near = false, t2_near = false, t3_near = false;
1919 if( t1 <= t2 && t1 <= t3)
1920 t1_near = true;
1921 if( t2 <= t1 && t2 <= t3)
1922 t2_near = true;
1923 if( t3 <= t1 && t3 <= t2)
1924 t3_near = true;
1925
1926 bool xy_hit = hitPointXY.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
1927 hitPointXY.length() < 2*manipulator_height_;
1928
1929 bool yz_hit = hitPointYZ.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
1930 hitPointYZ.length() < 2*manipulator_height_;
1931
1932 bool zx_hit = hitPointZX.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
1933 hitPointZX.length() < 2*manipulator_height_;
1934
1935
1936 bool more_than_one_hit = (xy_hit && yz_hit) || (xy_hit && zx_hit) || (yz_hit && zx_hit);
1937 // std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
1938 // hitPointXY << " < " << 2*manipulator_height_ << std::endl;
1939 //
1940 // std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
1941 // hitPointYZ << " < " << 2*manipulator_height_ << std::endl;
1942 //
1943 // std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
1944 // hitPointZX << " < " << 2*manipulator_height_ << std::endl;
1945
1946 // Test if hit point on x-y plane matches length of
1947 // manipulator radius_state
1948 if(xy_hit && (!more_than_one_hit || t1_near))
1949 {
1950 // Outer ring on xy plane has been hit
1951 if ( _updateStates == Click)
1952 element_[ZRing].clicked_ = true;
1953 else if ( _updateStates == Over)
1954 element_[ZRing].over_ = true;
1955 _v3 = hitPointXY;
1956 return true;
1957 }
1958
1959 else if(yz_hit && (!more_than_one_hit || t2_near))
1960 {
1961 // Outer ring on yz plane has been hit
1962 if ( _updateStates == Click)
1963 element_[XRing].clicked_ = true;
1964 else if ( _updateStates == Over)
1965 element_[XRing].over_ = true;
1966 _v3 = hitPointYZ;
1967 return true;
1968 }
1969
1970 else if(zx_hit && (!more_than_one_hit || t3_near))
1971 {
1972 // Outer ring around zx plane has been hit
1973 if ( _updateStates == Click)
1974 element_[YRing].clicked_ = true;
1975 else if ( _updateStates == Over)
1976 element_[YRing].over_ = true;
1977 _v3 = hitPointZX;
1978 return true;
1979 }
1980
1981 return false;
1982 }
1983
1984 //----------------------------------------------------------------------------
1985
1986 void
1987 TranslationManipulatorNode::
1988 pick(GLState& _state, PickTarget _target)
1989 {
1990 GLenum prev_depth = _state.depthFunc();
1991
1992 if (_target == PICK_FACE ||
1993 _target == PICK_ANYTHING) {
1994
1995 if (draw_manipulator_) {
1996
1997 updateSize (_state);
1998
1999 _state.pick_set_maximum(5);
2000
2001 // Enable depth test but store original status
2002 glPushAttrib(GL_DEPTH_BUFFER_BIT);
2003 ACG::GLState::enable(GL_DEPTH_TEST);
2004 ACG::GLState::depthFunc(GL_LEQUAL);
2005
2006 // Save modelview matrix
2007 _state.push_modelview_matrix();
2008
2009 // Correctly align nodes local coordinate system
2010 update_manipulator_system(_state);
2011
2012 _state.pick_set_name(0);
2013 //================================================================================================
2014 // Z-Axis
2015 //================================================================================================
2016 // gluCylinder draws into z direction so z-Axis first
2017
2018 axisBottom_->setBottomRadius(manipulator_radius_);
2019 axisBottom_->setTopRadius(manipulator_radius_);
2020 axisBottom_->draw(_state, manipulator_height_);
2021
2022 // Draw Top of z-axis
2023 _state.translate(0.0, 0.0, manipulator_height_);
2024 axisTop_->setBottomRadius(manipulator_radius_*2.0);
2025 axisTop_->setTopRadius(manipulator_radius_*2.0);
2026 axisTop_->draw(_state, manipulator_height_/2.0);
2027 _state.translate(0.0, 0.0, -manipulator_height_);
2028
2029 _state.pick_set_name(1);
2030 //================================================================================================
2031 // Y-Axis
2032 //================================================================================================
2033 _state.rotate(-90, 1.0, 0.0, 0.0);
2034 axisBottom_->setBottomRadius(manipulator_radius_);
2035 axisBottom_->setTopRadius(manipulator_radius_);
2036 axisBottom_->draw(_state, manipulator_height_);
2037
2038 // Draw Top of y-axis
2039 _state.translate(0.0, 0.0, manipulator_height_);
2040 axisTop_->setBottomRadius(manipulator_radius_*2.0);
2041 axisTop_->setTopRadius(manipulator_radius_*2.0);
2042 axisTop_->draw(_state, manipulator_height_/2.0);
2043 _state.translate(0.0, 0.0, -manipulator_height_);
2044
2045
2046 _state.pick_set_name(2);
2047 //================================================================================================
2048 // X-Axis
2049 //================================================================================================
2050 _state.rotate(90, 0.0, 1.0, 0.0);
2051
2052 axisBottom_->setBottomRadius(manipulator_radius_);
2053 axisBottom_->setTopRadius(manipulator_radius_);
2054 axisBottom_->draw(_state, manipulator_height_);
2055
2056 // Draw Top of x-axis
2057 _state.translate(0.0, 0.0, manipulator_height_);
2058 axisTop_->setBottomRadius(manipulator_radius_*2.0);
2059 axisTop_->setTopRadius(manipulator_radius_*2.0);
2060 axisTop_->draw(_state, manipulator_height_/2.0);
2061
2062 _state.translate(0.0, 0.0, -manipulator_height_);
2063
2064 _state.pick_set_name(3);
2065 //=================================================================================================
2066 // Sphere
2067 //=================================================================================================
2068
2069 sphere_->draw(_state, manipulator_radius_*2);
2070
2071 //=================================================================================================
2072 // Outer-Spheres
2073 //=================================================================================================
2074
2075 _state.pick_set_name(4);
2076 circle_->setInnerRadius(2.0f*manipulator_height_ - manipulator_height_/4.0f);
2077 circle_->setOuterRadius(2.0f*manipulator_height_);
2078 if ( activeRotations_ & X_AXIS)
2079 circle_->draw(_state);
2080
2081 _state.rotate(90, 0.0, 1.0, 0.0);
2082 if ( activeRotations_ & Y_AXIS)
2083 circle_->draw(_state);
2084
2085 _state.rotate(90, 1.0, 0.0, 0.0);
2086 if ( activeRotations_ & Z_AXIS)
2087 circle_->draw(_state);
2088
2089 // Restore old attributes and modelview
2090 glPopAttrib();
2091 _state.pop_modelview_matrix();
2092
2093 //restore original depth comparison function
2094 ACG::GLState::depthFunc(prev_depth);
2095 }
2096 }
2097 }
2098
2099
2100 //----------------------------------------------------------------------------
2101
2102 void
2103 TranslationManipulatorNode::set_direction(const Vec3d& _directionX, const Vec3d& _directionY)
2104 {
2105
2106 localTransformation_.identity();
2107
2108 const Vec3d cross = _directionX % _directionY;
2109
2110 localTransformation_(0,0) = _directionX[0];
2111 localTransformation_(1,0) = _directionX[1];
2112 localTransformation_(2,0) = _directionX[2];
2113 localTransformation_(3,0) = 0.0;
2114
2115 localTransformation_(0,1) = _directionY[0];
2116 localTransformation_(1,1) = _directionY[1];
2117 localTransformation_(2,1) = _directionY[2];
2118 localTransformation_(3,1) = 0.0;
2119
2120 localTransformation_(0,2) = cross[0];
2121 localTransformation_(1,2) = cross[1];
2122 localTransformation_(2,2) = cross[2];
2123 localTransformation_(3,2) = 0.0;
2124
2125 }
2126
2127 //----------------------------------------------------------------------------
2128
2129
2130 Vec3d
2131 TranslationManipulatorNode::directionX() const
2132 {
2133 return MathTools::sane_normalized( localTransformation_.transform_vector(dirX_) );
2134 }
2135
2136 //----------------------------------------------------------------------------
2137
2138
2139 Vec3d
2140 TranslationManipulatorNode::directionY() const
2141 {
2142 return MathTools::sane_normalized( localTransformation_.transform_vector(dirY_) );
2143 }
2144
2145 //----------------------------------------------------------------------------
2146
2147
2148 Vec3d
2149 TranslationManipulatorNode::directionZ() const
2150 {
2151 return MathTools::sane_normalized(localTransformation_.transform_vector(dirZ_));
2152 }
2153
2154 //----------------------------------------------------------------------------
2155
2156 double TranslationManipulatorNode::get_screen_length (GLState& _state, Vec3d& _point) const
2157 {
2158 Vec3d proj = _state.project (_point);
2159 proj[0] += 1.0;
2160 Vec3d uproj = _state.unproject (proj);
2161 uproj -= _point;
2162 return uproj.length ();
2163 }
2164
2165 //----------------------------------------------------------------------------
2166
2167 void TranslationManipulatorNode::updateSize (GLState& _state)
2168 {
2169 if (auto_size_ != TranslationManipulatorNode::Never)
2170 {
2171 Vec3d point = localTransformation_.transform_point(Vec3d (0.0, 0.0, 0.0));
2172
2173 int tmp, width, height;
2174
2175 _state.get_viewport (tmp, tmp, width, height);
2176
2177 auto_size_length_ = get_screen_length (_state, point) * (width + height) * 0.02;
2178
2179 if (auto_size_ == TranslationManipulatorNode::Once)
2180 auto_size_ = TranslationManipulatorNode::Never;
2181 }
2182
2183 manipulator_radius_ = set_manipulator_radius_ * auto_size_length_;
2184 manipulator_height_ = set_manipulator_height_ * auto_size_length_;
2185 }
2186
2187 //----------------------------------------------------------------------------
2188
2189
2190 void TranslationManipulatorNode::boundingBox( Vec3d & _bbMin, Vec3d & _bbMax )
2191 {
2192 if (!draw_manipulator_)
2193 return;
2194
2195 float r = 2 * manipulator_height_;
2196
2197 _bbMin.minimize(center()+Vec3d(-r,-r,-r));
2198 _bbMax.maximize(center()+Vec3d(r,r,r));
2199 }
2200
2201 //----------------------------------------------------------------------------
2202
2203 void TranslationManipulatorNode::setMode (ManipulatorMode _mode)
2204 {
2205 if (mode_ != _mode)
2206 ignoreTime_ = true;
2207 mode_ = _mode;
2208 setDirty ();
2209 }
2210
2211 //=============================================================================
2212 } // namespace SceneGraph
2213 } // namespace ACG
2214 //=============================================================================
ACG::GLState::scale
void scale(double _s)
scale by (_s, _s, _s)
Definition: GLState.hh:753
ACG::RenderObject::shaderDesc
ShaderGenDesc shaderDesc
Drawmode and other shader params.
Definition: RenderObject.hh:232
ACG::SceneGraph::ACG::SceneGraph::BaseNode::setTraverseMode
void setTraverseMode(unsigned int _mode)
Set traverse mode for node.
Definition: MeshNode2T.cc:428
ACG
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
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::PickTarget
PickTarget
What target to use for picking.
Definition: BaseNode.hh:99
ACG::SceneGraph::ACG::GLState::disable
static void disable(GLenum _cap)
replaces glDisable, but supports locking
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::TranslationManipulatorNode::mapToCylinderTop
bool mapToCylinderTop(GLState &_state, const Vec2i &_v2, StateUpdates _updateStates=None)
Definition: TranslationManipulatorNode.cc:1762
ACG::SceneGraph::PICK_FACE
picks faces (should be implemented for all nodes)
Definition: BaseNode.hh:104
ACG::SceneGraph::TranslationManipulatorNode::directionY
Vec3d directionY() const
Get current direction of y-Axis in world coordinates.
Definition: TranslationManipulatorNode.cc:2140
ACG::SceneGraph::PICK_ANYTHING
pick any of the prior targets (should be implemented for all nodes)
Definition: BaseNode.hh:110
ACG::RenderObject
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:105
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::unproject
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:649
ACG::RenderObject::blendDest
GLenum blendDest
glBlendFunc: GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ONE_MINUS_SRC_ALPHA ...
Definition: RenderObject.hh:254
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::TranslationManipulatorNode::setMode
void setMode(ManipulatorMode _mode)
set current operation mode
Definition: TranslationManipulatorNode.cc:2203
ACG::RenderObject::depthFunc
GLenum depthFunc
GL_LESS, GL_LEQUAL, GL_GREATER ..
Definition: RenderObject.hh:247
ACG::RenderObject::initFromState
void initFromState(GLState *_glState)
Initializes a RenderObject instance.
Definition: RenderObject.cc:69
ACG::Vec4f
VectorT< float, 4 > Vec4f
Definition: VectorT.hh:144
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::GLState::modelview
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:794
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::SceneGraph::TranslationManipulatorNode::computeWorldMatrix
GLMatrixd computeWorldMatrix()
computes world matrix, transforms from model to world space
Definition: TranslationManipulatorNode.cc:755
ACG::GLState::set_diffuse_color
void set_diffuse_color(const Vec4f &_col)
set diffuse color
Definition: GLState.cc:720
ACG::GLSphere
Definition: GLPrimitives.hh:137
ACG::SceneGraph::TranslationManipulatorNode::draw
void draw(GLState &_state, const DrawModes::DrawMode &_drawMode)
draw the cylinder (if enabled)
Definition: TranslationManipulatorNode.cc:695
ACG::Vec2d
VectorT< double, 2 > Vec2d
Definition: VectorT.hh:110
ACG::SceneGraph::TranslationManipulatorNode::setIdentity
virtual void setIdentity()
Definition: TranslationManipulatorNode.cc:217
ACG::SceneGraph::TranslationManipulatorNode::touched_
bool touched_
stores if this manipulator was used in order to avoid emitting manipulatorMoved unnecessarily ...
Definition: TranslationManipulatorNode.hh:231
ACG::SceneGraph::TranslationManipulatorNode
Definition: TranslationManipulatorNode.hh:90
ACG::GLState::push_modelview_matrix
void push_modelview_matrix()
push modelview matrix
Definition: GLState.cc:1006
ACG::SceneGraph::TransformNode::center
const Vec3d & center() const
get center
Definition: TransformNode.hh:121
ACG::SceneGraph::ACG::GLState::depthFunc
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
ACG::GLMatrixT::translate
void translate(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with translation matrix (x,y,z)
Definition: GLMatrixT.cc:102
ACG::SceneGraph::TranslationManipulatorNode::mapToCylinder
bool mapToCylinder(GLState &_state, const Vec2i &_v2, StateUpdates _updateStates=None)
Definition: TranslationManipulatorNode.cc:1651
ACG::IRenderer
Definition: IRenderer.hh:84
ACG::GLMatrixT< double >
ACG::SceneGraph::DrawModes::DrawMode
Specifies a DrawMode.
Definition: DrawModes.hh:294
ACG::SceneGraph::TranslationManipulatorNode::update_manipulator_system
void update_manipulator_system(GLState &_state)
set the current state to follow manipulator transformation
Definition: TranslationManipulatorNode.cc:226
ACG::GLMatrixT::scale
void scale(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with scaling matrix (x,y,z)
Definition: GLMatrixT.cc:81
ACG::SceneGraph::TranslationManipulatorNode::set_direction
void set_direction(const Vec3d &_directionX, const Vec3d &_directionY)
Set direction in world coordinates.
Definition: TranslationManipulatorNode.cc:2103
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::viewport_width
int viewport_width() const
get viewport width
Definition: GLState.hh:825
ACG::SceneGraph::TranslationManipulatorNode::pick
void pick(GLState &_state, PickTarget _target)
leave node
Definition: TranslationManipulatorNode.cc:1988
ACG::GLState::specular_color
const Vec4f & specular_color() const
get specular color
Definition: GLState.hh:944
ACG::SceneGraph::TranslationManipulatorNode::TranslationManipulatorNode
TranslationManipulatorNode(BaseNode *_parent=0, const std::string &_name="<TranslationTranslationManipulatorNode>")
Default constructor.
Definition: TranslationManipulatorNode.cc:131
ACG::SceneGraph::TranslationManipulatorNode::~TranslationManipulatorNode
~TranslationManipulatorNode()
Destructor.
Definition: TranslationManipulatorNode.cc:200
ACG::SceneGraph::BaseNode::ChildrenFirst
Execute action the children first and then on this node.
Definition: BaseNode.hh:419
ACG::SceneGraph::TranslationManipulatorNode::directionX
Vec3d directionX() const
Get current direction of x-Axis in world coordinates.
Definition: TranslationManipulatorNode.cc:2131
OpenMesh::VectorT< float, 4 >
ACG::SceneGraph::TransformNode::scale
const GLMatrixd & scale() const
return scale matrix
Definition: TransformNode.hh:181
ACG::GLMatrixT::rotate
void rotate(Scalar angle, Scalar x, Scalar y, Scalar z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
Definition: GLMatrixT.cc:161
ACG::GLDisk
Definition: GLPrimitives.hh:250
ACG::SceneGraph::TranslationManipulatorNode::hitSphere
bool hitSphere(GLState &_state, const Vec2i &_v2)
Determine whether the origin sphere has been hit.
Definition: TranslationManipulatorNode.cc:1571
ACG::ShaderGenDesc::clearTextures
void clearTextures()
disables texture support and removes all texture types
Definition: ShaderGenerator.hh:200
ACG::GLCone
Definition: GLPrimitives.hh:167
ACG::SceneGraph::TransformNode::inverse_rotation
const GLMatrixd & inverse_rotation() const
return inverse rotation matrix
Definition: TransformNode.hh:172
ACG::SceneGraph::TranslationManipulatorNode::update_rotation
void update_rotation(GLState &_state)
update the internal rotation matrix ( internal rotation may be changed without modifiing children of ...
Definition: TranslationManipulatorNode.cc:238
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::TranslationManipulatorNode::mapToSphere
bool mapToSphere(GLState &_state, const Vec2i &_v2, Vec3d &_v3, StateUpdates _updateStates=None)
Definition: TranslationManipulatorNode.cc:1878
ACG::GLState::get_viewport
void get_viewport(int &_left, int &_bottom, int &_width, int &_height) const
get viewport
Definition: GLState.hh:819
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::Matrix4x4T::identity
void identity()
setup an identity matrix
Definition: Matrix4x4T.cc:256
ACG::Matrix4x4T::transform_point
VectorT< T, 3 > transform_point(const VectorT< T, 3 > &_v) const
transform point (x',y',z',1) = M * (x,y,z,1)
Definition: Matrix4x4T.cc:202
ACG::SceneGraph::TransformNode
Definition: TransformNode.hh:95
ACG::SceneGraph::TranslationManipulatorNode::mouseEvent
virtual void mouseEvent(GLState &_state, QMouseEvent *_event)
get mouse events
Definition: TranslationManipulatorNode.cc:948
ACG::RenderObject::modelview
GLMatrixd modelview
Modelview transform.
Definition: RenderObject.hh:145
ACG::SceneGraph::TranslationManipulatorNode::boundingBox
void boundingBox(Vec3d &_bbMin, Vec3d &_bbMax)
bounding box of node
Definition: TranslationManipulatorNode.cc:2190
ACG::SceneGraph::TransformNode::translate
void translate(const Vec3d &_v)
Add a translation to the current Transformation.
Definition: TransformNode.cc:131
ACG::GLState::set_modelview
void set_modelview(const GLMatrixd &_m)
set modelview
Definition: GLState.hh:731
ACG::GLState::depthFunc
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:937
ACG::SceneGraph::Material
Definition: MaterialNode.hh:85
ACG::SceneGraph::TranslationManipulatorNode::directionZ
Vec3d directionZ() const
Get current direction of z-Axis in world coordinates.
Definition: TranslationManipulatorNode.cc:2149
ACG::SceneGraph::TransformNode::setIdentity
virtual void setIdentity()
Definition: TransformNode.cc:118
ACG::RenderObject::priority
int priority
Priority to allow sorting of objects.
Definition: RenderObject.hh:123
ACG::Matrix4x4T::invert
bool invert()
matrix inversion (returns true on success)
Definition: Matrix4x4T.cc:297
ACG::GLState::context_width
int context_width() const
get gl context width
Definition: GLState.hh:830
ACG::GLState::project
Vec3d project(const Vec3d &_point) const
project point in world coordinates to window coordinates
Definition: GLState.cc:638
ACG::SceneGraph::ACG::GLState::blendFunc
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: MeshNode2T.cc:314
ACG::SceneGraph::TranslationManipulatorNode::ManipulatorMode
ManipulatorMode
enum to define the manipulator mode
Definition: TranslationManipulatorNode.hh:108
ACG::GLState::viewport_height
int viewport_height() const
get viewport height
Definition: GLState.hh:827
ACG::GLState::viewing_ray
void viewing_ray(int _x, int _y, Vec3d &_origin, Vec3d &_direction) const
Definition: GLState.cc:926
ACG::SceneGraph::TranslationManipulatorNode::hitOuterSphere
bool hitOuterSphere(GLState &_state, const Vec2i &_v2)
Determine whether the outer sphere has been hit by the cursor.
Definition: TranslationManipulatorNode.cc:1611
ACG::SceneGraph::ACG::SceneGraph::BaseNode::setDirty
void setDirty(bool _dirty=true)
mark node for redrawn
Definition: MeshNode2T.cc:251
ACG::GLState::diffuse_color
const Vec4f & diffuse_color() const
get diffuse color
Definition: GLState.hh:939
ACG::SceneGraph::TranslationManipulatorNode::getRenderObjects
void getRenderObjects(IRenderer *_renderer, GLState &_state, const DrawModes::DrawMode &_drawMode, const Material *_mat)
create renderobjects for shaderpipeline renderer
Definition: TranslationManipulatorNode.cc:774