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 = (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 
1078  for (i = 0; i < NumElements; i++)
1079  element_[i].over_ = false;
1080  any_axis_over_ = false;
1081  any_top_over_ = false;
1082  outer_ring_over_ = false;
1083 
1084  if (!(element_[Origin].clicked_ || any_top_clicked_ || any_axis_clicked_ || outer_ring_clicked_)) {
1085  // over origin ?
1086  if ((mode_ != LocalRotation) && (mode_ != Rotation))
1087  element_[Origin].over_ = hitSphere(_state, newPoint2D);
1088  else
1089  element_[Origin].over_ = false;
1090 
1091 
1092  // over any top ?
1093  if (mode_ != Place) {
1094  any_top_over_ = mapToCylinderTop(_state, newPoint2D, Over);
1095  }
1096 
1097  // over any axis ?
1098  if (mode_ != Place) {
1099  any_axis_over_ = mapToCylinder(_state, newPoint2D, Over);
1100  }
1101 
1102  // over one of the outer rings ?
1103  if (mode_ != Resize) {
1104  outer_ring_over_ = mapToSphere(_state, newPoint2D, newPoint3D, Over);
1105  } else {
1106  outer_ring_over_ = false;
1107  }
1108 
1109  // origin has been hit, ignore all other parts
1110  if (element_[Origin].over_) {
1111  for (i = 1; i < NumElements; i++)
1112  element_[i].over_ = false;
1113  any_axis_over_ = false;
1114  any_top_over_ = false;
1115  outer_ring_over_ = false;
1116  } else if (any_top_over_) { // tops override the axes
1117  for (i = XAxis; i < NumElements; i++)
1118  element_[i].over_ = false;
1119  any_axis_over_ = false;
1120  outer_ring_over_ = false;
1121  } else if (any_axis_over_) { // axes have been hit, disable rest ... should not be required
1122  for (i = XRing; i < NumElements; i++)
1123  element_[i].over_ = false;
1124  outer_ring_over_ = false;
1125  } else if (outer_ring_over_) { // Nothing except the outer ring has been hit
1126  for (i = 0; i < XRing; i++)
1127  element_[i].over_ = false;
1128  any_axis_over_ = false;
1129  any_top_over_ = false;
1130  }
1131  }
1132 
1133  // set action for the different modes
1134  bool rot[3], trans[3];
1135  switch (mode_) {
1136  case Rotation:
1137  for (i = 0; i < 3; i++) {
1138  rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_;
1139  trans[i] = false;
1140  }
1141  break;
1142  case TranslationRotation:
1143  for (i = 0; i < 3; i++) {
1144  rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_;
1145  trans[i] = element_[XAxis + i].clicked_;
1146  }
1147  break;
1148  case LocalRotation:
1149  for (i = 0; i < 3; i++) {
1150  rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_ || element_[XAxis + i].clicked_;
1151  trans[i] = false;
1152  }
1153  break;
1154  case Place:
1155  break;
1156  case Resize:
1157  for (i = 0; i < 3; i++) {
1158  rot[i] = false;
1159  trans[i] = element_[XTop + i].clicked_ || element_[XAxis + i].clicked_;
1160  }
1161  break;
1162  }
1163 
1164  // If origin was clicked on
1165  if (element_[Origin].clicked_) {
1166 
1167  // translate along screen plane ( unproject to get world coords for translation and apply them )
1168 
1169  Vec3d d = _state.project(center());
1170  Vec3d d_origin = _state.project(draggingOrigin3D_);
1171 
1172  // Snap back to origin position if mouse cursor
1173  // is near enough
1174  if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1175  && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1176  && (_event->modifiers() & Qt::AltModifier) ) {
1177  newPoint2D = oldPoint2D_;
1178  Vec3d backtrans = draggingOrigin3D_ - center();
1179  if (mode_ != Resize) {
1180  translate(backtrans);
1181  }
1182  }
1183 
1184  // translate along screen plane ( unproject to get world coords for translation and apply them )
1185  Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1186  Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1187  Vec3d ntrans = newvec - oldvec;
1188 
1189  if (mode_ != Resize)
1190  translate(ntrans);
1191  else {
1192  // revert last scale
1193  scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1194  double positive = -1;
1195  if (newPoint2D[0] - oldPoint2D_[0] + oldPoint2D_[1] - newPoint2D[1] > 0)
1196  positive = 1;
1197 
1198  Vec2d div = Vec2d(newPoint2D[0], newPoint2D[1]) - Vec2d(oldPoint2D_[0], oldPoint2D_[1]);
1199 
1200  double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1201  scaleValue *= positive;
1202  currentScale_ += Vec3d(scaleValue, scaleValue, scaleValue);
1203 
1204  scale(currentScale_);
1205  }
1206 
1207  touched_ = true;
1208  }
1209 
1210  // x axis clicked apply translation along axis
1211  if (trans[0]) {
1212 
1213  mapToCylinder(_state, oldPoint2D_);
1214  mapToCylinder(_state, newPoint2D);
1215 
1216  // translate
1217  // Get screen coordinates of current mouse position and unproject them
1218  // into world coordinates. Project onto selected axis and apply resulting
1219  // vector as translation
1220 
1221  Vec3d d = _state.project(center());
1222  Vec3d d_origin = _state.project(draggingOrigin3D_);
1223 
1224  // Snap back to origin position if mouse cursor
1225  // is near enough
1226  if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1227  && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1228  && (_event->modifiers() & Qt::AltModifier) ) {
1229  newPoint2D = oldPoint2D_;
1230  Vec3d backtrans = draggingOrigin3D_ - center();
1231  if (mode_ != Resize) {
1232  translate(backtrans);
1233  }
1234  }
1235  Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1236  Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1237  Vec3d ntrans = newvec - oldvec;
1238 
1239  // project to current direction
1240  ntrans = (ntrans | directionX()) * directionX();
1241 
1242  if (mode_ == Resize) {
1243  //scaling
1244  double positive = -1;
1245  if ((directionX() | ntrans) > 0)
1246  positive = 1;
1247 
1248  if (currentScale_[0] < 0)
1249  positive *= -1;
1250 
1251  Vec3d proj = _state.project(ntrans + oldvec);
1252 
1253  Vec2d div = Vec2d(proj[0], proj[1]) - Vec2d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
1254 
1255  double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1256  scaleValue *= positive;
1257 
1258  // revert last scale
1259  GLMatrixd m = localTransformation_;
1260  GLMatrixd mi = localTransformation_;
1261  mi.invert();
1262 
1263  m.scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1264  m *= mi;
1265 
1266  scale(m);
1267 
1268  currentScale_ += Vec3d(scaleValue, 0.0, 0.0);
1269 
1270  m = localTransformation_;
1271  m.scale(currentScale_);
1272  m *= mi;
1273 
1274  scale(m);
1275  } else
1276  //translation
1277  translate(ntrans);
1278 
1279  touched_ = true;
1280  }
1281 
1282  // y axis clicked change translation along axis
1283  if (trans[1]) {
1284 
1285  mapToCylinder(_state, oldPoint2D_);
1286  mapToCylinder(_state, newPoint2D);
1287 
1288  // translate
1289  // Get screen coordinates of current mouse position and unproject them
1290  // into world coordinates. Project onto selected axis and apply resulting
1291  // vector as translation
1292 
1293  Vec3d d = _state.project(center());
1294  Vec3d d_origin = _state.project(draggingOrigin3D_);
1295 
1296  // Snap back to origin position if mouse cursor
1297  // is near enough
1298  if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1299  && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1300  && (_event->modifiers() & Qt::AltModifier) ) {
1301  newPoint2D = oldPoint2D_;
1302  Vec3d backtrans = draggingOrigin3D_ - center();
1303  if (mode_ != Resize) {
1304  translate(backtrans);
1305  }
1306  }
1307  Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1308  Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1309  Vec3d ntrans = newvec - oldvec;
1310 
1311  // project to current direction
1312  ntrans = (ntrans | directionY()) * directionY();
1313 
1314  if (mode_ == Resize) {
1315  //scaling
1316  double positive = -1;
1317  if ((directionY() | ntrans) > 0)
1318  positive = 1;
1319 
1320  if (currentScale_[1] < 0)
1321  positive *= -1;
1322 
1323  Vec3d proj = _state.project(ntrans + oldvec);
1324 
1325  Vec2d div = Vec2d(proj[0], proj[1]) - Vec2d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
1326 
1327  double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1328  scaleValue *= positive;
1329 
1330  // revert last scale
1331  GLMatrixd m = localTransformation_;
1332  GLMatrixd mi = localTransformation_;
1333  mi.invert();
1334 
1335  m.scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1336  m *= mi;
1337 
1338  scale(m);
1339 
1340  currentScale_ += Vec3d(0.0, scaleValue, 0.0);
1341 
1342  m = localTransformation_;
1343  m.scale(currentScale_);
1344  m *= mi;
1345 
1346  scale(m);
1347 
1348  } else
1349  //translation
1350  translate(ntrans);
1351 
1352  touched_ = true;
1353  }
1354 
1355  // z axis clicked change translation along axis
1356  if (trans[2]) {
1357 
1358  mapToCylinder(_state, oldPoint2D_);
1359  mapToCylinder(_state, newPoint2D);
1360 
1361  // translate
1362  // Get screen coordinates of current mouse position and unproject them
1363  // into world coordinates. Project onto selected axis and apply resulting
1364  // vector as translation
1365 
1366  Vec3d d = _state.project(center());
1367  Vec3d d_origin = _state.project(draggingOrigin3D_);
1368 
1369  // Snap back to origin position if mouse cursor
1370  // is near enough
1371  if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1372  && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1373  && (_event->modifiers() & Qt::AltModifier) ) {
1374  newPoint2D = oldPoint2D_;
1375  Vec3d backtrans = draggingOrigin3D_ - center();
1376  if (mode_ != Resize) {
1377  translate(backtrans);
1378  }
1379  }
1380  Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1381  Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1382  Vec3d ntrans = newvec - oldvec;
1383 
1384  // project to current direction
1385  ntrans = (ntrans | directionZ()) * directionZ();
1386 
1387  if (mode_ == Resize) {
1388  //scaling
1389  double positive = -1;
1390  if ((directionZ() | ntrans) > 0)
1391  positive = 1;
1392 
1393  if (currentScale_[2] < 0)
1394  positive *= -1;
1395 
1396  Vec3d proj = _state.project(ntrans + oldvec);
1397 
1398  Vec2d div = Vec2d(proj[0], proj[1]) - Vec2d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
1399 
1400  double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1401  scaleValue *= positive;
1402 
1403  // revert last scale
1404  GLMatrixd m = localTransformation_;
1405  GLMatrixd mi = localTransformation_;
1406  mi.invert();
1407 
1408  m.scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1409  m *= mi;
1410 
1411  scale(m);
1412 
1413  currentScale_ += Vec3d(0.0, 0.0, scaleValue);
1414 
1415  m = localTransformation_;
1416  m.scale(currentScale_);
1417  m *= mi;
1418 
1419  scale(m);
1420 
1421  } else
1422  //translation
1423  translate(ntrans);
1424 
1425  touched_ = true;
1426  }
1427 
1428  // x top clicked: rotate around x axis
1429  if (rot[0] && (activeRotations_ & X_AXIS)) {
1430 
1431  mapToCylinder(_state, oldPoint2D_);
1432  mapToCylinder(_state, newPoint2D);
1433 
1434  Vec2i dist = oldPoint2D_ - newPoint2D;
1435  int rotation = 0;
1436 
1437  // Rasterize movement if shift is pressed
1438  if (_event->modifiers() == mods) {
1439  if (abs(dist[1]) < (int) (_state.viewport_height() / 16)) {
1440  rotation = 0;
1441  lockOldPoint = true;
1442  } else {
1443  // Rotate exactly 45 degrees
1444  if (dist[1] < 0)
1445  rotation = -45;
1446  else
1447  rotation = 45;
1448  ;
1449  }
1450  } else {
1451  rotation = dist[1];
1452  }
1453 
1454  // Shift has been pressed
1455  // Rotate manipulator but not parent node
1456  if (mode_ == LocalRotation) {
1457 
1458  // Update only local rotation
1459  localTransformation_.rotate(-rotation, directionX(), ACG::MULT_FROM_LEFT);
1460 
1461  } else {
1462  // Rotate parent node but not manipulator
1463  _state.push_modelview_matrix();
1464  _state.translate(center()[0], center()[1], center()[2]);
1465  update_rotation(_state);
1466 
1467  rotate(rotation, directionX());
1468 
1469  _state.pop_modelview_matrix();
1470  }
1471 
1472  touched_ = true;
1473  }
1474 
1475  // y top clicked: rotate around y axis
1476  // or outer ring on zx axis has been clicked
1477  if (rot[1] && (activeRotations_ & Y_AXIS)) {
1478 
1479  mapToCylinder(_state, oldPoint2D_);
1480  mapToCylinder(_state, newPoint2D);
1481 
1482  Vec2i dist = oldPoint2D_ - newPoint2D;
1483  int rotation = 0;
1484 
1485  // Rasterize movement if shift is pressed
1486  if (_event->modifiers() == mods) {
1487  if (abs(dist[1]) < (int) (_state.viewport_width() / 16)) {
1488  rotation = 0;
1489  lockOldPoint = true;
1490  } else {
1491  // Rotate exactly 45 degrees
1492  if (dist[1] < 0)
1493  rotation = -45;
1494  else
1495  rotation = 45;
1496  ;
1497  }
1498  } else {
1499  rotation = dist[1];
1500  }
1501 
1502  if (mode_ == LocalRotation) {
1503 
1504  // Update only local rotation
1505  localTransformation_.rotate(-rotation, directionY(), ACG::MULT_FROM_LEFT);
1506 
1507  } else {
1508  _state.push_modelview_matrix();
1509  _state.translate(center()[0], center()[1], center()[2]);
1510 
1511  rotate(rotation, directionY());
1512 
1513  _state.pop_modelview_matrix();
1514  }
1515 
1516  touched_ = true;
1517  }
1518 
1519  // z top clicked: rotate around z axis
1520  if (rot[2] && (activeRotations_ & Z_AXIS)) {
1521 
1522  mapToCylinder(_state, oldPoint2D_);
1523  mapToCylinder(_state, newPoint2D);
1524 
1525  Vec2i dist = oldPoint2D_ - newPoint2D;
1526 
1527  int rotation = 0;
1528 
1529  // Rasterize movement if shift is pressed
1530  if (_event->modifiers() == mods) {
1531  if (abs(dist[1]) < (int) (_state.viewport_width() / 16)) {
1532  rotation = 0;
1533  lockOldPoint = true;
1534  } else {
1535  // Rotate exactly 45 degrees
1536  if (dist[1] < 0)
1537  rotation = 45;
1538  else
1539  rotation = -45;
1540  ;
1541  }
1542  } else {
1543  rotation = -dist[1];
1544  }
1545 
1546  if (mode_ == LocalRotation) {
1547 
1548  // Update only local rotation
1549  localTransformation_.rotate(-rotation, directionZ(), ACG::MULT_FROM_LEFT); // (dist[0]+dist[1])/2
1550 
1551  } else {
1552  _state.push_modelview_matrix();
1553  _state.translate(center()[0], center()[1], center()[2]);
1554 
1555  rotate(rotation, directionZ());
1556 
1557  _state.pop_modelview_matrix();
1558  }
1559 
1560  touched_ = true;
1561  }
1562 
1563  break;
1564  }
1565 
1566  default: // avoid warning
1567  break;
1568  }
1569 
1570  setDirty();
1571 
1572  // save old Point
1573  if (!lockOldPoint)
1574  oldPoint2D_ = newPoint2D;
1575 }
1576 
1577 
1578 //----------------------------------------------------------------------------
1579 
1582  const Vec2i& _v2)
1583 {
1584  // Qt -> GL coordinate systems
1585  unsigned int x = _v2[0];
1586  unsigned int y = _state.context_height() - _v2[1];
1587 
1588 
1589  // get ray from eye through pixel, in sphere coords
1590  Vec3d origin, direction;
1591 
1592  _state.set_updateGL(false);
1593  _state.push_modelview_matrix();
1594 
1595  update_manipulator_system(_state);
1596  _state.scale(2*manipulator_radius_);
1597 
1598  _state.viewing_ray(x, y, origin, direction);
1599 
1600  _state.pop_modelview_matrix();
1601  _state.set_updateGL(true);
1602 
1603 
1604 
1605  // calc sphere-ray intersection
1606  // (sphere is centered at origin, has radius 1)
1607  double a = direction.sqrnorm(),
1608  b = 2.0 * (origin | direction),
1609  c = origin.sqrnorm() - 1.0,
1610  d = b*b - 4.0*a*c;
1611 
1612  return (d >= 0.0);
1613 }
1614 
1615 
1616 //------------------------------------------------------------------------------------
1617 
1618 
1620 
1622  const Vec2i& _v2)
1623 {
1624  // Qt -> GL coordinate systems
1625  unsigned int x = _v2[0];
1626  unsigned int y = _state.context_height() - _v2[1];
1627 
1628 
1629  // get ray from eye through pixel, in sphere coords
1630  Vec3d origin, direction;
1631 
1632  _state.set_updateGL(false);
1633  _state.push_modelview_matrix();
1634 
1635  update_manipulator_system(_state);
1636  _state.scale(manipulator_height_+4*manipulator_radius_);
1637 
1638  _state.viewing_ray(x, y, origin, direction);
1639 
1640  _state.pop_modelview_matrix();
1641  _state.set_updateGL(true);
1642 
1643 
1644  // calc sphere-ray intersection
1645  // (sphere is centered at origin, has radius 1)
1646  double a = direction.sqrnorm(),
1647  b = 2.0 * (origin | direction),
1648  c = origin.sqrnorm() - 1.0,
1649  d = b*b - 4.0*a*c;
1650 
1651  return (d >= 0.0);
1652 }
1653 
1654 
1655 //------------------------------------------------------------------------------------
1656 
1657 
1660 bool
1662  const Vec2i& _v1,
1663  StateUpdates _updateStates )
1664 {
1665  // Qt -> GL coordinate systems
1666  unsigned int x = _v1[0];
1667  unsigned int y = _state.context_height() - _v1[1];
1668 
1669 
1670  // get ray from eye through pixel (cylinder coords)
1671  Vec3d originX, directionX;
1672  Vec3d originY, directionY;
1673  Vec3d originZ, directionZ;
1674 
1675  _state.set_updateGL(false);
1676  _state.push_modelview_matrix();
1677 
1678  // Now that we have 3 different axes we have to test intersection with each of them
1679  // Z-Axis:
1680  update_manipulator_system(_state);
1681  _state.viewing_ray(x, y, originZ, directionZ);
1682 
1683  // Y-Axis:
1684  _state.rotate(-90, 1.0, 0.0, 0.0);
1685  _state.viewing_ray(x, y, originY, directionY);
1686 
1687  // X-Axis:
1688  _state.rotate(90, 0.0, 1.0, 0.0);
1689  _state.viewing_ray(x, y, originX, directionX);
1690 
1691  _state.pop_modelview_matrix();
1692  _state.set_updateGL(true);
1693 
1694 
1695  // get cylinder axis ray: it's in its own coord system!
1696  // Viewing ray function unprojects screen coordinates thorugh inverse viewport, projection and modelview
1697  // such that we end in local coordinate system of the manipulator.
1698  // local transformation of the manipulator is included in update_manipulator_system which applies the
1699  // local transformation to the current glstate used by viewing_ray
1700  const Vec3d origin2(0,0,0),
1701  cylinderAxis(0.0, 0.0, 1.0); // Always same but we change the coordinate system for the viewer
1702 
1703 
1704  // compute pseude-intersection (x axis)
1705  Vec3d normalX = (directionX % cylinderAxis).normalize();
1706  Vec3d vdX = ((origin2 - originX) % directionX);
1707  double axis_hitX = (normalX | vdX);
1708  double orthodistanceX = std::abs( ( origin2 - originX ) | normalX);
1709 
1710  // compute pseude-intersection (y axis)
1711  Vec3d normalY = (directionY % cylinderAxis).normalize();
1712  Vec3d vdY = ((origin2 - originY) % directionY);
1713  double axis_hitY = (normalY | vdY);
1714  double orthodistanceY = std::abs( ( origin2 - originY ) | normalY);
1715 
1716  // compute pseude-intersection (z axis)
1717  Vec3d normalZ = (directionZ % cylinderAxis).normalize();
1718  Vec3d vdZ = ((origin2 - originZ) % directionZ);
1719  double axis_hitZ = (normalZ | vdZ);
1720  double orthodistanceZ = std::abs( ( origin2 - originZ ) | normalZ);
1721 
1722  if ( _updateStates == None )
1723  return false;
1724 
1725  if ( ( orthodistanceX < manipulator_radius_ ) &&
1726  ( axis_hitX >= 0 ) &&
1727  ( axis_hitX <= manipulator_height_ ) )
1728  {
1729 
1730  // z axis has been hit
1731  if ( _updateStates == Click)
1732  element_[XAxis].clicked_ = true;
1733  else
1734  element_[XAxis].over_ = true;
1735 
1736  } else if ( ( orthodistanceY < manipulator_radius_ ) &&
1737  ( axis_hitY >= 0 ) &&
1738  ( axis_hitY <= manipulator_height_))
1739  {
1740 
1741  // y axis has been hit
1742  if ( _updateStates == Click)
1743  element_[YAxis].clicked_ = true;
1744  else
1745  element_[YAxis].over_ = true;
1746 
1747  } else if ( ( orthodistanceZ < manipulator_radius_ ) &&
1748  ( axis_hitZ >= 0 ) &&
1749  ( axis_hitZ <= manipulator_height_ ) )
1750  {
1751  // x axis has been hit
1752  if ( _updateStates == Click)
1753  element_[ZAxis].clicked_ = true;
1754  else
1755  element_[ZAxis].over_ = true;
1756 
1757  }
1758 
1759  if ( _updateStates == Click)
1760  return (element_[XAxis].clicked_ || element_[YAxis].clicked_ || element_[ZAxis].clicked_);
1761 
1762  return (element_[XAxis].over_ || element_[YAxis].over_ || element_[ZAxis].over_);
1763 }
1764 
1765 
1766 //----------------------------------------------------------------------------
1769 // This method treats the top as cylinder
1770 // TODO: Adapt intersection test to cone shape
1771 bool
1773  const Vec2i& _v1,
1774  StateUpdates _updateStates )
1775 {
1776  // Qt -> GL coordinate systems
1777  unsigned int x = _v1[0];
1778  unsigned int y = _state.context_height() - _v1[1];
1779 
1780 
1781  // get ray from eye through pixel (cylinder coords)
1782  Vec3d originX, directionX;
1783  Vec3d originY, directionY;
1784  Vec3d originZ, directionZ;
1785 
1786  _state.set_updateGL(false);
1787  _state.push_modelview_matrix();
1788 
1789  // Z-Axis:
1790  update_manipulator_system(_state);
1791  _state.translate( 0.0, 0.0, manipulator_height_);
1792  _state.viewing_ray(x, y, originZ, directionZ);
1793  _state.translate( 0.0, 0.0, -manipulator_height_);
1794 
1795  // Y-Axis:
1796  _state.rotate(-90, 1.0, 0.0, 0.0);
1797  _state.translate(0.0, 0.0 , manipulator_height_ );
1798  _state.viewing_ray(x, y, originY, directionY);
1799  _state.translate(0.0, 0.0, -manipulator_height_);
1800 
1801  // X-Axis:
1802  _state.rotate(90, 0.0, 1.0, 0.0);
1803  _state.translate(0.0, 0.0, manipulator_height_);
1804  _state.viewing_ray(x, y, originX, directionX);
1805  _state.translate(0.0, 0.0, -manipulator_height_);
1806 
1807  _state.pop_modelview_matrix();
1808  _state.set_updateGL(true);
1809 
1810 
1811  // get cylinder axis ray: it's in its own coord system!
1812  // Viewing ray function unprojects screen coordinates thorugh inverse viewport, projection and modelview
1813  // such that we end in local coordinate system of the manipulator.
1814  // local transformation of the manipulator is included in update_manipulator_system which applies the
1815  // local transformation to the current glstate used by viewing_ray
1816  const Vec3d origin2(0,0,0),
1817  cylinderAxis(0.0, 0.0, 1.0);
1818 
1819  // compute pseude-intersection (x axis)
1820  Vec3d normalX = (directionX % cylinderAxis).normalize();
1821  Vec3d vdX = ((origin2 - originX) % directionX );
1822  double axis_hitX = (normalX | vdX);
1823  double orthodistanceX = std::abs( ( origin2 - originX ) | normalX);
1824 
1825  // compute pseude-intersection (y axis)
1826  Vec3d normalY = (directionY % cylinderAxis).normalize();
1827  Vec3d vdY = ((origin2 - originY) % directionY);
1828  double axis_hitY = (normalY | vdY);
1829  double orthodistanceY = std::abs( ( origin2 - originY ) | normalY);
1830 
1831  // compute pseude-intersection (z axis)
1832  Vec3d normalZ = (directionZ % cylinderAxis).normalize();
1833  Vec3d vdZ = ((origin2 - originZ) % directionZ);
1834  double axis_hitZ = (normalZ | vdZ);
1835  double orthodistanceZ = std::abs( ( origin2 - originZ ) | normalZ);
1836 
1837  if ( _updateStates == None )
1838  return false;
1839 
1840  // TODO: Work with cones :
1841 
1842  if ( ( orthodistanceX < manipulator_radius_ * 2.0 ) &&
1843  ( axis_hitX >= 0.0 ) &&
1844  ( axis_hitX <= manipulator_height_ / 2.0 ) )
1845  {
1846 
1847  // z top has been hit
1848  if ( _updateStates == Click)
1849  element_[XTop].clicked_ = true;
1850  else
1851  element_[XTop].over_ = true;
1852 
1853  } else if ( ( orthodistanceY < manipulator_radius_ * 2.0 ) &&
1854  ( axis_hitY >= 0.0 ) &&
1855  ( axis_hitY <= manipulator_height_ / 2.0 ) )
1856  {
1857 
1858  // y top has been hit
1859  if ( _updateStates == Click)
1860  element_[YTop].clicked_ = true;
1861  else
1862  element_[YTop].over_ = true;
1863 
1864  } else if ( ( orthodistanceZ < manipulator_radius_ * 2.0 ) &&
1865  ( axis_hitZ >= 0.0 ) &&
1866  ( axis_hitZ <= manipulator_height_ / 2.0 ) )
1867  {
1868 
1869  // x top has been hit
1870  if ( _updateStates == Click)
1871  element_[ZTop].clicked_ = true;
1872  else
1873  element_[ZTop].over_ = true;
1874 
1875  }
1876 
1877  if ( _updateStates == Click)
1878  return (element_[XTop].clicked_ || element_[YTop].clicked_ || element_[ZTop].clicked_);
1879  return (element_[XTop].over_ || element_[YTop].over_ || element_[ZTop].over_);
1880 }
1881 
1882 //----------------------------------------------------------------------------
1883 
1887 bool
1889  const Vec2i& _v2,
1890  Vec3d& _v3,
1891  StateUpdates _updateStates)
1892 {
1893  // Qt -> GL coordinate systems
1894  unsigned int x = _v2[0];
1895  unsigned int y = _state.context_height() - _v2[1];
1896 
1897  // get ray from eye through pixel
1898  Vec3d originXY, directionXY,
1899  originYZ, directionYZ,
1900  originZX, directionZX;
1901 
1902  _state.set_updateGL(false);
1903  _state.push_modelview_matrix();
1904 
1905  update_manipulator_system(_state);
1906 
1907  _state.viewing_ray(x, y, originXY, directionXY);
1908  _state.rotate(90, 0.0, 1.0, 0.0);
1909  _state.viewing_ray(x, y, originYZ, directionYZ);
1910  _state.rotate(90, 1.0, 0.0, 0.0);
1911  _state.viewing_ray(x, y, originZX, directionZX);
1912 
1913  _state.pop_modelview_matrix();
1914  _state.set_updateGL(true);
1915 
1916  // origin + direction * t = (x, y, 0) <=> t = -origin_z / direction_z
1917  // => Point on xy-plane p = (origin_x + direction_x*t, origin_y + direction_y*t, 0)
1918  double t1 = -originXY[2]/directionXY[2];
1919  Vec3d hitPointXY = originXY + directionXY*t1;
1920 
1921  double t2 = -originYZ[2]/directionYZ[2];
1922  Vec3d hitPointYZ = originYZ + directionYZ*t2;
1923 
1924  double t3 = -originZX[2]/directionZX[2];
1925  Vec3d hitPointZX = originZX + directionZX*t3;
1926 
1927  // Depth test: Take nearest object
1928  bool t1_near = false, t2_near = false, t3_near = false;
1929  if( t1 <= t2 && t1 <= t3)
1930  t1_near = true;
1931  if( t2 <= t1 && t2 <= t3)
1932  t2_near = true;
1933  if( t3 <= t1 && t3 <= t2)
1934  t3_near = true;
1935 
1936  bool xy_hit = hitPointXY.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
1937  hitPointXY.length() < 2*manipulator_height_;
1938 
1939  bool yz_hit = hitPointYZ.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
1940  hitPointYZ.length() < 2*manipulator_height_;
1941 
1942  bool zx_hit = hitPointZX.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
1943  hitPointZX.length() < 2*manipulator_height_;
1944 
1945 
1946  bool more_than_one_hit = (xy_hit && yz_hit) || (xy_hit && zx_hit) || (yz_hit && zx_hit);
1947 // std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
1948 // hitPointXY << " < " << 2*manipulator_height_ << std::endl;
1949 //
1950 // std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
1951 // hitPointYZ << " < " << 2*manipulator_height_ << std::endl;
1952 //
1953 // std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
1954 // hitPointZX << " < " << 2*manipulator_height_ << std::endl;
1955 
1956  // Test if hit point on x-y plane matches length of
1957  // manipulator radius_state
1958  if(xy_hit && (!more_than_one_hit || t1_near))
1959  {
1960  // Outer ring on xy plane has been hit
1961  if ( _updateStates == Click)
1962  element_[ZRing].clicked_ = true;
1963  else if ( _updateStates == Over)
1964  element_[ZRing].over_ = true;
1965  _v3 = hitPointXY;
1966  return true;
1967  }
1968 
1969  else if(yz_hit && (!more_than_one_hit || t2_near))
1970  {
1971  // Outer ring on yz plane has been hit
1972  if ( _updateStates == Click)
1973  element_[XRing].clicked_ = true;
1974  else if ( _updateStates == Over)
1975  element_[XRing].over_ = true;
1976  _v3 = hitPointYZ;
1977  return true;
1978  }
1979 
1980  else if(zx_hit && (!more_than_one_hit || t3_near))
1981  {
1982  // Outer ring around zx plane has been hit
1983  if ( _updateStates == Click)
1984  element_[YRing].clicked_ = true;
1985  else if ( _updateStates == Over)
1986  element_[YRing].over_ = true;
1987  _v3 = hitPointZX;
1988  return true;
1989  }
1990 
1991  return false;
1992 }
1993 
1994 //----------------------------------------------------------------------------
1995 
1996 void
1998 pick(GLState& _state, PickTarget _target)
1999 {
2000  GLenum prev_depth = _state.depthFunc();
2001 
2002  if (_target == PICK_FACE ||
2003  _target == PICK_ANYTHING) {
2004 
2005  if (draw_manipulator_) {
2006 
2007  updateSize (_state);
2008 
2009  _state.pick_set_maximum(5);
2010 
2011  // Enable depth test but store original status
2012  if(_state.compatibilityProfile())
2013  glPushAttrib(GL_DEPTH_BUFFER_BIT);
2014  GLboolean depthTest;
2015  glGetBooleanv(GL_DEPTH_TEST, &depthTest);
2016  ACG::GLState::enable(GL_DEPTH_TEST);
2017  ACG::GLState::depthFunc(GL_LEQUAL);
2018 
2019  // Save modelview matrix
2020  _state.push_modelview_matrix();
2021 
2022  // Correctly align nodes local coordinate system
2023  update_manipulator_system(_state);
2024 
2025  _state.pick_set_name(0);
2026  //================================================================================================
2027  // Z-Axis
2028  //================================================================================================
2029  // gluCylinder draws into z direction so z-Axis first
2030 
2031  axisBottom_->setBottomRadius(manipulator_radius_);
2032  axisBottom_->setTopRadius(manipulator_radius_);
2033  axisBottom_->draw(_state, manipulator_height_);
2034 
2035  // Draw Top of z-axis
2036  _state.translate(0.0, 0.0, manipulator_height_);
2037  axisTop_->setBottomRadius(manipulator_radius_*2.0);
2038  axisTop_->setTopRadius(manipulator_radius_*2.0);
2039  axisTop_->draw(_state, manipulator_height_/2.0);
2040  _state.translate(0.0, 0.0, -manipulator_height_);
2041 
2042  _state.pick_set_name(1);
2043  //================================================================================================
2044  // Y-Axis
2045  //================================================================================================
2046  _state.rotate(-90, 1.0, 0.0, 0.0);
2047  axisBottom_->setBottomRadius(manipulator_radius_);
2048  axisBottom_->setTopRadius(manipulator_radius_);
2049  axisBottom_->draw(_state, manipulator_height_);
2050 
2051  // Draw Top of y-axis
2052  _state.translate(0.0, 0.0, manipulator_height_);
2053  axisTop_->setBottomRadius(manipulator_radius_*2.0);
2054  axisTop_->setTopRadius(manipulator_radius_*2.0);
2055  axisTop_->draw(_state, manipulator_height_/2.0);
2056  _state.translate(0.0, 0.0, -manipulator_height_);
2057 
2058 
2059  _state.pick_set_name(2);
2060  //================================================================================================
2061  // X-Axis
2062  //================================================================================================
2063  _state.rotate(90, 0.0, 1.0, 0.0);
2064 
2065  axisBottom_->setBottomRadius(manipulator_radius_);
2066  axisBottom_->setTopRadius(manipulator_radius_);
2067  axisBottom_->draw(_state, manipulator_height_);
2068 
2069  // Draw Top of x-axis
2070  _state.translate(0.0, 0.0, manipulator_height_);
2071  axisTop_->setBottomRadius(manipulator_radius_*2.0);
2072  axisTop_->setTopRadius(manipulator_radius_*2.0);
2073  axisTop_->draw(_state, manipulator_height_/2.0);
2074 
2075  _state.translate(0.0, 0.0, -manipulator_height_);
2076 
2077  _state.pick_set_name(3);
2078  //=================================================================================================
2079  // Sphere
2080  //=================================================================================================
2081 
2082  sphere_->draw(_state, manipulator_radius_*2);
2083 
2084  //=================================================================================================
2085  // Outer-Spheres
2086  //=================================================================================================
2087 
2088  _state.pick_set_name(4);
2089  circle_->setInnerRadius(2.0f*manipulator_height_ - manipulator_height_/4.0f);
2090  circle_->setOuterRadius(2.0f*manipulator_height_);
2091  if ( activeRotations_ & X_AXIS)
2092  circle_->draw(_state);
2093 
2094  _state.rotate(90, 0.0, 1.0, 0.0);
2095  if ( activeRotations_ & Y_AXIS)
2096  circle_->draw(_state);
2097 
2098  _state.rotate(90, 1.0, 0.0, 0.0);
2099  if ( activeRotations_ & Z_AXIS)
2100  circle_->draw(_state);
2101 
2102  // Restore old attributes and modelview
2103  if(_state.compatibilityProfile())
2104  glPopAttrib();
2105  _state.pop_modelview_matrix();
2106 
2107  if(depthTest)
2108  ACG::GLState::enable(GL_DEPTH_TEST);
2109  //restore original depth comparison function
2110  ACG::GLState::depthFunc(prev_depth);
2111  }
2112  }
2113 }
2114 
2115 
2116 //----------------------------------------------------------------------------
2117 
2118 void
2119 TranslationManipulatorNode::set_direction(const Vec3d& _directionX, const Vec3d& _directionY)
2120 {
2121 
2122  localTransformation_.identity();
2123 
2124  const Vec3d cross = _directionX % _directionY;
2125 
2126  localTransformation_(0,0) = _directionX[0];
2127  localTransformation_(1,0) = _directionX[1];
2128  localTransformation_(2,0) = _directionX[2];
2129  localTransformation_(3,0) = 0.0;
2130 
2131  localTransformation_(0,1) = _directionY[0];
2132  localTransformation_(1,1) = _directionY[1];
2133  localTransformation_(2,1) = _directionY[2];
2134  localTransformation_(3,1) = 0.0;
2135 
2136  localTransformation_(0,2) = cross[0];
2137  localTransformation_(1,2) = cross[1];
2138  localTransformation_(2,2) = cross[2];
2139  localTransformation_(3,2) = 0.0;
2140 
2141 }
2142 
2143 //----------------------------------------------------------------------------
2144 
2145 
2146 
2147 
2148 Vec3d
2150 {
2151  Vec3d direction = localTransformation_.transform_vector(dirX_);
2152 
2153  if ( ! OpenMesh::is_zero( direction.sqrnorm() ) )
2154  direction.normalize();
2155  else
2156  direction = Vec3d(0.0,0.0,0.0);
2157 
2158  return direction;
2159 }
2160 
2161 //----------------------------------------------------------------------------
2162 
2163 
2164 Vec3d
2166 {
2167  Vec3d direction = localTransformation_.transform_vector(dirY_);
2168 
2169  if ( ! OpenMesh::is_zero( direction.sqrnorm() ) )
2170  direction.normalize();
2171  else
2172  direction = Vec3d(0.0,0.0,0.0);
2173 
2174  return direction;
2175 }
2176 
2177 //----------------------------------------------------------------------------
2178 
2179 
2180 Vec3d
2182 {
2183  Vec3d direction = localTransformation_.transform_vector(dirZ_);
2184 
2185  if ( ! OpenMesh::is_zero( direction.sqrnorm() ) )
2186  direction.normalize();
2187  else
2188  direction = Vec3d(0.0,0.0,0.0);
2189 
2190  return direction;
2191 }
2192 
2193 //----------------------------------------------------------------------------
2194 
2195 double TranslationManipulatorNode::get_screen_length (GLState& _state, Vec3d& _point) const
2196 {
2197  Vec3d proj = _state.project (_point);
2198  proj[0] += 1.0;
2199  Vec3d uproj = _state.unproject (proj);
2200  uproj -= _point;
2201  return uproj.length ();
2202 }
2203 
2204 //----------------------------------------------------------------------------
2205 
2206 void TranslationManipulatorNode::updateSize (GLState& _state)
2207 {
2208  if (auto_size_ != TranslationManipulatorNode::Never)
2209  {
2210  Vec3d point = localTransformation_.transform_point(Vec3d (0.0, 0.0, 0.0));
2211 
2212  int tmp, width, height;
2213 
2214  _state.get_viewport (tmp, tmp, width, height);
2215 
2216  auto_size_length_ = get_screen_length (_state, point) * (width + height) * 0.02;
2217 
2218  if (auto_size_ == TranslationManipulatorNode::Once)
2219  auto_size_ = TranslationManipulatorNode::Never;
2220  }
2221 
2222  manipulator_radius_ = set_manipulator_radius_ * auto_size_length_;
2223  manipulator_height_ = set_manipulator_height_ * auto_size_length_;
2224 }
2225 
2226 //----------------------------------------------------------------------------
2227 
2228 
2230 {
2231  if (!draw_manipulator_)
2232  return;
2233 
2234  float r = 2 * manipulator_height_;
2235 
2236  _bbMin.minimize(center()+Vec3d(-r,-r,-r));
2237  _bbMax.maximize(center()+Vec3d(r,r,r));
2238 }
2239 
2240 //----------------------------------------------------------------------------
2241 
2243 {
2244  if (mode_ != _mode)
2245  ignoreTime_ = true;
2246  mode_ = _mode;
2247  setDirty ();
2248 }
2249 
2250 //=============================================================================
2251 } // namespace SceneGraph
2252 } // namespace ACG
2253 //=============================================================================
bool mapToCylinder(GLState &_state, const Vec2i &_v2, StateUpdates _updateStates=None)
Vec3d directionZ() const
Get current direction of z-Axis in world coordinates.
bool invert()
matrix inversion (returns true on success)
vector_type & maximize(const vector_type &_rhs)
maximize values: same as *this = max(*this, _rhs), but faster
Definition: Vector11T.hh:563
const Vec4f & specular_color() const
get specular color
Definition: GLState.hh:941
Namespace providing different geometric functions concerning angles.
void clearTextures()
disables texture support and removes all texture types
const GLMatrixd & inverse_scale() const
return inverse scale matrix
void pick(GLState &_state, PickTarget _target)
leave node
void translate(const Vec3d &_v)
Add a translation to the current Transformation.
void update_rotation(GLState &_state)
update the internal rotation matrix ( internal rotation may be changed without modifiing children of ...
void set_specular_color(const Vec4f &_col)
set specular color
Definition: GLState.cc:737
void set_ambient_color(const Vec4f &_col)
set ambient color
Definition: GLState.cc:707
pick any of the prior targets (should be implemented for all nodes)
Definition: PickTarget.hh:84
int context_width() const
get gl context width
Definition: GLState.hh:827
auto norm() const -> decltype(std::sqrt(std::declval< VectorT< S, DIM >>().sqrnorm()))
compute euclidean norm
Definition: Vector11T.hh:409
void set_diffuse_color(const Vec4f &_col)
set diffuse color
Definition: GLState.cc:722
decltype(std::declval< S >() *std::declval< S >()) sqrnorm() const
compute squared euclidean norm
Definition: Vector11T.hh:397
void push_modelview_matrix()
push modelview matrix
Definition: GLState.cc:1010
void set_updateGL(bool _b)
should GL matrices be updated after each matrix operation
Definition: GLState.hh:235
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:941
static void enable(GLenum _cap, bool _warnRemoved=true)
replaces glEnable, but supports locking
int context_height() const
get gl context height
Definition: GLState.hh:830
const GLMatrixd & scale() const
return scale matrix
virtual void mouseEvent(GLState &_state, QMouseEvent *_event)
get mouse events
ManipulatorMode
enum to define the manipulator mode
VectorT< float, 4 > Vec4f
Definition: VectorT.hh:138
void set_color(const Vec4f &_col)
set color
Definition: GLState.cc:691
void translate(double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
translate by (_x, _y, _z)
Definition: GLState.cc:533
void initFromState(GLState *_glState)
Initializes a RenderObject instance.
Definition: RenderObject.cc:61
int viewport_width() const
get viewport width
Definition: GLState.hh:822
void setMode(ManipulatorMode _mode)
set current operation mode
GLMatrixd modelview
Modelview transform.
auto normalize() -> decltype(*this/=std::declval< VectorT< S, DIM >>().norm())
Definition: Vector11T.hh:429
static void disable(GLenum _cap, bool _warnRemoved=true)
replaces glDisable, but supports locking
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)
Interface class between scenegraph and renderer.
Definition: RenderObject.hh:98
GLMatrixd computeWorldMatrix()
computes world matrix, transforms from model to world space
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
GLenum depthFunc
GL_LESS, GL_LEQUAL, GL_GREATER ..
VectorT< double, 2 > Vec2d
Definition: VectorT.hh:104
void boundingBox(Vec3d &_bbMin, Vec3d &_bbMax)
bounding box of node
const GLMatrixd & inverse_rotation() const
return inverse rotation matrix
void set_direction(const Vec3d &_directionX, const Vec3d &_directionY)
Set direction in world coordinates.
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
void setDirty(bool _dirty=true)
mark node for redrawn
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
void scale(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with scaling matrix (x,y,z)
void setTraverseMode(unsigned int _mode)
Set traverse mode for node.
static void shadeModel(GLenum _mode)
replaces glShadeModel, supports locking
Vec3d directionY() const
Get current direction of y-Axis in world coordinates.
int viewport_height() const
get viewport height
Definition: GLState.hh:824
Execute action the children first and then on this node.
Definition: BaseNode.hh:443
void get_viewport(int &_left, int &_bottom, int &_width, int &_height) const
get viewport
Definition: GLState.hh:816
TranslationManipulatorNode(BaseNode *_parent=0, const std::string &_name="<TranslationTranslationManipulatorNode>")
Default constructor.
bool touched_
stores if this manipulator was used in order to avoid emitting manipulatorMoved unnecessarily ...
bool hitSphere(GLState &_state, const Vec2i &_v2)
Determine whether the origin sphere has been hit.
void viewing_ray(int _x, int _y, Vec3d &_origin, Vec3d &_direction) const
Definition: GLState.cc:930
const GLMatrixd & rotation() const
return rotation matrix
void getRenderObjects(IRenderer *_renderer, GLState &_state, const DrawModes::DrawMode &_drawMode, const Material *_mat)
create renderobjects for shaderpipeline renderer
auto length() const -> decltype(std::declval< VectorT< S, DIM >>().norm())
compute squared euclidean norm
Definition: Vector11T.hh:418
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:791
ShaderGenDesc shaderDesc
Drawmode and other shader params.
bool is_zero(const T &_a, Real _eps)
Definition: MathDefs.hh:61
PickTarget
What target to use for picking.
Definition: PickTarget.hh:73
vector_type & minimize(const vector_type &_rhs)
minimize values: same as *this = min(*this, _rhs), but faster
Definition: Vector11T.hh:535
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
std::string name
Name for logging.
void pop_modelview_matrix()
pop modelview matrix
Definition: GLState.cc:1026
void identity()
setup an identity matrix
void draw(GLState &_state, const DrawModes::DrawMode &_drawMode)
draw the cylinder (if enabled)
void scale(double _s)
scale by (_s, _s, _s)
Definition: GLState.hh:750
picks faces (should be implemented for all nodes)
Definition: PickTarget.hh:78
void update_manipulator_system(GLState &_state)
set the current state to follow manipulator transformation
bool mapToSphere(GLState &_state, const Vec2i &_v2, Vec3d &_v3, StateUpdates _updateStates=None)
void set_modelview(const GLMatrixd &_m)
set modelview
Definition: GLState.hh:728
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
void rotate(Scalar angle, Scalar x, Scalar y, Scalar z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
const Vec4f & diffuse_color() const
get diffuse color
Definition: GLState.hh:936
GLenum blendDest
glBlendFunc: GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ONE_MINUS_SRC_ALPHA ...
bool mapToCylinderTop(GLState &_state, const Vec2i &_v2, StateUpdates _updateStates=None)
unsigned int msSinceLastRedraw() const
time passed since last redraw in milliseconds
Definition: GLState.hh:238
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)
void translate(Scalar _x, Scalar _y, Scalar _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
multiply self with translation matrix (x,y,z)
const Vec3d & center() const
get center
bool hitOuterSphere(GLState &_state, const Vec2i &_v2)
Determine whether the outer sphere has been hit by the cursor.
bool pick_set_maximum(size_t _idx)
Set the maximal number of primitives/components of your object.
Definition: GLState.cc:1051
void pick_set_name(size_t _idx)
sets the current name/color (like glLoadName(_idx))
Definition: GLState.cc:1061
int priority
Priority to allow sorting of objects.
Vec3d directionX() const
Get current direction of x-Axis in world coordinates.