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