Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
TranslationManipulatorNode.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 
51 
52 
53 //=============================================================================
54 //
55 // CLASS TranslationManipulatorNode - IMPLEMENTATION
56 //
57 //=============================================================================
58 
59 
60 //== INCLUDES =================================================================
61 
62 
63 #include "TranslationManipulatorNode.hh"
64 
65 #include <ACG/GL/IRenderer.hh>
66 
67 #include <Math_Tools/Math_Tools.hh>
68 
69 //== NAMESPACES ===============================================================
70 
71 
72 namespace ACG {
73 namespace SceneGraph {
74 
75 
76 //== IMPLEMENTATION ==========================================================
77 
78 // How many pixels should the cursor be away from the dragging center
79 // for the translation operation to affect the geometry's position
80 #define SNAP_PIXEL_TOLERANCE 30
81 
82 // Node colors (normal, over, clicked, occluded normal, occluded over, occluded clicked)
83 
84 const Vec4f colors[4][6] = {
85  // origin
86  {
87  // normal
88  Vec4f(0.2f,0.2f,0.2f,1.0f), Vec4f(0.5f,0.5f,0.5f,1.0f), Vec4f(0.8f,0.8f,0.8f,1.0f),
89  // occluded
90  Vec4f(0.2f,0.2f,0.2f,0.2f), Vec4f(0.5f,0.5f,0.5f,0.4f), Vec4f(0.8f,0.8f,0.8f,0.6f)
91  },
92  // X
93  {
94  // normal
95  Vec4f(0.2f,0.0f,0.0f,1.0f), Vec4f(0.5f,0.0f,0.0f,1.0f), Vec4f(0.8f,0.0f,0.0f,1.0f),
96  // occluded
97  Vec4f(0.3f,0.1f,0.1f,0.2f), Vec4f(0.5f,0.2f,0.2f,0.4f), Vec4f(0.8f,0.4f,0.4f,0.6f)
98  },
99  // Y
100  {
101  // normal
102  Vec4f(0.0f,0.2f,0.0f,1.0f), Vec4f(0.0f,0.5f,0.0f,1.0f), Vec4f(0.0f,0.8f,0.0f,1.0f),
103  // occluded
104  Vec4f(0.1f,0.3f,0.1f,0.2f), Vec4f(0.2f,0.5f,0.2f,0.4f), Vec4f(0.4f,0.8f,0.4f,0.6f)
105  },
106  // Z
107  {
108  // normal
109  Vec4f(0.0f,0.0f,0.2f,1.0f), Vec4f(0.0f,0.0f,0.5f,1.0f), Vec4f(0.0f,0.0f,0.8f,1.0f),
110  // occluded
111  Vec4f(0.1f,0.1f,0.3f,0.2f), Vec4f(0.2f,0.2f,0.5f,0.4f), Vec4f(0.4f,0.4f,0.8f,0.6f)
112  }
113 };
114 
115 
116 //----------------------------------------------------------------------------
117 
118 TranslationManipulatorNode::Element::Element () :
119  active_target_color_ (0.0, 0.0, 0.0, 1.0),
120  active_current_color_ (0.0, 0.0, 0.0, 1.0),
121  inactive_target_color_ (0.0, 0.0, 0.0, 1.0),
122  inactive_current_color_ (0.0, 0.0, 0.0, 1.0),
123  clicked_ (false),
124  over_ (false)
125 {
126 }
127 
128 //----------------------------------------------------------------------------
129 
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] * static_cast<float>(0.5) ) + (colors[((i-1)%3) + 1][2] * static_cast<float>(0.5));
303  element_[i].inactive_target_color_ = (colors[0][5] * static_cast<float>(0.5)) + (colors[((i-1)%3) + 1][5] * static_cast<float>(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] * static_cast<float>(0.5)) + (colors[((i-1)%3) + 1][1] * static_cast<float>(0.5));
312  element_[i].inactive_target_color_ = (colors[0][4] * static_cast<float>(0.5)) + (colors[((i-1)%3) + 1][4] * static_cast<float>(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  ro.alpha = 1.0f;
822 
823  addManipulatorToRenderer(_renderer, &ro, true);
824  }
825 }
826 
827 //----------------------------------------------------------------------------
828 
829 void TranslationManipulatorNode::addAxisToRenderer (IRenderer* _renderer, RenderObject* _baseRO, bool _active, int _axis)
830 {
831  assert(_axis >= XAxis && _axis - 3 >= 0 && _axis <= ZAxis);
832 
833  for (int i = 0; i < 3; ++i)
834  _baseRO->emissive[i] = _active ? element_[_axis].active_current_color_[i] : element_[_axis].inactive_current_color_[i];
835 
836  // Draw Bottom
837  axisBottom_->setBottomRadius((1.0 - resize_current_) * manipulator_radius_);
838  axisBottom_->setTopRadius((1.0 + resize_current_) * manipulator_radius_);
839  axisBottom_->addToRenderer(_renderer, _baseRO, manipulator_height_/2.0f);
840 
841  // Draw center
842  _baseRO->modelview.translate(0.0, 0.0, manipulator_height_/2);
843 
844  axisCenter_->setBottomRadius(manipulator_radius_);
845  axisCenter_->setTopRadius(manipulator_radius_);
846  axisCenter_->addToRenderer(_renderer, _baseRO, manipulator_height_/2.0f);
847 
848 
849  // Draw top
850 
851  // _axis - 3 computes id of axis-top in 'Elements' enum
852  for (int i = 0; i < 3; ++i)
853  _baseRO->emissive[i] = _active ? (element_[_axis-3].active_current_color_[i]) : (element_[_axis-3].inactive_current_color_[i]);
854 
855  _baseRO->modelview.translate(0.0, 0.0, manipulator_height_/2);
856  axisTop_->setBottomRadius(manipulator_radius_*2.0);
857  axisTop_->setTopRadius(0.0);
858  axisTop_->addToRenderer(_renderer, _baseRO, manipulator_height_/2.0f);
859  _baseRO->modelview.translate(0.0, 0.0, -manipulator_height_);
860 
861 }
862 
863 //----------------------------------------------------------------------------
864 
865 void TranslationManipulatorNode::addManipulatorToRenderer (IRenderer* _renderer, RenderObject* _baseRO, bool _active)
866 {
867  _baseRO->culling = false;
868 
869  GLMatrixd oldModelview = _baseRO->modelview;
870 
871  //================================================================================================
872  // Z-Axis
873  //================================================================================================
874  // gluCylinder draws into z direction so z-Axis first
875 
876  _baseRO->debugName = "TranslationManipulatorNode.z";
877  addAxisToRenderer(_renderer, _baseRO, _active, ZAxis);
878 
879  //================================================================================================
880  // Y-Axis
881  //================================================================================================
882 
883  _baseRO->debugName = "TranslationManipulatorNode.y";
884  _baseRO->modelview.rotate(-90, 1.0, 0.0, 0.0);
885  addAxisToRenderer(_renderer, _baseRO, _active, YAxis);
886 
887  //================================================================================================
888  // X-Axis
889  //================================================================================================
890 
891  _baseRO->debugName = "TranslationManipulatorNode.x";
892  _baseRO->modelview.rotate(90, 0.0, 1.0, 0.0);
893  addAxisToRenderer(_renderer, _baseRO, _active, XAxis);
894 
895  //=================================================================================================
896  // Sphere
897  //=================================================================================================
898 
899  _baseRO->debugName = "TranslationManipulatorNode.sphere";
900 
901  for (int i = 0; i < 3; ++i)
902  _baseRO->emissive[i] = _active ? (element_[Origin].active_current_color_[i]) : (element_[Origin].inactive_current_color_[i]);
903 
904  sphere_->addToRenderer(_renderer, _baseRO, manipulator_radius_ * 2.0f);
905 
906  //=================================================================================================
907  // Outer-Rings
908  //=================================================================================================
909 
910 // _baseRO->blending = true;
911 
912  // update circle size
913  circle_->setInnerRadius(2.0f*manipulator_height_ - manipulator_height_/4.0f);
914  circle_->setOuterRadius(2.0f*manipulator_height_);
915 
916  if ( activeRotations_ & X_AXIS)
917  {
918  _baseRO->name = "TranslationManipulatorNode.x_ring";
919 
920  for (int i = 0; i < 3; ++i)
921  _baseRO->emissive[i] = _active ? (element_[XRing].active_current_color_[i]) : (element_[XRing].inactive_current_color_[i]);
922 
923  circle_->addToRenderer_primitive(_renderer, _baseRO);
924  }
925 
926 
927  _baseRO->modelview.rotate(90, 0.0, 1.0, 0.0);
928  if ( activeRotations_ & Y_AXIS)
929  {
930  _baseRO->debugName = "TranslationManipulatorNode.y_ring";
931 
932  for (int i = 0; i < 3; ++i)
933  _baseRO->emissive[i] = _active ? (element_[YRing].active_current_color_[i]) : (element_[YRing].inactive_current_color_[i]);
934  circle_->addToRenderer_primitive(_renderer, _baseRO);
935  }
936 
937  _baseRO->modelview.rotate(90, 1.0, 0.0, 0.0);
938  if ( activeRotations_ & Z_AXIS)
939  {
940  _baseRO->debugName = "TranslationManipulatorNode.z_ring";
941 
942  for (int i = 0; i < 3; ++i)
943  _baseRO->emissive[i] = _active ? (element_[ZRing].active_current_color_[i]) : (element_[ZRing].inactive_current_color_[i]);
944  circle_->addToRenderer_primitive(_renderer, _baseRO);
945  }
946 
947  _baseRO->modelview = oldModelview;
948 }
949 
950 //----------------------------------------------------------------------------
951 
952 // void
953 // TranslationManipulatorNode::leave(GLState& _state, const DrawModes::DrawMode& /* _drawMode */ )
954 // {
955 
956 // }
957 
958 //----------------------------------------------------------------------------
959 
960 void
961 TranslationManipulatorNode::mouseEvent(GLState& _state, QMouseEvent* _event)
962 {
963  if (!draw_manipulator_)
964  return; // Avoid transformation of object while transformator is invisible
965 
966  Vec3d oldPoint3D;
967  Vec2i newPoint2D(_event->pos().x(), _event->pos().y());
968  Vec3d newPoint3D;
969  bool rot[3], trans[3];
970  unsigned int i;
971  bool lockOldPoint = false;
972 
973  updateSize(_state);
974 
975  switch (_event->type()) {
976 
977  // If mouse is pressed check if any part of the manipulator is hit and store that state
978  case QEvent::MouseButtonPress: {
979  for (i = 0; i < NumElements; i++)
980  element_[i].clicked_ = false;
981 
982  // Start dragging process
983  if (!dragging_) {
984  draggingOrigin3D_ = center();
985  dragging_ = true;
986  }
987 
988  // hit origin ?
989  if ((mode_ != LocalRotation) && (mode_ != Rotation))
990  element_[Origin].clicked_ = hitSphere(_state, newPoint2D);
991  else
992  element_[Origin].clicked_ = false;
993 
994  // hit any top ?
995  any_top_clicked_ = mapToCylinderTop(_state, newPoint2D, Click);
996 
997  // hit any axis ?
998  any_axis_clicked_ = mapToCylinder(_state, newPoint2D, Click);
999 
1000  // hit one of the outer rings ?
1001  if (mode_ != Resize)
1002  outer_ring_clicked_ = mapToSphere(_state, newPoint2D, newPoint3D, Click);
1003  else
1004  outer_ring_clicked_ = false;
1005 
1006  // origin has been hit, ignore all other parts
1007  if (element_[Origin].clicked_) {
1008  for (i = 1; i < NumElements; i++)
1009  element_[i].clicked_ = false;
1010  any_axis_clicked_ = false;
1011  any_top_clicked_ = false;
1012  outer_ring_clicked_ = false;
1013  } else if (any_top_clicked_) { // tops override the axes
1014  for (i = XAxis; i < NumElements; i++)
1015  element_[i].clicked_ = false;
1016  any_axis_clicked_ = false;
1017  outer_ring_clicked_ = false;
1018  } else if (any_axis_clicked_) { // axes have been hit, disable rest ... should not be required
1019  for (i = XRing; i < NumElements; i++)
1020  element_[i].clicked_ = false;
1021  outer_ring_clicked_ = false;
1022  } else if (outer_ring_clicked_) { // Nothing except the outer ring has been hit
1023  for (i = 0; i < XRing; i++)
1024  element_[i].clicked_ = false;
1025  any_axis_clicked_ = false;
1026  any_top_clicked_ = false;
1027  }
1028 
1029  // Reset local transformation:
1030  if ( (_event->modifiers() & Qt::ControlModifier) && (_event->modifiers() & Qt::AltModifier) ) {
1031  localTransformation_.identity();
1032  }
1033 
1034  oldPoint2D_ = newPoint2D;
1035  currentScale_ = Vec3d(1.0, 1.0, 1.0);
1036  ignoreTime_ = true;
1037 
1038  touched_ = element_[Origin].clicked_
1039  || any_top_clicked_
1040  || any_axis_clicked_
1041  || outer_ring_clicked_;
1042  break;
1043  }
1044 
1045  // Reset all states as we stopped manipulating
1046  case QEvent::MouseButtonRelease: {
1047 
1048  for (i = 0; i < NumElements; i++) {
1049  if (element_[i].clicked_)
1050  touched_ = true;
1051  element_[i].clicked_ = false;
1052  }
1053 
1054  touched_ = touched_
1055  || any_top_clicked_
1056  || any_axis_clicked_
1057  || outer_ring_clicked_;
1058 
1059  any_axis_clicked_ = false;
1060  any_top_clicked_ = false;
1061  outer_ring_clicked_ = false;
1062  ignoreTime_ = true;
1063  dragging_ = false;
1064  break;
1065  }
1066 
1067  case QEvent::MouseButtonDblClick: {
1068  draw_manipulator_ = !draw_manipulator_;
1069  break;
1070  }
1071 
1072  // All real manipulation is done here
1073  case QEvent::MouseMove: {
1074  if (!draw_manipulator_) {
1075  touched_ = false;
1076  return; // Avoid manipulation if manipulator is invisible
1077  }
1078 
1079  // Get pressed modifiers
1080  Qt::KeyboardModifiers mods = Qt::ShiftModifier | Qt::ControlModifier;
1081 
1082  for (i = 0; i < NumElements; i++)
1083  element_[i].over_ = false;
1084  any_axis_over_ = false;
1085  any_top_over_ = false;
1086  outer_ring_over_ = false;
1087 
1088  if (!(element_[Origin].clicked_ || any_top_clicked_ || any_axis_clicked_ || outer_ring_clicked_)) {
1089  // over origin ?
1090  if ((mode_ != LocalRotation) && (mode_ != Rotation))
1091  element_[Origin].over_ = hitSphere(_state, newPoint2D);
1092  else
1093  element_[Origin].over_ = false;
1094 
1095 
1096  // over any top ?
1097  if (mode_ != Place) {
1098  any_top_over_ = mapToCylinderTop(_state, newPoint2D, Over);
1099  }
1100 
1101  // over any axis ?
1102  if (mode_ != Place) {
1103  any_axis_over_ = mapToCylinder(_state, newPoint2D, Over);
1104  }
1105 
1106  // over one of the outer rings ?
1107  if (mode_ != Resize) {
1108  outer_ring_over_ = mapToSphere(_state, newPoint2D, newPoint3D, Over);
1109  } else {
1110  outer_ring_over_ = false;
1111  }
1112 
1113  // origin has been hit, ignore all other parts
1114  if (element_[Origin].over_) {
1115  for (i = 1; i < NumElements; i++)
1116  element_[i].over_ = false;
1117  any_axis_over_ = false;
1118  any_top_over_ = false;
1119  outer_ring_over_ = false;
1120  } else if (any_top_over_) { // tops override the axes
1121  for (i = XAxis; i < NumElements; i++)
1122  element_[i].over_ = false;
1123  any_axis_over_ = false;
1124  outer_ring_over_ = false;
1125  } else if (any_axis_over_) { // axes have been hit, disable rest ... should not be required
1126  for (i = XRing; i < NumElements; i++)
1127  element_[i].over_ = false;
1128  outer_ring_over_ = false;
1129  } else if (outer_ring_over_) { // Nothing except the outer ring has been hit
1130  for (i = 0; i < XRing; i++)
1131  element_[i].over_ = false;
1132  any_axis_over_ = false;
1133  any_top_over_ = false;
1134  }
1135  }
1136 
1137  // set action for the different modes
1138  switch (mode_) {
1139  case Rotation:
1140  for (i = 0; i < 3; i++) {
1141  rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_;
1142  trans[i] = false;
1143  }
1144  break;
1145  case TranslationRotation:
1146  for (i = 0; i < 3; i++) {
1147  rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_;
1148  trans[i] = element_[XAxis + i].clicked_;
1149  }
1150  break;
1151  case LocalRotation:
1152  for (i = 0; i < 3; i++) {
1153  rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_ || element_[XAxis + i].clicked_;
1154  trans[i] = false;
1155  }
1156  break;
1157  case Place:
1158  break;
1159  case Resize:
1160  for (i = 0; i < 3; i++) {
1161  rot[i] = false;
1162  trans[i] = element_[XTop + i].clicked_ || element_[XAxis + i].clicked_;
1163  }
1164  break;
1165  }
1166 
1167  // If origin was clicked on
1168  if (element_[Origin].clicked_) {
1169 
1170  // translate along screen plane ( unproject to get world coords for translation and apply them )
1171 
1172  Vec3d d = _state.project(center());
1173  Vec3d d_origin = _state.project(draggingOrigin3D_);
1174 
1175  // Snap back to origin position if mouse cursor
1176  // is near enough
1177  if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1178  && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1179  && (_event->modifiers() & Qt::AltModifier) ) {
1180  newPoint2D = oldPoint2D_;
1181  Vec3d backtrans = draggingOrigin3D_ - center();
1182  if (mode_ != Resize) {
1183  translate(backtrans);
1184  }
1185  }
1186 
1187  // translate along screen plane ( unproject to get world coords for translation and apply them )
1188  Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1189  Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1190  Vec3d ntrans = newvec - oldvec;
1191 
1192  if (mode_ != Resize)
1193  translate(ntrans);
1194  else {
1195  // revert last scale
1196  scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1197  double positive = -1;
1198  if (newPoint2D[0] - oldPoint2D_[0] + oldPoint2D_[1] - newPoint2D[1] > 0)
1199  positive = 1;
1200 
1201  Vec2d div = Vec2d(newPoint2D[0], newPoint2D[1]) - Vec2d(oldPoint2D_[0], oldPoint2D_[1]);
1202 
1203  double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1204  scaleValue *= positive;
1205  currentScale_ += Vec3d(scaleValue, scaleValue, scaleValue);
1206 
1207  scale(currentScale_);
1208  }
1209 
1210  touched_ = true;
1211  }
1212 
1213  // x axis clicked apply translation along axis
1214  if (trans[0]) {
1215 
1216  mapToCylinder(_state, oldPoint2D_);
1217  mapToCylinder(_state, newPoint2D);
1218 
1219  // translate
1220  // Get screen coordinates of current mouse position and unproject them
1221  // into world coordinates. Project onto selected axis and apply resulting
1222  // vector as translation
1223 
1224  Vec3d d = _state.project(center());
1225  Vec3d d_origin = _state.project(draggingOrigin3D_);
1226 
1227  // Snap back to origin position if mouse cursor
1228  // is near enough
1229  if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1230  && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1231  && (_event->modifiers() & Qt::AltModifier) ) {
1232  newPoint2D = oldPoint2D_;
1233  Vec3d backtrans = draggingOrigin3D_ - center();
1234  if (mode_ != Resize) {
1235  translate(backtrans);
1236  }
1237  }
1238  Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1239  Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1240  Vec3d ntrans = newvec - oldvec;
1241 
1242  // project to current direction
1243  ntrans = (ntrans | directionX()) * directionX();
1244 
1245  if (mode_ == Resize) {
1246  //scaling
1247  double positive = -1;
1248  if ((directionX() | ntrans) > 0)
1249  positive = 1;
1250 
1251  if (currentScale_[0] < 0)
1252  positive *= -1;
1253 
1254  Vec3d proj = _state.project(ntrans + oldvec);
1255 
1256  Vec2d div = Vec2d(proj[0], proj[1]) - Vec2d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
1257 
1258  double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1259  scaleValue *= positive;
1260 
1261  // revert last scale
1262  GLMatrixd m = localTransformation_;
1263  GLMatrixd mi = localTransformation_;
1264  mi.invert();
1265 
1266  m.scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1267  m *= mi;
1268 
1269  scale(m);
1270 
1271  currentScale_ += Vec3d(scaleValue, 0.0, 0.0);
1272 
1273  m = localTransformation_;
1274  m.scale(currentScale_);
1275  m *= mi;
1276 
1277  scale(m);
1278  } else
1279  //translation
1280  translate(ntrans);
1281 
1282  touched_ = true;
1283  }
1284 
1285  // y axis clicked change translation along axis
1286  if (trans[1]) {
1287 
1288  mapToCylinder(_state, oldPoint2D_);
1289  mapToCylinder(_state, newPoint2D);
1290 
1291  // translate
1292  // Get screen coordinates of current mouse position and unproject them
1293  // into world coordinates. Project onto selected axis and apply resulting
1294  // vector as translation
1295 
1296  Vec3d d = _state.project(center());
1297  Vec3d d_origin = _state.project(draggingOrigin3D_);
1298 
1299  // Snap back to origin position if mouse cursor
1300  // is near enough
1301  if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1302  && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1303  && (_event->modifiers() & Qt::AltModifier) ) {
1304  newPoint2D = oldPoint2D_;
1305  Vec3d backtrans = draggingOrigin3D_ - center();
1306  if (mode_ != Resize) {
1307  translate(backtrans);
1308  }
1309  }
1310  Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1311  Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1312  Vec3d ntrans = newvec - oldvec;
1313 
1314  // project to current direction
1315  ntrans = (ntrans | directionY()) * directionY();
1316 
1317  if (mode_ == Resize) {
1318  //scaling
1319  double positive = -1;
1320  if ((directionY() | ntrans) > 0)
1321  positive = 1;
1322 
1323  if (currentScale_[1] < 0)
1324  positive *= -1;
1325 
1326  Vec3d proj = _state.project(ntrans + oldvec);
1327 
1328  Vec2d div = Vec2d(proj[0], proj[1]) - Vec2d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
1329 
1330  double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1331  scaleValue *= positive;
1332 
1333  // revert last scale
1334  GLMatrixd m = localTransformation_;
1335  GLMatrixd mi = localTransformation_;
1336  mi.invert();
1337 
1338  m.scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1339  m *= mi;
1340 
1341  scale(m);
1342 
1343  currentScale_ += Vec3d(0.0, scaleValue, 0.0);
1344 
1345  m = localTransformation_;
1346  m.scale(currentScale_);
1347  m *= mi;
1348 
1349  scale(m);
1350 
1351  } else
1352  //translation
1353  translate(ntrans);
1354 
1355  touched_ = true;
1356  }
1357 
1358  // z axis clicked change translation along axis
1359  if (trans[2]) {
1360 
1361  mapToCylinder(_state, oldPoint2D_);
1362  mapToCylinder(_state, newPoint2D);
1363 
1364  // translate
1365  // Get screen coordinates of current mouse position and unproject them
1366  // into world coordinates. Project onto selected axis and apply resulting
1367  // vector as translation
1368 
1369  Vec3d d = _state.project(center());
1370  Vec3d d_origin = _state.project(draggingOrigin3D_);
1371 
1372  // Snap back to origin position if mouse cursor
1373  // is near enough
1374  if (std::abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE
1375  && std::abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
1376  && (_event->modifiers() & Qt::AltModifier) ) {
1377  newPoint2D = oldPoint2D_;
1378  Vec3d backtrans = draggingOrigin3D_ - center();
1379  if (mode_ != Resize) {
1380  translate(backtrans);
1381  }
1382  }
1383  Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
1384  Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
1385  Vec3d ntrans = newvec - oldvec;
1386 
1387  // project to current direction
1388  ntrans = (ntrans | directionZ()) * directionZ();
1389 
1390  if (mode_ == Resize) {
1391  //scaling
1392  double positive = -1;
1393  if ((directionZ() | ntrans) > 0)
1394  positive = 1;
1395 
1396  if (currentScale_[2] < 0)
1397  positive *= -1;
1398 
1399  Vec3d proj = _state.project(ntrans + oldvec);
1400 
1401  Vec2d div = Vec2d(proj[0], proj[1]) - Vec2d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
1402 
1403  double scaleValue = div.norm() * 3.0 / qMin(_state.context_height(), _state.context_width());
1404  scaleValue *= positive;
1405 
1406  // revert last scale
1407  GLMatrixd m = localTransformation_;
1408  GLMatrixd mi = localTransformation_;
1409  mi.invert();
1410 
1411  m.scale(Vec3d(1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
1412  m *= mi;
1413 
1414  scale(m);
1415 
1416  currentScale_ += Vec3d(0.0, 0.0, scaleValue);
1417 
1418  m = localTransformation_;
1419  m.scale(currentScale_);
1420  m *= mi;
1421 
1422  scale(m);
1423 
1424  } else
1425  //translation
1426  translate(ntrans);
1427 
1428  touched_ = true;
1429  }
1430 
1431  // x top clicked: rotate around x axis
1432  if (rot[0] && (activeRotations_ & X_AXIS)) {
1433 
1434  mapToCylinder(_state, oldPoint2D_);
1435  mapToCylinder(_state, newPoint2D);
1436 
1437  Vec2i dist = oldPoint2D_ - newPoint2D;
1438  int rotation = 0;
1439 
1440  // Rasterize movement if shift is pressed
1441  if (_event->modifiers() == mods) {
1442  if (abs(dist[1]) < (int) (_state.viewport_height() / 16)) {
1443  rotation = 0;
1444  lockOldPoint = true;
1445  } else {
1446  // Rotate exactly 45 degrees
1447  if (dist[1] < 0)
1448  rotation = -45;
1449  else
1450  rotation = 45;
1451  ;
1452  }
1453  } else {
1454  rotation = dist[1];
1455  }
1456 
1457  // Shift has been pressed
1458  // Rotate manipulator but not parent node
1459  if (mode_ == LocalRotation) {
1460 
1461  // Update only local rotation
1462  localTransformation_.rotate(-rotation, directionX(), ACG::MULT_FROM_LEFT);
1463 
1464  } else {
1465  // Rotate parent node but not manipulator
1466  _state.push_modelview_matrix();
1467  _state.translate(center()[0], center()[1], center()[2]);
1468  update_rotation(_state);
1469 
1470  rotate(rotation, directionX());
1471 
1472  _state.pop_modelview_matrix();
1473  }
1474 
1475  touched_ = true;
1476  }
1477 
1478  // y top clicked: rotate around y axis
1479  // or outer ring on zx axis has been clicked
1480  if (rot[1] && (activeRotations_ & Y_AXIS)) {
1481 
1482  mapToCylinder(_state, oldPoint2D_);
1483  mapToCylinder(_state, newPoint2D);
1484 
1485  Vec2i dist = oldPoint2D_ - newPoint2D;
1486  int rotation = 0;
1487 
1488  // Rasterize movement if shift is pressed
1489  if (_event->modifiers() == mods) {
1490  if (abs(dist[1]) < (int) (_state.viewport_width() / 16)) {
1491  rotation = 0;
1492  lockOldPoint = true;
1493  } else {
1494  // Rotate exactly 45 degrees
1495  if (dist[1] < 0)
1496  rotation = -45;
1497  else
1498  rotation = 45;
1499  ;
1500  }
1501  } else {
1502  rotation = dist[1];
1503  }
1504 
1505  if (mode_ == LocalRotation) {
1506 
1507  // Update only local rotation
1508  localTransformation_.rotate(-rotation, directionY(), ACG::MULT_FROM_LEFT);
1509 
1510  } else {
1511  _state.push_modelview_matrix();
1512  _state.translate(center()[0], center()[1], center()[2]);
1513 
1514  rotate(rotation, directionY());
1515 
1516  _state.pop_modelview_matrix();
1517  }
1518 
1519  touched_ = true;
1520  }
1521 
1522  // z top clicked: rotate around z axis
1523  if (rot[2] && (activeRotations_ & Z_AXIS)) {
1524 
1525  mapToCylinder(_state, oldPoint2D_);
1526  mapToCylinder(_state, newPoint2D);
1527 
1528  Vec2i dist = oldPoint2D_ - newPoint2D;
1529 
1530  int rotation = 0;
1531 
1532  // Rasterize movement if shift is pressed
1533  if (_event->modifiers() == mods) {
1534  if (abs(dist[1]) < (int) (_state.viewport_width() / 16)) {
1535  rotation = 0;
1536  lockOldPoint = true;
1537  } else {
1538  // Rotate exactly 45 degrees
1539  if (dist[1] < 0)
1540  rotation = 45;
1541  else
1542  rotation = -45;
1543  ;
1544  }
1545  } else {
1546  rotation = -dist[1];
1547  }
1548 
1549  if (mode_ == LocalRotation) {
1550 
1551  // Update only local rotation
1552  localTransformation_.rotate(-rotation, directionZ(), ACG::MULT_FROM_LEFT); // (dist[0]+dist[1])/2
1553 
1554  } else {
1555  _state.push_modelview_matrix();
1556  _state.translate(center()[0], center()[1], center()[2]);
1557 
1558  rotate(rotation, directionZ());
1559 
1560  _state.pop_modelview_matrix();
1561  }
1562 
1563  touched_ = true;
1564  }
1565 
1566  break;
1567  }
1568 
1569  default: // avoid warning
1570  break;
1571  }
1572 
1573  setDirty();
1574 
1575  // save old Point
1576  if (!lockOldPoint)
1577  oldPoint2D_ = newPoint2D;
1578 }
1579 
1580 
1581 //----------------------------------------------------------------------------
1582 
1585  const Vec2i& _v2)
1586 {
1587  // Qt -> GL coordinate systems
1588  unsigned int x = _v2[0];
1589  unsigned int y = _state.context_height() - _v2[1];
1590 
1591 
1592  // get ray from eye through pixel, in sphere coords
1593  Vec3d origin, direction;
1594 
1595  _state.set_updateGL(false);
1596  _state.push_modelview_matrix();
1597 
1598  update_manipulator_system(_state);
1599  _state.scale(2*manipulator_radius_);
1600 
1601  _state.viewing_ray(x, y, origin, direction);
1602 
1603  _state.pop_modelview_matrix();
1604  _state.set_updateGL(true);
1605 
1606 
1607 
1608  // calc sphere-ray intersection
1609  // (sphere is centered at origin, has radius 1)
1610  double a = direction.sqrnorm(),
1611  b = 2.0 * (origin | direction),
1612  c = origin.sqrnorm() - 1.0,
1613  d = b*b - 4.0*a*c;
1614 
1615  return (d >= 0.0);
1616 }
1617 
1618 
1619 //------------------------------------------------------------------------------------
1620 
1621 
1623 
1625  const Vec2i& _v2)
1626 {
1627  // Qt -> GL coordinate systems
1628  unsigned int x = _v2[0];
1629  unsigned int y = _state.context_height() - _v2[1];
1630 
1631 
1632  // get ray from eye through pixel, in sphere coords
1633  Vec3d origin, direction;
1634 
1635  _state.set_updateGL(false);
1636  _state.push_modelview_matrix();
1637 
1638  update_manipulator_system(_state);
1639  _state.scale(manipulator_height_+4*manipulator_radius_);
1640 
1641  _state.viewing_ray(x, y, origin, direction);
1642 
1643  _state.pop_modelview_matrix();
1644  _state.set_updateGL(true);
1645 
1646 
1647  // calc sphere-ray intersection
1648  // (sphere is centered at origin, has radius 1)
1649  double a = direction.sqrnorm(),
1650  b = 2.0 * (origin | direction),
1651  c = origin.sqrnorm() - 1.0,
1652  d = b*b - 4.0*a*c;
1653 
1654  return (d >= 0.0);
1655 }
1656 
1657 
1658 //------------------------------------------------------------------------------------
1659 
1660 
1663 bool
1665  const Vec2i& _v1,
1666  StateUpdates _updateStates )
1667 {
1668  // Qt -> GL coordinate systems
1669  unsigned int x = _v1[0];
1670  unsigned int y = _state.context_height() - _v1[1];
1671 
1672 
1673  // get ray from eye through pixel (cylinder coords)
1674  Vec3d originX, directionX;
1675  Vec3d originY, directionY;
1676  Vec3d originZ, directionZ;
1677 
1678  _state.set_updateGL(false);
1679  _state.push_modelview_matrix();
1680 
1681  // Now that we have 3 different axes we have to test intersection with each of them
1682  // Z-Axis:
1683  update_manipulator_system(_state);
1684  _state.viewing_ray(x, y, originZ, directionZ);
1685 
1686  // Y-Axis:
1687  _state.rotate(-90, 1.0, 0.0, 0.0);
1688  _state.viewing_ray(x, y, originY, directionY);
1689 
1690  // X-Axis:
1691  _state.rotate(90, 0.0, 1.0, 0.0);
1692  _state.viewing_ray(x, y, originX, directionX);
1693 
1694  _state.pop_modelview_matrix();
1695  _state.set_updateGL(true);
1696 
1697 
1698  // get cylinder axis ray: it's in its own coord system!
1699  // Viewing ray function unprojects screen coordinates thorugh inverse viewport, projection and modelview
1700  // such that we end in local coordinate system of the manipulator.
1701  // local transformation of the manipulator is included in update_manipulator_system which applies the
1702  // local transformation to the current glstate used by viewing_ray
1703  const Vec3d origin2(0,0,0),
1704  cylinderAxis(0.0, 0.0, 1.0); // Always same but we change the coordinate system for the viewer
1705 
1706 
1707  // compute pseude-intersection (x axis)
1708  Vec3d normalX = (directionX % cylinderAxis).normalize();
1709  Vec3d vdX = ((origin2 - originX) % directionX);
1710  double axis_hitX = (normalX | vdX);
1711  double orthodistanceX = std::abs( ( origin2 - originX ) | normalX);
1712 
1713  // compute pseude-intersection (y axis)
1714  Vec3d normalY = (directionY % cylinderAxis).normalize();
1715  Vec3d vdY = ((origin2 - originY) % directionY);
1716  double axis_hitY = (normalY | vdY);
1717  double orthodistanceY = std::abs( ( origin2 - originY ) | normalY);
1718 
1719  // compute pseude-intersection (z axis)
1720  Vec3d normalZ = (directionZ % cylinderAxis).normalize();
1721  Vec3d vdZ = ((origin2 - originZ) % directionZ);
1722  double axis_hitZ = (normalZ | vdZ);
1723  double orthodistanceZ = std::abs( ( origin2 - originZ ) | normalZ);
1724 
1725  if ( _updateStates == None )
1726  return false;
1727 
1728  if ( ( orthodistanceX < manipulator_radius_ ) &&
1729  ( axis_hitX >= 0 ) &&
1730  ( axis_hitX <= manipulator_height_ ) )
1731  {
1732 
1733  // z axis has been hit
1734  if ( _updateStates == Click)
1735  element_[XAxis].clicked_ = true;
1736  else
1737  element_[XAxis].over_ = true;
1738 
1739  } else if ( ( orthodistanceY < manipulator_radius_ ) &&
1740  ( axis_hitY >= 0 ) &&
1741  ( axis_hitY <= manipulator_height_))
1742  {
1743 
1744  // y axis has been hit
1745  if ( _updateStates == Click)
1746  element_[YAxis].clicked_ = true;
1747  else
1748  element_[YAxis].over_ = true;
1749 
1750  } else if ( ( orthodistanceZ < manipulator_radius_ ) &&
1751  ( axis_hitZ >= 0 ) &&
1752  ( axis_hitZ <= manipulator_height_ ) )
1753  {
1754  // x axis has been hit
1755  if ( _updateStates == Click)
1756  element_[ZAxis].clicked_ = true;
1757  else
1758  element_[ZAxis].over_ = true;
1759 
1760  }
1761 
1762  if ( _updateStates == Click)
1763  return (element_[XAxis].clicked_ || element_[YAxis].clicked_ || element_[ZAxis].clicked_);
1764 
1765  return (element_[XAxis].over_ || element_[YAxis].over_ || element_[ZAxis].over_);
1766 }
1767 
1768 
1769 //----------------------------------------------------------------------------
1772 // This method treats the top as cylinder
1773 // TODO: Adapt intersection test to cone shape
1774 bool
1776  const Vec2i& _v1,
1777  StateUpdates _updateStates )
1778 {
1779  // Qt -> GL coordinate systems
1780  unsigned int x = _v1[0];
1781  unsigned int y = _state.context_height() - _v1[1];
1782 
1783 
1784  // get ray from eye through pixel (cylinder coords)
1785  Vec3d originX, directionX;
1786  Vec3d originY, directionY;
1787  Vec3d originZ, directionZ;
1788 
1789  _state.set_updateGL(false);
1790  _state.push_modelview_matrix();
1791 
1792  // Z-Axis:
1793  update_manipulator_system(_state);
1794  _state.translate( 0.0, 0.0, manipulator_height_);
1795  _state.viewing_ray(x, y, originZ, directionZ);
1796  _state.translate( 0.0, 0.0, -manipulator_height_);
1797 
1798  // Y-Axis:
1799  _state.rotate(-90, 1.0, 0.0, 0.0);
1800  _state.translate(0.0, 0.0 , manipulator_height_ );
1801  _state.viewing_ray(x, y, originY, directionY);
1802  _state.translate(0.0, 0.0, -manipulator_height_);
1803 
1804  // X-Axis:
1805  _state.rotate(90, 0.0, 1.0, 0.0);
1806  _state.translate(0.0, 0.0, manipulator_height_);
1807  _state.viewing_ray(x, y, originX, directionX);
1808  _state.translate(0.0, 0.0, -manipulator_height_);
1809 
1810  _state.pop_modelview_matrix();
1811  _state.set_updateGL(true);
1812 
1813 
1814  // get cylinder axis ray: it's in its own coord system!
1815  // Viewing ray function unprojects screen coordinates thorugh inverse viewport, projection and modelview
1816  // such that we end in local coordinate system of the manipulator.
1817  // local transformation of the manipulator is included in update_manipulator_system which applies the
1818  // local transformation to the current glstate used by viewing_ray
1819  const Vec3d origin2(0,0,0),
1820  cylinderAxis(0.0, 0.0, 1.0);
1821 
1822  // compute pseude-intersection (x axis)
1823  Vec3d normalX = (directionX % cylinderAxis).normalize();
1824  Vec3d vdX = ((origin2 - originX) % directionX );
1825  double axis_hitX = (normalX | vdX);
1826  double orthodistanceX = std::abs( ( origin2 - originX ) | normalX);
1827 
1828  // compute pseude-intersection (y axis)
1829  Vec3d normalY = (directionY % cylinderAxis).normalize();
1830  Vec3d vdY = ((origin2 - originY) % directionY);
1831  double axis_hitY = (normalY | vdY);
1832  double orthodistanceY = std::abs( ( origin2 - originY ) | normalY);
1833 
1834  // compute pseude-intersection (z axis)
1835  Vec3d normalZ = (directionZ % cylinderAxis).normalize();
1836  Vec3d vdZ = ((origin2 - originZ) % directionZ);
1837  double axis_hitZ = (normalZ | vdZ);
1838  double orthodistanceZ = std::abs( ( origin2 - originZ ) | normalZ);
1839 
1840  if ( _updateStates == None )
1841  return false;
1842 
1843  // TODO: Work with cones :
1844 
1845  if ( ( orthodistanceX < manipulator_radius_ * 2.0 ) &&
1846  ( axis_hitX >= 0.0 ) &&
1847  ( axis_hitX <= manipulator_height_ / 2.0 ) )
1848  {
1849 
1850  // z top has been hit
1851  if ( _updateStates == Click)
1852  element_[XTop].clicked_ = true;
1853  else
1854  element_[XTop].over_ = true;
1855 
1856  } else if ( ( orthodistanceY < manipulator_radius_ * 2.0 ) &&
1857  ( axis_hitY >= 0.0 ) &&
1858  ( axis_hitY <= manipulator_height_ / 2.0 ) )
1859  {
1860 
1861  // y top has been hit
1862  if ( _updateStates == Click)
1863  element_[YTop].clicked_ = true;
1864  else
1865  element_[YTop].over_ = true;
1866 
1867  } else if ( ( orthodistanceZ < manipulator_radius_ * 2.0 ) &&
1868  ( axis_hitZ >= 0.0 ) &&
1869  ( axis_hitZ <= manipulator_height_ / 2.0 ) )
1870  {
1871 
1872  // x top has been hit
1873  if ( _updateStates == Click)
1874  element_[ZTop].clicked_ = true;
1875  else
1876  element_[ZTop].over_ = true;
1877 
1878  }
1879 
1880  if ( _updateStates == Click)
1881  return (element_[XTop].clicked_ || element_[YTop].clicked_ || element_[ZTop].clicked_);
1882  return (element_[XTop].over_ || element_[YTop].over_ || element_[ZTop].over_);
1883 }
1884 
1885 //----------------------------------------------------------------------------
1886 
1890 bool
1892  const Vec2i& _v2,
1893  Vec3d& _v3,
1894  StateUpdates _updateStates)
1895 {
1896  // Qt -> GL coordinate systems
1897  unsigned int x = _v2[0];
1898  unsigned int y = _state.context_height() - _v2[1];
1899 
1900  // get ray from eye through pixel
1901  Vec3d originXY, directionXY,
1902  originYZ, directionYZ,
1903  originZX, directionZX;
1904 
1905  _state.set_updateGL(false);
1906  _state.push_modelview_matrix();
1907 
1908  update_manipulator_system(_state);
1909 
1910  _state.viewing_ray(x, y, originXY, directionXY);
1911  _state.rotate(90, 0.0, 1.0, 0.0);
1912  _state.viewing_ray(x, y, originYZ, directionYZ);
1913  _state.rotate(90, 1.0, 0.0, 0.0);
1914  _state.viewing_ray(x, y, originZX, directionZX);
1915 
1916  _state.pop_modelview_matrix();
1917  _state.set_updateGL(true);
1918 
1919  // origin + direction * t = (x, y, 0) <=> t = -origin_z / direction_z
1920  // => Point on xy-plane p = (origin_x + direction_x*t, origin_y + direction_y*t, 0)
1921  double t1 = -originXY[2]/directionXY[2];
1922  Vec3d hitPointXY = originXY + directionXY*t1;
1923 
1924  double t2 = -originYZ[2]/directionYZ[2];
1925  Vec3d hitPointYZ = originYZ + directionYZ*t2;
1926 
1927  double t3 = -originZX[2]/directionZX[2];
1928  Vec3d hitPointZX = originZX + directionZX*t3;
1929 
1930  // Depth test: Take nearest object
1931  bool t1_near = false, t2_near = false, t3_near = false;
1932  if( t1 <= t2 && t1 <= t3)
1933  t1_near = true;
1934  if( t2 <= t1 && t2 <= t3)
1935  t2_near = true;
1936  if( t3 <= t1 && t3 <= t2)
1937  t3_near = true;
1938 
1939  bool xy_hit = hitPointXY.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
1940  hitPointXY.length() < 2*manipulator_height_;
1941 
1942  bool yz_hit = hitPointYZ.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
1943  hitPointYZ.length() < 2*manipulator_height_;
1944 
1945  bool zx_hit = hitPointZX.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
1946  hitPointZX.length() < 2*manipulator_height_;
1947 
1948 
1949  bool more_than_one_hit = (xy_hit && yz_hit) || (xy_hit && zx_hit) || (yz_hit && zx_hit);
1950 // std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
1951 // hitPointXY << " < " << 2*manipulator_height_ << std::endl;
1952 //
1953 // std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
1954 // hitPointYZ << " < " << 2*manipulator_height_ << std::endl;
1955 //
1956 // std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
1957 // hitPointZX << " < " << 2*manipulator_height_ << std::endl;
1958 
1959  // Test if hit point on x-y plane matches length of
1960  // manipulator radius_state
1961  if(xy_hit && (!more_than_one_hit || t1_near))
1962  {
1963  // Outer ring on xy plane has been hit
1964  if ( _updateStates == Click)
1965  element_[ZRing].clicked_ = true;
1966  else if ( _updateStates == Over)
1967  element_[ZRing].over_ = true;
1968  _v3 = hitPointXY;
1969  return true;
1970  }
1971 
1972  else if(yz_hit && (!more_than_one_hit || t2_near))
1973  {
1974  // Outer ring on yz plane has been hit
1975  if ( _updateStates == Click)
1976  element_[XRing].clicked_ = true;
1977  else if ( _updateStates == Over)
1978  element_[XRing].over_ = true;
1979  _v3 = hitPointYZ;
1980  return true;
1981  }
1982 
1983  else if(zx_hit && (!more_than_one_hit || t3_near))
1984  {
1985  // Outer ring around zx plane has been hit
1986  if ( _updateStates == Click)
1987  element_[YRing].clicked_ = true;
1988  else if ( _updateStates == Over)
1989  element_[YRing].over_ = true;
1990  _v3 = hitPointZX;
1991  return true;
1992  }
1993 
1994  return false;
1995 }
1996 
1997 //----------------------------------------------------------------------------
1998 
1999 void
2001 pick(GLState& _state, PickTarget _target)
2002 {
2003  GLenum prev_depth = _state.depthFunc();
2004 
2005  if (_target == PICK_FACE ||
2006  _target == PICK_ANYTHING) {
2007 
2008  if (draw_manipulator_) {
2009 
2010  updateSize (_state);
2011 
2012  _state.pick_set_maximum(5);
2013 
2014  // Enable depth test but store original status
2015  glPushAttrib(GL_DEPTH_BUFFER_BIT);
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  glPopAttrib();
2104  _state.pop_modelview_matrix();
2105 
2106  //restore original depth comparison function
2107  ACG::GLState::depthFunc(prev_depth);
2108  }
2109  }
2110 }
2111 
2112 
2113 //----------------------------------------------------------------------------
2114 
2115 void
2116 TranslationManipulatorNode::set_direction(const Vec3d& _directionX, const Vec3d& _directionY)
2117 {
2118 
2119  localTransformation_.identity();
2120 
2121  const Vec3d cross = _directionX % _directionY;
2122 
2123  localTransformation_(0,0) = _directionX[0];
2124  localTransformation_(1,0) = _directionX[1];
2125  localTransformation_(2,0) = _directionX[2];
2126  localTransformation_(3,0) = 0.0;
2127 
2128  localTransformation_(0,1) = _directionY[0];
2129  localTransformation_(1,1) = _directionY[1];
2130  localTransformation_(2,1) = _directionY[2];
2131  localTransformation_(3,1) = 0.0;
2132 
2133  localTransformation_(0,2) = cross[0];
2134  localTransformation_(1,2) = cross[1];
2135  localTransformation_(2,2) = cross[2];
2136  localTransformation_(3,2) = 0.0;
2137 
2138 }
2139 
2140 //----------------------------------------------------------------------------
2141 
2142 
2143 Vec3d
2145 {
2146  return MathTools::sane_normalized( localTransformation_.transform_vector(dirX_) );
2147 }
2148 
2149 //----------------------------------------------------------------------------
2150 
2151 
2152 Vec3d
2154 {
2155  return MathTools::sane_normalized( localTransformation_.transform_vector(dirY_) );
2156 }
2157 
2158 //----------------------------------------------------------------------------
2159 
2160 
2161 Vec3d
2163 {
2164  return MathTools::sane_normalized(localTransformation_.transform_vector(dirZ_));
2165 }
2166 
2167 //----------------------------------------------------------------------------
2168 
2169 double TranslationManipulatorNode::get_screen_length (GLState& _state, Vec3d& _point) const
2170 {
2171  Vec3d proj = _state.project (_point);
2172  proj[0] += 1.0;
2173  Vec3d uproj = _state.unproject (proj);
2174  uproj -= _point;
2175  return uproj.length ();
2176 }
2177 
2178 //----------------------------------------------------------------------------
2179 
2180 void TranslationManipulatorNode::updateSize (GLState& _state)
2181 {
2182  if (auto_size_ != TranslationManipulatorNode::Never)
2183  {
2184  Vec3d point = localTransformation_.transform_point(Vec3d (0.0, 0.0, 0.0));
2185 
2186  int tmp, width, height;
2187 
2188  _state.get_viewport (tmp, tmp, width, height);
2189 
2190  auto_size_length_ = get_screen_length (_state, point) * (width + height) * 0.02;
2191 
2192  if (auto_size_ == TranslationManipulatorNode::Once)
2193  auto_size_ = TranslationManipulatorNode::Never;
2194  }
2195 
2196  manipulator_radius_ = set_manipulator_radius_ * auto_size_length_;
2197  manipulator_height_ = set_manipulator_height_ * auto_size_length_;
2198 }
2199 
2200 //----------------------------------------------------------------------------
2201 
2202 
2204 {
2205  if (!draw_manipulator_)
2206  return;
2207 
2208  float r = 2 * manipulator_height_;
2209 
2210  _bbMin.minimize(center()+Vec3d(-r,-r,-r));
2211  _bbMax.maximize(center()+Vec3d(r,r,r));
2212 }
2213 
2214 //----------------------------------------------------------------------------
2215 
2217 {
2218  if (mode_ != _mode)
2219  ignoreTime_ = true;
2220  mode_ = _mode;
2221  setDirty ();
2222 }
2223 
2224 //=============================================================================
2225 } // namespace SceneGraph
2226 } // namespace ACG
2227 //=============================================================================
int viewport_width() const
get viewport width
Definition: GLState.hh:825
const Vec3d & center() const
get center
bool pick_set_maximum(size_t _idx)
Set the maximal number of primitives/components of your object.
Definition: GLState.cc:1048
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
Definition: GLState.cc:938
bool mapToCylinderTop(GLState &_state, const Vec2i &_v2, StateUpdates _updateStates=None)
void set_updateGL(bool _b)
should GL matrices be updated after each matrix operation
Definition: GLState.hh:242
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:563
void translate(const Vec3d &_v)
Add a translation to the current Transformation.
Vec3d project(const Vec3d &_point) const
project point in world coordinates to window coordinates
Definition: GLState.cc:639
static void blendFunc(GLenum _sfactor, GLenum _dfactor)
replaces glBlendFunc, supports locking
Definition: MeshNode2T.cc:314
bool invert()
matrix inversion (returns true on success)
Definition: Matrix4x4T.cc:297
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:721
const GLenum & depthFunc() const
get glDepthFunc() that is supposed to be active
const Vec4f & diffuse_color() const
get diffuse color
Definition: GLState.hh:939
void pop_modelview_matrix()
pop modelview matrix
Definition: GLState.cc:1023
void push_modelview_matrix()
push modelview matrix
Definition: GLState.cc:1007
void set_modelview(const GLMatrixd &_m)
set modelview
Definition: GLState.hh:731
const GLMatrixd & rotation() const
return rotation matrix
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
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
static void enable(GLenum _cap)
replaces glEnable, but supports locking
bool hitSphere(GLState &_state, const Vec2i &_v2)
Determine whether the origin sphere has been hit.
const GLMatrixd & inverse_scale() const
return inverse scale matrix
void set_specular_color(const Vec4f &_col)
set specular color
Definition: GLState.cc:736
Vec3d directionX() const
Get current direction of x-Axis in world coordinates.
GLenum depthFunc
GL_LESS, GL_LEQUAL, GL_GREATER ..
ManipulatorMode
enum to define the manipulator mode
static void disable(GLenum _cap)
replaces glDisable, but supports locking
void rotate(Scalar angle, Scalar x, Scalar y, Scalar z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
Definition: GLMatrixT.cc:161
void setDirty(bool _dirty=true)
mark node for redrawn
Definition: MeshNode2T.cc:306
bool mapToSphere(GLState &_state, const Vec2i &_v2, Vec3d &_v3, StateUpdates _updateStates=None)
pick any of the prior targets (should be implemented for all nodes)
Definition: BaseNode.hh:110
GLMatrixd computeWorldMatrix()
computes world matrix, transforms from model to world space
void clearTextures()
disables texture support and removes all texture types
const Vec4f & specular_color() const
get specular color
Definition: GLState.hh:944
void update_rotation(GLState &_state)
update the internal rotation matrix ( internal rotation may be changed without modifiing children of ...
void getRenderObjects(IRenderer *_renderer, GLState &_state, const DrawModes::DrawMode &_drawMode, const Material *_mat)
create renderobjects for shaderpipeline renderer
void get_viewport(int &_left, int &_bottom, int &_width, int &_height) const
get viewport
Definition: GLState.hh:819
void boundingBox(Vec3d &_bbMin, Vec3d &_bbMax)
bounding box of node
TranslationManipulatorNode(BaseNode *_parent=0, const std::string &_name="<TranslationTranslationManipulatorNode>")
Default constructor.
void draw(GLState &_state, const DrawModes::DrawMode &_drawMode)
draw the cylinder (if enabled)
Vec3d directionZ() const
Get current direction of z-Axis in world coordinates.
void set_direction(const Vec3d &_directionX, const Vec3d &_directionY)
Set direction 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
GLMatrixd modelview
Modelview transform.
picks faces (should be implemented for all nodes)
Definition: BaseNode.hh:104
VectorT< T, 3 > transform_vector(const VectorT< T, 3 > &_v) const
transform vector (x',y',z',0) = A * (x,y,z,0)
Definition: Matrix4x4T.cc:225
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:613
void translate(double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
translate by (_x, _y, _z)
Definition: GLState.cc:532
void setMode(ManipulatorMode _mode)
set current operation mode
std::string name
Name for logging.
int viewport_height() const
get viewport height
Definition: GLState.hh:827
int priority
Priority to allow sorting of objects.
VectorT< float, 4 > Vec4f
Definition: VectorT.hh:144
const GLMatrixd & scale() const
return scale matrix
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:794
void viewing_ray(int _x, int _y, Vec3d &_origin, Vec3d &_direction) const
Definition: GLState.cc:927
GLenum blendDest
glBlendFunc: GL_SRC_ALPHA, GL_ZERO, GL_ONE, GL_ONE_MINUS_SRC_ALPHA ...
void scale(double _s)
scale by (_s, _s, _s)
Definition: GLState.hh:753
static void shadeModel(GLenum _mode)
replaces glShadeModel, supports locking
void update_manipulator_system(GLState &_state)
set the current state to follow manipulator transformation
PickTarget
What target to use for picking.
Definition: BaseNode.hh:99
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
virtual void mouseEvent(GLState &_state, QMouseEvent *_event)
get mouse events
bool mapToCylinder(GLState &_state, const Vec2i &_v2, StateUpdates _updateStates=None)
Interface class between scenegraph and renderer.
void pick_set_name(size_t _idx)
sets the current name/color (like glLoadName(_idx))
Definition: GLState.cc:1058
VectorT< double, 2 > Vec2d
Definition: VectorT.hh:110
bool touched_
stores if this manipulator was used in order to avoid emitting manipulatorMoved unnecessarily ...
int context_width() const
get gl context width
Definition: GLState.hh:830
int context_height() const
get gl context height
Definition: GLState.hh:833
Vec3d directionY() const
Get current direction of y-Axis in world coordinates.
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
VectorT< T, 3 > transform_point(const VectorT< T, 3 > &_v) const
transform point (x',y',z',1) = M * (x,y,z,1)
Definition: Matrix4x4T.cc:202
void initFromState(GLState *_glState)
Initializes a RenderObject instance.
Definition: RenderObject.cc:69
void identity()
setup an identity matrix
Definition: Matrix4x4T.cc:256
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:650
void pick(GLState &_state, PickTarget _target)
leave node
ShaderGenDesc shaderDesc
Drawmode and other shader params.
void setTraverseMode(unsigned int _mode)
Set traverse mode for node.
Definition: MeshNode2T.cc:483