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