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 
68 namespace ACG {
69 namespace 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 
80 const 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 
114 TranslationManipulatorNode::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 
127 TranslationManipulatorNode( 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 
211 void
214 {
216 }
217 
218 
219 //----------------------------------------------------------------------------
220 void
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
233 void
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 
254 void 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 
390 bool 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 
445 void 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 
691 void
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 
826 void 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 
862 void 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 
957 void
958 TranslationManipulatorNode::mouseEvent(GLState& _state, QMouseEvent* _event)
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 
1050  touched_ = touched_
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 
1626  update_manipulator_system(_state);
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 
1666  update_manipulator_system(_state);
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 
1691 bool
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:
1711  update_manipulator_system(_state);
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
1802 bool
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:
1821  update_manipulator_system(_state);
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 
1918 bool
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 
1936  update_manipulator_system(_state);
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 
2027 void
2029 pick(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
2054  update_manipulator_system(_state);
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 
2149 void
2150 TranslationManipulatorNode::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 
2179 Vec3d
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 
2195 Vec3d
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 
2211 Vec3d
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 
2226 double TranslationManipulatorNode::get_screen_length (GLState& _state, 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 
2237 void TranslationManipulatorNode::updateSize (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 //=============================================================================
Vec3d directionY() const
Get current direction of y-Axis in world coordinates.
void translate(const Vec3d &_v)
Add a translation to the current Transformation.
void rotate(Scalar angle, Scalar x, Scalar y, Scalar z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
Definition: GLState.cc:1507
void initFromState(GLState *_glState)
Initializes a RenderObject instance.
Definition: RenderObject.cc:61
void pop_modelview_matrix()
pop modelview matrix
Definition: GLState.cc:1026
static void shadeModel(GLenum _mode)
replaces glShadeModel, supports locking
Definition: GLState.cc:1729
const Vec4f & specular_color() const
get specular color
Definition: GLState.hh:966
void set_diffuse_color(const Vec4f &_col)
set diffuse color
Definition: GLState.cc:722
Vec3d directionZ() const
Get current direction of z-Axis in world coordinates.
const Vec3d & center() const
get center
picks faces (should be implemented for all nodes)
Definition: PickTarget.hh:78
int viewport_width() const
get viewport width
Definition: GLState.hh:847
Namespace providing different geometric functions concerning angles.
void boundingBox(Vec3d &_bbMin, Vec3d &_bbMax) override
bounding box of node
Vec3d project(const Vec3d &_point) const
project point in world coordinates to window coordinates
Definition: GLState.cc:640
VectorT< float, 4 > Vec4f
Definition: VectorT.hh:138
void setDirty(bool _dirty=true)
mark node for redrawn
Definition: BaseNode.hh:275
GLenum depthFunc
GL_LESS, GL_LEQUAL, GL_GREATER ..
void get_viewport(int &_left, int &_bottom, int &_width, int &_height) const
get viewport
Definition: GLState.hh:841
ShaderGenDesc shaderDesc
Drawmode and other shader params.
void translate(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with translation matrix (x,y,z)
bool hitSphere(GLState &_state, const Vec2i &_v2)
Determine whether the origin sphere has been hit.
void clearTextures()
disables texture support and removes all texture types
void identity()
setup an identity matrix
const GLMatrixd & inverse_scale() const
return inverse scale matrix
void scale(double _s)
scale by (_s, _s, _s)
Definition: GLState.hh:775
vector_type & maximize(const vector_type &_rhs)
maximize values: same as *this = max(*this, _rhs), but faster
Definition: Vector11T.hh:587
std::string name
Name for logging.
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:941
const Vec4f & diffuse_color() const
get diffuse color
Definition: GLState.hh:961
void setTraverseMode(unsigned int _mode)
Set traverse mode for node.
Definition: BaseNode.hh:452
VectorT< T, 3 > transform_point(const VectorT< T, 3 > &_v) const
transform point (x&#39;,y&#39;,z&#39;,1) = M * (x,y,z,1)
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
void set_updateGL(bool _b)
should GL matrices be updated after each matrix operation
Definition: GLState.hh:235
void set_direction(const Vec3d &_directionX, const Vec3d &_directionY)
Set direction in world coordinates.
PickTarget
What target to use for picking.
Definition: PickTarget.hh:73
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:651
bool invert()
matrix inversion (returns true on success)
void push_modelview_matrix()
push modelview matrix
Definition: GLState.cc:1010
void set_modelview(const GLMatrixd &_m)
set modelview
Definition: GLState.hh:753
void setMode(ManipulatorMode _mode)
set current operation mode
GLMatrixd computeWorldMatrix()
computes world matrix, transforms from model to world space
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
Definition: GLState.cc:1527
const GLMatrixd & inverse_rotation() const
return inverse rotation matrix
bool mapToCylinderTop(GLState &_state, const Vec2i &_v2, StateUpdates _updateStates=None)
pick any of the prior targets (should be implemented for all nodes)
Definition: PickTarget.hh:84
void set_ambient_color(const Vec4f &_col)
set ambient color
Definition: GLState.cc:707
bool pick_set_maximum(size_t _idx)
Set the maximal number of primitives/components of your object.
Definition: GLState.cc:1051
void pick(GLState &_state, PickTarget _target) override
leave node
void scale(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with scaling matrix (x,y,z)
int viewport_height() const
get viewport height
Definition: GLState.hh:849
vector_type & minimize(const vector_type &_rhs)
minimize values: same as *this = min(*this, _rhs), but faster
Definition: Vector11T.hh:559
VectorT< T, 3 > transform_vector(const VectorT< T, 3 > &_v) const
transform vector (x&#39;,y&#39;,z&#39;,0) = A * (x,y,z,0)
auto norm() const -> decltype(std::sqrt(std::declval< VectorT< S, DIM >>().sqrnorm()))
compute euclidean norm
Definition: Vector11T.hh:433
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: GLState.hh:307
void set_specular_color(const Vec4f &_col)
set specular color
Definition: GLState.cc:737
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
void getRenderObjects(IRenderer *_renderer, GLState &_state, const DrawModes::DrawMode &_drawMode, const Material *_mat) override
create renderobjects for shaderpipeline renderer
TranslationManipulatorNode(BaseNode *_parent=0, const std::string &_name="<TranslationTranslationManipulatorNode>")
Default constructor.
bool mapToSphere(GLState &_state, const Vec2i &_v2, Vec3d &_v3, StateUpdates _updateStates=None)
void set_color(const Vec4f &_col)
set color
Definition: GLState.cc:691
int priority
Priority to allow sorting of objects.
void viewing_ray(int _x, int _y, Vec3d &_origin, Vec3d &_direction) const
Definition: GLState.cc:930
auto length() const -> decltype(std::declval< VectorT< S, DIM >>().norm())
compute squared euclidean norm
Definition: Vector11T.hh:442
void update_rotation(GLState &_state)
update the internal rotation matrix ( internal rotation may be changed without modifiing children of ...
Vec3d directionX() const
Get current direction of x-Axis in world coordinates.
ManipulatorMode
enum to define the manipulator mode
void pick_set_name(size_t _idx)
sets the current name/color (like glLoadName(_idx))
Definition: GLState.cc:1061
bool mapToCylinder(GLState &_state, const Vec2i &_v2, StateUpdates _updateStates=None)
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:816
decltype(std::declval< S >() *std::declval< S >()) sqrnorm() const
compute squared euclidean norm
Definition: Vector11T.hh:421
virtual void mouseEvent(GLState &_state, QMouseEvent *_event) override
get mouse events
Execute action the children first and then on this node.
Definition: BaseNode.hh:443
int context_height() const
get gl context height
Definition: GLState.hh:855
unsigned int msSinceLastRedraw() const
time passed since last redraw in milliseconds
Definition: GLState.hh:238
void update_manipulator_system(GLState &_state)
set the current state to follow manipulator transformation
bool touched_
stores if this manipulator was used in order to avoid emitting manipulatorMoved unnecessarily ...
GLenum blendDest
glBlendFunc: GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ONE_MINUS_SRC_ALPHA ...
const GLMatrixd & rotation() const
return rotation matrix
VectorT< double, 2 > Vec2d
Definition: VectorT.hh:104
void draw(GLState &_state, const DrawModes::DrawMode &_drawMode) override
draw the cylinder (if enabled)
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:453
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:98
bool is_zero(const T &_a, Real _eps)
Definition: MathDefs.hh:61
const GLMatrixd & scale() const
return scale matrix
void translate(double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
translate by (_x, _y, _z)
Definition: GLState.cc:533
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
int context_width() const
get gl context width
Definition: GLState.hh:852
GLMatrixd modelview
Modelview transform.
bool hitOuterSphere(GLState &_state, const Vec2i &_v2)
Determine whether the outer sphere has been hit by the cursor.