TranslationManipulatorNode.cc

00001 /*===========================================================================*\
00002  *                                                                           *
00003  *                              OpenFlipper                                  *
00004  *      Copyright (C) 2001-2009 by Computer Graphics Group, RWTH Aachen      *
00005  *                           www.openflipper.org                             *
00006  *                                                                           *
00007  *---------------------------------------------------------------------------*
00008  *  This file is part of OpenFlipper.                                        *
00009  *                                                                           *
00010  *  OpenFlipper is free software: you can redistribute it and/or modify      *
00011  *  it under the terms of the GNU Lesser General Public License as           *
00012  *  published by the Free Software Foundation, either version 3 of           *
00013  *  the License, or (at your option) any later version with the              *
00014  *  following exceptions:                                                    *
00015  *                                                                           *
00016  *  If other files instantiate templates or use macros                       *
00017  *  or inline functions from this file, or you compile this file and         *
00018  *  link it with other files to produce an executable, this file does        *
00019  *  not by itself cause the resulting executable to be covered by the        *
00020  *  GNU Lesser General Public License. This exception does not however       *
00021  *  invalidate any other reasons why the executable file might be            *
00022  *  covered by the GNU Lesser General Public License.                        *
00023  *                                                                           *
00024  *  OpenFlipper is distributed in the hope that it will be useful,           *
00025  *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
00026  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
00027  *  GNU Lesser General Public License for more details.                      *
00028  *                                                                           *
00029  *  You should have received a copy of the GNU LesserGeneral Public          *
00030  *  License along with OpenFlipper. If not,                                  *
00031  *  see <http://www.gnu.org/licenses/>.                                      *
00032  *                                                                           *
00033 \*===========================================================================*/
00034 
00035 /*===========================================================================*\
00036  *                                                                           *
00037  *   $Revision: 7475 $                                                       *
00038  *   $Author: moebius $                                                      *
00039  *   $Date: 2009-10-20 11:23:30 +0200 (Di, 20. Okt 2009) $                   *
00040  *                                                                           *
00041 \*===========================================================================*/
00042 
00043 
00044 
00045 
00046 //=============================================================================
00047 //
00048 //  CLASS TranslationManipulatorNode - IMPLEMENTATION
00049 //
00050 //=============================================================================
00051 
00052 
00053 //== INCLUDES =================================================================
00054 
00055 
00056 #include "TranslationManipulatorNode.hh"
00057 #include "../Math/GLMatrixT.hh"
00058 #include "../GL/gl.hh"
00059 
00060 #include <QMouseEvent>
00061 #include <QEvent>
00062 #include <float.h>
00063 
00064 #include <Math_Tools/Math_Tools.hh>
00065 #include <OpenMesh/Core/Geometry/MathDefs.hh>
00066 
00067 //== NAMESPACES ===============================================================
00068 
00069 
00070 namespace ACG {
00071 namespace SceneGraph {
00072 
00073 
00074 //== IMPLEMENTATION ==========================================================
00075 
00076 // How many pixels should the cursor be away from the dragging center
00077 // for the translation operation to affect the geometry's position
00078 #define SNAP_PIXEL_TOLERANCE 30
00079 
00080 // Node colors (normal, over, clicked, occluded normal, occluded over, occluded clicked)
00081 
00082 const Vec4f colors[4][6] = {
00083   // origin
00084   {
00085     // normal
00086     Vec4f(0.2,0.2,0.2,1.0), Vec4f(0.5,0.5,0.5,1.0), Vec4f(0.8,0.8,0.8,1.0),
00087     // occluded
00088     Vec4f(0.2,0.2,0.2,0.2), Vec4f(0.5,0.5,0.5,0.4), Vec4f(0.8,0.8,0.8,0.6)
00089   },
00090   // X
00091   {
00092     // normal
00093     Vec4f(0.2,0.0,0.0,1.0), Vec4f(0.5,0.0,0.0,1.0), Vec4f(0.8,0.0,0.0,1.0),
00094     // occluded
00095     Vec4f(0.3,0.1,0.1,0.2), Vec4f(0.5,0.2,0.2,0.4), Vec4f(0.8,0.4,0.4,0.6)
00096   },
00097   // Y
00098   {
00099     // normal
00100     Vec4f(0.0,0.2,0.0,1.0), Vec4f(0.0,0.5,0.0,1.0), Vec4f(0.0,0.8,0.0,1.0),
00101     // occluded
00102     Vec4f(0.1,0.3,0.1,0.2), Vec4f(0.2,0.5,0.2,0.4), Vec4f(0.4,0.8,0.4,0.6)
00103   },
00104   // Z
00105   {
00106     // normal
00107     Vec4f(0.0,0.0,0.2,1.0), Vec4f(0.0,0.0,0.5,1.0), Vec4f(0.0,0.0,0.8,1.0),
00108     // occluded
00109     Vec4f(0.1,0.1,0.3,0.2), Vec4f(0.2,0.2,0.5,0.4), Vec4f(0.4,0.4,0.8,0.6)
00110   }
00111 };
00112 
00113 
00114 //----------------------------------------------------------------------------
00115 
00116 TranslationManipulatorNode::Element::Element () :
00117   active_target_color_ (0.0, 0.0, 0.0, 1.0),
00118   active_current_color_ (0.0, 0.0, 0.0, 1.0),
00119   inactive_target_color_ (0.0, 0.0, 0.0, 1.0),
00120   inactive_current_color_ (0.0, 0.0, 0.0, 1.0),
00121   clicked_ (false),
00122   over_ (false)
00123 {
00124 }
00125 
00126 //----------------------------------------------------------------------------
00127 
00128 TranslationManipulatorNode::
00129 TranslationManipulatorNode( BaseNode* _parent, const std::string& _name )
00130   : TransformNode(_parent, _name),
00131     draw_manipulator_(false),
00132     dirX_(1.0,0.0,0.0),
00133     dirY_(0.0,1.0,0.0),
00134     dirZ_(0.0,0.0,1.0),
00135     axis_(0),
00136     circle_(0),
00137     sphere_(0),
00138     manipulator_radius_(20.0),
00139     manipulator_height_(20),
00140     manipulator_slices_(10),
00141     manipulator_stacks_(10),
00142     any_axis_clicked_(false),
00143     any_top_clicked_(false),
00144     outer_ring_clicked_(false),
00145     any_axis_over_(false),
00146     any_top_over_(false),
00147     outer_ring_over_(false),
00148     resize_current_ (0.0),
00149     mode_ (TranslationRotation),
00150     ignoreTime_ (false),
00151     dragging_(false),
00152     auto_size_(TranslationManipulatorNode::Never),
00153     auto_size_length_(1.0)
00154 {
00155   localTransformation_.identity();
00156 
00157   // Create quadrics
00158   axis_ = gluNewQuadric();
00159   circle_ = gluNewQuadric();
00160   sphere_ = gluNewQuadric();
00161 
00162   setTraverseMode( BaseNode::ChildrenFirst );
00163 
00164   updateTargetColors ();
00165   for (unsigned int i = 0; i < TranslationManipulatorNode::NumElements; i++)
00166   {
00167     element_[i].active_current_color_ = element_[i].active_target_color_;
00168     element_[i].inactive_current_color_ = element_[i].inactive_target_color_;
00169   }
00170 
00171 }
00172 
00173 
00174 //----------------------------------------------------------------------------
00175 
00176 TranslationManipulatorNode::~TranslationManipulatorNode() {
00177 
00178         if (axis_) {
00179                 gluDeleteQuadric(axis_);
00180         }
00181 
00182         if (circle_) {
00183                 gluDeleteQuadric(circle_);
00184         }
00185 
00186         if (sphere_) {
00187                 gluDeleteQuadric(sphere_);
00188         }
00189 }
00190 
00191 
00192 //----------------------------------------------------------------------------
00193 
00194 
00195 void
00196 TranslationManipulatorNode::
00197 setIdentity()
00198 {
00199   TransformNode::setIdentity();
00200 }
00201 
00202 
00203 //----------------------------------------------------------------------------
00204 void
00205 TranslationManipulatorNode::
00206 update_manipulator_system(GLState& _state)
00207 {
00208   _state.translate(center()[0], center()[1], center()[2]); // Follow translation of parent node
00209   _state.mult_matrix(inverse_scale (), scale ()); // Adapt scaling
00210 
00211   update_rotation(_state);
00212   updateSize (_state);
00213 }
00214 
00215 //----------------------------------------------------------------------------
00216 // Local rotation of the manipulator
00217 void
00218 TranslationManipulatorNode::update_rotation(GLState& _state){
00219 
00220   // Get global transformation
00221   glMatrixMode(GL_MODELVIEW);
00222   GLMatrixd model = _state.modelview();
00223 
00224   // revert global transformation as we want to use our own
00225   model *= inverse_rotation();
00226 
00227   // apply local transformation to adjust our coordinate system
00228   model *= localTransformation_;
00229 
00230   // And update current matrix
00231   _state.set_modelview(model);
00232 
00233 }
00234 
00235 //----------------------------------------------------------------------------
00236 
00237 void TranslationManipulatorNode::updateTargetColors ()
00238 {
00239   // reset all color to default values
00240   element_[Origin].active_target_color_ = colors[0][0];
00241   element_[XAxis].active_target_color_ = colors[1][0];
00242   element_[YAxis].active_target_color_ = colors[2][0];
00243   element_[ZAxis].active_target_color_ = colors[3][0];
00244   element_[XTop].active_target_color_ = colors[1][0];
00245   element_[YTop].active_target_color_ = colors[2][0];
00246   element_[ZTop].active_target_color_ = colors[3][0];
00247   element_[XRing].active_target_color_ = colors[1][0];
00248   element_[YRing].active_target_color_ = colors[2][0];
00249   element_[ZRing].active_target_color_ = colors[3][0];
00250 
00251   element_[Origin].inactive_target_color_ = colors[0][3];
00252   element_[XAxis].inactive_target_color_ = colors[1][3];
00253   element_[YAxis].inactive_target_color_ = colors[2][3];
00254   element_[ZAxis].inactive_target_color_ = colors[3][3];
00255   element_[XTop].inactive_target_color_ = colors[1][3];
00256   element_[YTop].inactive_target_color_ = colors[2][3];
00257   element_[ZTop].inactive_target_color_ = colors[3][3];
00258   element_[XRing].inactive_target_color_ = colors[1][3];
00259   element_[YRing].inactive_target_color_ = colors[2][3];
00260   element_[ZRing].inactive_target_color_ = colors[3][3];
00261 
00262 
00263   // blending is enabled for ring so we have to set alpha correctly
00264   element_[XRing].active_target_color_[3] = 1.0;
00265   element_[YRing].active_target_color_[3] = 1.0;
00266   element_[ZRing].active_target_color_[3] = 1.0;
00267 
00268   // hide rings in resize mode
00269   if (mode_ == Resize || mode_ == Place)
00270     for (unsigned int i = 0; i < 3; i++)
00271     {
00272       element_[XRing + i].active_target_color_[3] = 0.0;
00273       element_[XRing + i].inactive_target_color_[3] = 0.0;
00274     }
00275 
00276   // set colors according to current (clicked/over/none) state
00277   if(element_[Origin].clicked_){
00278     element_[Origin].active_target_color_ = colors[0][2];
00279     element_[Origin].inactive_target_color_ = colors[0][5];
00280     for (unsigned int i = 1; i < NumElements - 3; i++)
00281     {
00282       element_[i].active_target_color_ = (colors[0][2] * 0.5) + (colors[((i-1)%3) + 1][2] * 0.5);
00283       element_[i].inactive_target_color_ = (colors[0][5] * 0.5) + (colors[((i-1)%3) + 1][5] * 0.5);
00284     }
00285     return;
00286   } else if(element_[Origin].over_){
00287     element_[Origin].active_target_color_ = colors[0][1];
00288     element_[Origin].inactive_target_color_ = colors[0][4];
00289     for (unsigned int i = 1; i < NumElements - 3; i++)
00290     {
00291       element_[i].active_target_color_ = (colors[0][1] * 0.5) + (colors[((i-1)%3) + 1][1] * 0.5);
00292       element_[i].inactive_target_color_ = (colors[0][4] * 0.5) + (colors[((i-1)%3) + 1][4] * 0.5);
00293     }
00294     return;
00295   }
00296 
00297   for (unsigned int i = 0; i < 3; i++)
00298     if (element_[i + XTop].clicked_)
00299     {
00300       element_[i + XTop].active_target_color_ = colors[i+1][2];
00301       element_[i + XTop].inactive_target_color_ = colors[i+1][5];
00302       if (mode_ != TranslationRotation)
00303       {
00304         element_[i + XAxis].active_target_color_ = colors[i+1][2];
00305         element_[i + XAxis].inactive_target_color_ = colors[i+1][5];
00306       }
00307       if (mode_ != Resize) {
00308         element_[i + XRing].active_target_color_ = colors[i+1][2];
00309         element_[i + XRing].inactive_target_color_ = colors[i+1][5];
00310       }
00311       return;
00312     } else if (element_[i + XTop].over_)
00313     {
00314       element_[i + XTop].active_target_color_ = colors[i+1][1];
00315       element_[i + XTop].inactive_target_color_ = colors[i+1][4];
00316       if (mode_ != TranslationRotation)
00317       {
00318         element_[i + XAxis].active_target_color_ = colors[i+1][1];
00319         element_[i + XAxis].inactive_target_color_ = colors[i+1][4];
00320       }
00321       if (mode_ != Resize) {
00322         element_[i + XRing].active_target_color_ = colors[i+1][1];
00323         element_[i + XRing].inactive_target_color_ = colors[i+1][4];
00324       }
00325       return;
00326     }
00327 
00328   for (unsigned int i = 0; i < 3; i++)
00329     if (element_[i + XAxis].clicked_)
00330     {
00331       element_[i + XTop].active_target_color_ = colors[i+1][2];
00332       element_[i + XTop].inactive_target_color_ = colors[i+1][5];
00333       element_[i + XAxis].active_target_color_ = colors[i+1][2];
00334       element_[i + XAxis].inactive_target_color_ = colors[i+1][5];
00335       if (mode_ == LocalRotation) {
00336         element_[i + XRing].active_target_color_ = colors[i+1][2];
00337         element_[i + XRing].inactive_target_color_ = colors[i+1][5];
00338       }
00339       return;
00340     } else if (element_[i + XAxis].over_)
00341     {
00342       element_[i + XTop].active_target_color_ = colors[i+1][1];
00343       element_[i + XTop].inactive_target_color_ = colors[i+1][4];
00344       element_[i + XAxis].active_target_color_ = colors[i+1][1];
00345       element_[i + XAxis].inactive_target_color_ = colors[i+1][4];
00346       if (mode_ == LocalRotation) {
00347         element_[i + XRing].active_target_color_ = colors[i+1][1];
00348         element_[i + XRing].inactive_target_color_ = colors[i+1][4];
00349       }
00350       return;
00351     }
00352 
00353   if (mode_ != Resize)
00354   for (unsigned int i = 0; i < 3; i++)
00355     if (element_[i + XRing].clicked_)
00356     {
00357       element_[i + XRing].active_target_color_ = colors[i+1][2];
00358       element_[i + XRing].inactive_target_color_ = colors[i+1][5];
00359       return;
00360     } else if (element_[i + XRing].over_)
00361     {
00362       element_[i + XRing].active_target_color_ = colors[i+1][1];
00363       element_[i + XRing].inactive_target_color_ = colors[i+1][4];
00364       return;
00365     }
00366 
00367 }
00368 
00369 //----------------------------------------------------------------------------
00370 
00371 bool TranslationManipulatorNode::updateCurrentColors (GLState& _state)
00372 {
00373     bool rv = false;
00374 
00375     float value = (float)_state.msSinceLastRedraw () / 1000.0;
00376 
00377     if (ignoreTime_)
00378     {
00379       value = 0;
00380       ignoreTime_ = false;
00381     }
00382 
00383     for (unsigned int i = 0; i < NumElements; i++)
00384     {
00385         Vec4f diff = element_[i].active_target_color_ -
00386                      element_[i].active_current_color_;
00387         for (unsigned int j = 0; j < 4; j++)
00388             if (diff[j] > value)
00389                 diff[j] = value;
00390             else if (diff[j] < -value)
00391                 diff[j] = -value;
00392         element_[i].active_current_color_ += diff;
00393         diff = element_[i].inactive_target_color_ -
00394                element_[i].inactive_current_color_;
00395         for (unsigned int j = 0; j < 4; j++)
00396             if (diff[j] > value)
00397                 diff[j] = value;
00398             else if (diff[j] < -value)
00399                 diff[j] = -value;
00400         element_[i].inactive_current_color_ += diff;
00401 
00402         rv |= element_[i].active_target_color_ != element_[i].active_current_color_ ||
00403               element_[i].inactive_target_color_ != element_[i].inactive_current_color_;
00404     }
00405 
00406     float diff = ((mode_ == Resize) ? 1.0 : 0.0) - resize_current_;
00407     if (diff > value)
00408       diff = value;
00409     else if (diff < -value)
00410       diff = -value;
00411     resize_current_ += diff;
00412     rv |= resize_current_ != ((mode_ == Resize) ? 1.0 : 0.0);
00413 
00414     return rv;
00415 }
00416 
00417 //----------------------------------------------------------------------------
00418 
00419 void TranslationManipulatorNode::drawManipulator (GLState& _state, bool _active)
00420 {
00421   glPushAttrib(GL_ENABLE_BIT );
00422   glDisable( GL_CULL_FACE );
00423 
00424   // Save modelview matrix
00425   _state.push_modelview_matrix();
00426 
00427   //================================================================================================
00428   // Sphere
00429   //================================================================================================
00430 
00431 //     glDisable(GL_ALPHA_TEST);
00432 //     glEnable(GL_BLEND);
00433 //     glEnable(GL_CULL_FACE);
00434 //     glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ) ;
00435 //     glEnable(GL_COLOR_MATERIAL);
00436 //
00437 //     glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_DST_ALPHA);
00438 //
00439 //     glColor4f( 1.0,0.0,0.0,0.3);
00440 //     gluSphere( axis_, manipulator_height_ * 1.5 ,  manipulator_slices_ * 2, manipulator_stacks_ * 2);
00441 //     glDisable(GL_COLOR_MATERIAL);
00442 //
00443 //
00444 //     glEnable(GL_ALPHA_TEST);
00445 //     glDisable(GL_BLEND);
00446 
00447   //================================================================================================
00448   // Z-Axis
00449   //================================================================================================
00450   // gluCylinder draws into z direction so z-Axis first
00451 
00452   if (_active)
00453   {
00454     _state.set_diffuse_color(element_[ZAxis].active_current_color_);
00455     _state.set_specular_color(element_[ZAxis].active_current_color_);
00456   } else {
00457     _state.set_diffuse_color(element_[ZAxis].inactive_current_color_);
00458     _state.set_specular_color(element_[ZAxis].inactive_current_color_);
00459   }
00460 
00461   // Draw Bottom of z-axis
00462   gluCylinder(axis_,
00463               (1.0 - resize_current_) * manipulator_radius_,
00464               (1.0 + resize_current_) * manipulator_radius_,
00465               manipulator_height_/2,
00466               manipulator_slices_,
00467               manipulator_stacks_);
00468 
00469   // Draw center of z-axis
00470   _state.translate(0.0, 0.0, manipulator_height_/2);
00471 
00472   gluCylinder(axis_,
00473               manipulator_radius_,
00474               manipulator_radius_,
00475               manipulator_height_/2,
00476               manipulator_slices_,
00477               manipulator_stacks_);
00478 
00479 
00480   // Draw Top of z-axis
00481   if (_active)
00482   {
00483     _state.set_diffuse_color(element_[ZTop].active_current_color_);
00484     _state.set_specular_color(element_[ZTop].active_current_color_);
00485   } else {
00486     _state.set_diffuse_color(element_[ZTop].inactive_current_color_);
00487     _state.set_specular_color(element_[ZTop].inactive_current_color_);
00488   }
00489 
00490   _state.translate(0.0, 0.0, manipulator_height_/2);
00491   gluCylinder(axis_,
00492               manipulator_radius_*2,
00493               0,
00494               manipulator_height_/2,
00495               manipulator_slices_,
00496               manipulator_stacks_);
00497   _state.translate(0.0, 0.0, -manipulator_height_);
00498 
00499   //================================================================================================
00500   // Y-Axis
00501   //================================================================================================
00502   _state.rotate(-90, 1.0, 0.0, 0.0);
00503   if (_active)
00504   {
00505     _state.set_diffuse_color(element_[YAxis].active_current_color_);
00506     _state.set_specular_color(element_[YAxis].active_current_color_);
00507   } else {
00508     _state.set_diffuse_color(element_[YAxis].inactive_current_color_);
00509     _state.set_specular_color(element_[YAxis].inactive_current_color_);
00510   }
00511 
00512   // Draw Bottom of z-axis
00513   gluCylinder(axis_,
00514               (1.0 - resize_current_) * manipulator_radius_,
00515               (1.0 + resize_current_) * manipulator_radius_,
00516               manipulator_height_/2,
00517               manipulator_slices_,
00518               manipulator_stacks_);
00519 
00520   // Draw center of z-axis
00521   _state.translate(0.0, 0.0, manipulator_height_/2);
00522 
00523   gluCylinder(axis_,
00524               manipulator_radius_,
00525               manipulator_radius_,
00526               manipulator_height_/2,
00527               manipulator_slices_,
00528               manipulator_stacks_);
00529 
00530 
00531   // Draw Top of z-axis
00532   if (_active)
00533   {
00534     _state.set_diffuse_color(element_[YTop].active_current_color_);
00535     _state.set_specular_color(element_[YTop].active_current_color_);
00536   } else {
00537     _state.set_diffuse_color(element_[YTop].inactive_current_color_);
00538     _state.set_specular_color(element_[YTop].inactive_current_color_);
00539   }
00540 
00541   _state.translate(0.0, 0.0, manipulator_height_/2);
00542   gluCylinder(axis_,
00543               manipulator_radius_*2,
00544               0,
00545               manipulator_height_/2,
00546               manipulator_slices_,
00547               manipulator_stacks_);
00548   _state.translate(0.0, 0.0, -manipulator_height_);
00549 
00550 
00551   //================================================================================================
00552   // X-Axis
00553   //================================================================================================
00554   _state.rotate(90, 0.0, 1.0, 0.0);
00555   if (_active)
00556   {
00557     _state.set_diffuse_color(element_[XAxis].active_current_color_);
00558     _state.set_specular_color(element_[XAxis].active_current_color_);
00559   } else {
00560     _state.set_diffuse_color(element_[XAxis].inactive_current_color_);
00561     _state.set_specular_color(element_[XAxis].inactive_current_color_);
00562   }
00563 
00564   // Draw Bottom of z-axis
00565   gluCylinder(axis_,
00566               (1.0 - resize_current_) * manipulator_radius_,
00567               (1.0 + resize_current_) * manipulator_radius_,
00568               manipulator_height_/2,
00569               manipulator_slices_,
00570               manipulator_stacks_);
00571 
00572   // Draw center of z-axis
00573   _state.translate(0.0, 0.0, manipulator_height_/2);
00574 
00575   gluCylinder(axis_,
00576               manipulator_radius_,
00577               manipulator_radius_,
00578               manipulator_height_/2,
00579               manipulator_slices_,
00580               manipulator_stacks_);
00581 
00582 
00583   // Draw Top of z-axis
00584   if (_active)
00585   {
00586     _state.set_diffuse_color(element_[XTop].active_current_color_);
00587     _state.set_specular_color(element_[XTop].active_current_color_);
00588   } else {
00589     _state.set_diffuse_color(element_[XTop].inactive_current_color_);
00590     _state.set_specular_color(element_[XTop].inactive_current_color_);
00591   }
00592 
00593   _state.translate(0.0, 0.0, manipulator_height_/2);
00594   gluCylinder(axis_,
00595               manipulator_radius_*2,
00596               0,
00597               manipulator_height_/2,
00598               manipulator_slices_,
00599               manipulator_stacks_);
00600   _state.translate(0.0, 0.0, -manipulator_height_);
00601 
00602   //=================================================================================================
00603   // Sphere
00604   //=================================================================================================
00605   if (_active)
00606   {
00607     _state.set_diffuse_color(element_[Origin].active_current_color_);
00608     _state.set_specular_color(element_[Origin].active_current_color_);
00609   } else {
00610     _state.set_diffuse_color(element_[Origin].inactive_current_color_);
00611     _state.set_specular_color(element_[Origin].inactive_current_color_);
00612   }
00613 
00614   gluSphere( sphere_, manipulator_radius_*2, manipulator_slices_, manipulator_stacks_ );
00615 
00616   //=================================================================================================
00617   // Outer-Rings
00618   //=================================================================================================
00619 
00620   glEnable (GL_BLEND);
00621   glPushAttrib(GL_LIGHTING_BIT);
00622   glDisable(GL_LIGHTING);
00623 
00624   if (_active)
00625   {
00626     glColor4f(element_[XRing].active_current_color_[0],
00627               element_[XRing].active_current_color_[1],
00628               element_[XRing].active_current_color_[2],
00629               element_[XRing].active_current_color_[3]);
00630   } else {
00631     glColor4f(element_[XRing].inactive_current_color_[0],
00632               element_[XRing].inactive_current_color_[1],
00633               element_[XRing].inactive_current_color_[2],
00634               element_[XRing].inactive_current_color_[3]);
00635   }
00636 
00637   drawCircle(2*manipulator_height_, 2*manipulator_height_ - manipulator_height_/4.0);
00638 
00639   if (_active)
00640   {
00641     glColor4f(element_[YRing].active_current_color_[0],
00642               element_[YRing].active_current_color_[1],
00643               element_[YRing].active_current_color_[2],
00644               element_[YRing].active_current_color_[3]);
00645   } else {
00646     glColor4f(element_[YRing].inactive_current_color_[0],
00647               element_[YRing].inactive_current_color_[1],
00648               element_[YRing].inactive_current_color_[2],
00649               element_[YRing].inactive_current_color_[3]);
00650   }
00651 
00652   _state.rotate(90, 0.0, 1.0, 0.0);
00653   drawCircle(2*manipulator_height_, 2*manipulator_height_ - manipulator_height_/4.0);
00654 
00655   if (_active)
00656   {
00657     glColor4f(element_[ZRing].active_current_color_[0],
00658               element_[ZRing].active_current_color_[1],
00659               element_[ZRing].active_current_color_[2],
00660               element_[ZRing].active_current_color_[3]);
00661   } else {
00662     glColor4f(element_[ZRing].inactive_current_color_[0],
00663               element_[ZRing].inactive_current_color_[1],
00664               element_[ZRing].inactive_current_color_[2],
00665               element_[ZRing].inactive_current_color_[3]);
00666   }
00667 
00668   _state.rotate(90, 1.0, 0.0, 0.0);
00669   drawCircle(2*manipulator_height_, 2*manipulator_height_ - manipulator_height_/4.0);
00670 
00671   glPopAttrib(); // ENABLE_BIT
00672   glPopAttrib(); // LIGHTING_BIT
00673 
00674 
00675   _state.pop_modelview_matrix();
00676 }
00677 
00678 //----------------------------------------------------------------------------
00679 
00680 
00681 void
00682 TranslationManipulatorNode::draw(GLState& _state, unsigned int /* _drawMode */ )
00683 {
00684    if (draw_manipulator_) {
00685 
00686     // Store lighting bits and enable lighting
00687     glPushAttrib(GL_LIGHTING_BIT);
00688     glEnable(GL_LIGHTING);
00689     glShadeModel(GL_SMOOTH);
00690 
00691     // Store original depth status
00692     glPushAttrib(GL_DEPTH_BUFFER_BIT);
00693 
00694 
00695     // Alpha Test things
00696     glPushAttrib(GL_COLOR_BUFFER_BIT);
00697 
00698     glPushAttrib(GL_ENABLE_BIT);
00699 
00700     // backup colors
00701     Vec4f backup_diffuse  = _state.diffuse_color();
00702     Vec4f backup_specular = _state.specular_color();
00703 
00704 
00705     // Correctly align nodes local coordinate system
00706     update_manipulator_system(_state);
00707 
00708     updateTargetColors ();
00709     if (updateCurrentColors (_state))
00710       setDirty ();
00711 
00712     glEnable(GL_DEPTH_TEST);
00713     glDepthFunc(GL_GREATER);
00714     glDepthMask(GL_FALSE);
00715     glEnable (GL_BLEND);
00716     glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00717     drawManipulator(_state, false);
00718     glDisable (GL_BLEND);
00719 
00720     glDepthFunc(GL_LEQUAL);
00721     glDepthMask(GL_TRUE);
00722     drawManipulator(_state, true);
00723 
00724     // Restore old attributes and modelview
00725     glPopAttrib();
00726     glPopAttrib();
00727     glPopAttrib();
00728     glPopAttrib();
00729 
00730     // restore active colors
00731     _state.set_diffuse_color(backup_diffuse);
00732     _state.set_specular_color(backup_specular);
00733   }
00734 }
00735 
00736 
00737 //----------------------------------------------------------------------------
00738 
00740 void
00741 TranslationManipulatorNode::drawCircle(const float outerRadius, const float innerRadius)
00742 {
00743   gluDisk(circle_, innerRadius, outerRadius, 30, 30);
00744 }
00745 
00746 //----------------------------------------------------------------------------
00747 
00748 // void
00749 // TranslationManipulatorNode::leave(GLState& _state, unsigned int /* _drawMode */ )
00750 // {
00751 
00752 // }
00753 
00754 //----------------------------------------------------------------------------
00755 
00756 void
00757 TranslationManipulatorNode::mouseEvent(GLState& _state, QMouseEvent* _event)
00758 {
00759   if(!draw_manipulator_) return; // Avoid transformation of object while transformator is invisible
00760 
00761   Vec3d         oldPoint3D;
00762   Vec2i         newPoint2D(_event->pos().x(), _event->pos().y());
00763   Vec3d         newPoint3D;
00764   double        old_axis_hit, new_axis_hit, new_axis_over;
00765   bool          rot[3], trans[3];
00766   unsigned int  i;
00767 
00768   updateSize (_state);
00769 
00770   switch (_event->type()) {
00771 
00772     // If mouse is pressed check if any part of the manipulator is hit and store that state
00773     case QEvent::MouseButtonPress:
00774     {
00775       for (i = 0; i < NumElements; i++)
00776         element_[i].clicked_ = false;
00777 
00778       // Start dragging process
00779       if(!dragging_) {
00780           draggingOrigin3D_ = center();
00781           dragging_ = true;
00782       }
00783 
00784       // hit origin ?
00785       if (mode_ != LocalRotation)
00786         element_[Origin].clicked_ = hitSphere(_state, newPoint2D);
00787       else
00788         element_[Origin].clicked_ = false;
00789 
00790       // hit any top ?
00791       any_top_clicked_ = mapToCylinderTop(_state, newPoint2D, new_axis_hit, Click);
00792 
00793       // hit any axis ?
00794       any_axis_clicked_ = mapToCylinder(_state, newPoint2D, new_axis_hit, Click);
00795 
00796       // hit one of the outer rings ?
00797       if (mode_ != Resize)
00798         outer_ring_clicked_ = mapToSphere(_state, newPoint2D, newPoint3D, Click);
00799       else
00800         outer_ring_clicked_ = false;
00801 
00802       // origin has been hit, ignore all other parts
00803       if (element_[Origin].clicked_) {
00804         for (i = 1; i < NumElements; i++)
00805           element_[i].clicked_ = false;
00806         any_axis_clicked_   = false;
00807         any_top_clicked_    = false;
00808         outer_ring_clicked_ = false;
00809       } else if ( any_top_clicked_ ) { // tops override the axes
00810         for (i = XAxis; i < NumElements; i++)
00811           element_[i].clicked_ = false;
00812         any_axis_clicked_ = false;
00813         outer_ring_clicked_ = false;
00814       } else if ( any_axis_clicked_ ) { // axes have been hit, disable rest ... should not be required
00815         for (i = XRing; i < NumElements; i++)
00816           element_[i].clicked_ = false;
00817         outer_ring_clicked_ = false;
00818       } else if ( outer_ring_clicked_ ) { // Nothing except the outer ring has been hit
00819         for (i = 0; i < XRing; i++)
00820           element_[i].clicked_ = false;
00821         any_axis_clicked_   = false;
00822         any_top_clicked_    = false;
00823       }
00824 
00825       // Reset local transformation:
00826       if( _event->modifiers() & Qt::ControlModifier && _event->modifiers() & Qt::AltModifier) {
00827         localTransformation_.identity();
00828       }
00829 
00830       oldPoint2D_ = newPoint2D;
00831       currentScale_ = Vec3d (1.0, 1.0, 1.0);
00832       ignoreTime_ = true;
00833       break;
00834     }
00835 
00836 
00837     // Reset all states as we stopped manipulating
00838     case QEvent::MouseButtonRelease:
00839     {
00840 
00841       for (i = 0; i < NumElements; i++) {
00842         element_[i].clicked_ = false;
00843       }
00844       any_axis_clicked_   = false;
00845       any_top_clicked_    = false;
00846       outer_ring_clicked_ = false;
00847       ignoreTime_ = true;
00848       dragging_ = false;
00849       break;
00850     }
00851 
00852 
00853     case QEvent::MouseButtonDblClick:
00854     {
00855       draw_manipulator_ = !draw_manipulator_;
00856       break;
00857     }
00858 
00859 
00860     // All real manipulation is done here
00861     case QEvent::MouseMove:
00862     {
00863       if(!draw_manipulator_) return; // Avoid manipulation if manipulator is invisible
00864 
00865       for (i = 0; i < NumElements; i++)
00866         element_[i].over_ = false;
00867       any_axis_over_   = false;
00868       any_top_over_    = false;
00869       outer_ring_over_ = false;
00870 
00871       if (!(element_[Origin].clicked_ || any_top_clicked_ || any_axis_clicked_ ||
00872             outer_ring_clicked_))
00873       {
00874         // over origin ?
00875         if (mode_ != LocalRotation)
00876           element_[Origin].over_ = hitSphere(_state, newPoint2D);
00877         else
00878           element_[Origin].over_ = false;
00879 
00880         // over any top ?
00881         if(mode_ != Place) {
00882                 any_top_over_ = mapToCylinderTop(_state, newPoint2D, new_axis_over, Over);
00883         }
00884 
00885         // over any axis ?
00886         if(mode_ != Place) {
00887                 any_axis_over_ = mapToCylinder(_state, newPoint2D, new_axis_over, Over);
00888         }
00889 
00890         // over one of the outer rings ?
00891         if (mode_ != Resize) {
00892           outer_ring_over_ = mapToSphere(_state, newPoint2D, newPoint3D, Over);
00893         }
00894         else {
00895           outer_ring_over_ = false;
00896         }
00897 
00898         // origin has been hit, ignore all other parts
00899         if (element_[Origin].over_) {
00900           for (i = 1; i < NumElements; i++)
00901             element_[i].over_ = false;
00902           any_axis_over_   = false;
00903           any_top_over_    = false;
00904           outer_ring_over_ = false;
00905         } else if ( any_top_over_ ) { // tops override the axes
00906           for (i = XAxis; i < NumElements; i++)
00907             element_[i].over_ = false;
00908           any_axis_over_ = false;
00909           outer_ring_over_ = false;
00910         } else if ( any_axis_over_ ) { // axes have been hit, disable rest ... should not be required
00911           for (i = XRing; i < NumElements; i++)
00912             element_[i].over_ = false;
00913           outer_ring_over_ = false;
00914         } else if ( outer_ring_over_ ) { // Nothing except the outer ring has been hit
00915           for (i = 0; i < XRing; i++)
00916             element_[i].over_ = false;
00917           any_axis_over_   = false;
00918           any_top_over_    = false;
00919         }
00920       }
00921 
00922       // set action for the different modes
00923       switch (mode_)
00924       {
00925         case TranslationRotation:
00926           for (i = 0; i < 3; i++)
00927           {
00928             rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_;
00929             trans[i] = element_[XAxis + i].clicked_;
00930           }
00931           break;
00932         case LocalRotation:
00933           for (i = 0; i < 3; i++)
00934           {
00935             rot[i] = element_[XTop + i].clicked_ || element_[XRing + i].clicked_ || element_[XAxis + i].clicked_;
00936             trans[i] = false;
00937           }
00938           break;
00939         case Place:
00940           break;
00941         case Resize:
00942           for (i = 0; i < 3; i++)
00943           {
00944             rot[i] = false;
00945             trans[i] = element_[XTop + i].clicked_ || element_[XAxis + i].clicked_;
00946           }
00947           break;
00948       }
00949 
00950       // If origin was clicked on
00951       if(element_[Origin].clicked_) {
00952 
00953         // translate along screen plane ( unproject to get world coords for translation and apply them )
00954 
00955                 Vec3d d = _state.project(center());
00956                 Vec3d d_origin = _state.project(draggingOrigin3D_);
00957 
00958                 // Snap back to origin position if mouse cursor
00959                 // is near enough
00960                 if (abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE &&
00961                                 abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
00962                        && _event->modifiers() & Qt::AltModifier) {
00963                         newPoint2D = oldPoint2D_;
00964                         Vec3d backtrans = draggingOrigin3D_ - center();
00965                         if (mode_ != Resize) {
00966                                 translate(backtrans);
00967                         }
00968                 }
00969 
00970                 // translate along screen plane ( unproject to get world coords for translation and apply them )
00971                 Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
00972                 Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
00973                 Vec3d ntrans = newvec - oldvec;
00974 
00975                 if (mode_ != Resize)
00976                         translate(ntrans);
00977                 else
00978                 {
00979                   // revert last scale
00980                   scale(Vec3d (1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
00981                   double positive = -1;
00982                   if (newPoint2D[0] - oldPoint2D_[0] + oldPoint2D_[1] - newPoint2D[1] > 0)
00983                   positive = 1;
00984 
00985                   Vec2d div = Vec2d (newPoint2D[0], newPoint2D[1]) - Vec2d (oldPoint2D_[0], oldPoint2D_[1]);
00986 
00987                   double scaleValue = div.norm () * 3.0 / qMin (_state.context_height(), _state.context_width());
00988                   scaleValue *= positive;
00989                   currentScale_ += Vec3d(scaleValue, scaleValue, scaleValue);
00990 
00991                   scale(currentScale_);
00992                 }
00993         }
00994 
00995 
00996       // x axis clicked apply translation along axis
00997       if (trans[0]) {
00998 
00999         mapToCylinder(_state, oldPoint2D_, old_axis_hit);
01000         mapToCylinder(_state, newPoint2D,  new_axis_hit);
01001 
01002         // translate
01003         // Get screen coordinates of current mouse position and unproject them
01004         // into world coordinates. Project onto selected axis and apply resulting
01005         // vector as translation
01006 
01007         Vec3d d = _state.project(center());
01008                 Vec3d d_origin = _state.project(draggingOrigin3D_);
01009 
01010                 // Snap back to origin position if mouse cursor
01011                 // is near enough
01012                 if (abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE &&
01013                                 abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
01014                        && _event->modifiers() & Qt::AltModifier) {
01015                         newPoint2D = oldPoint2D_;
01016                         Vec3d backtrans = draggingOrigin3D_ - center();
01017                         if (mode_ != Resize) {
01018                                 translate(backtrans);
01019                         }
01020                 }
01021         Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
01022         Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
01023         Vec3d ntrans = newvec - oldvec;
01024 
01025         // project to current direction
01026         ntrans       = ( ntrans | directionX() ) * directionX();
01027 
01028         if (mode_ == Resize){
01029           //scaling
01030           double positive = -1;
01031           if ( (directionX() | ntrans) > 0 ) positive = 1;
01032 
01033           if (currentScale_[0] < 0)
01034             positive *= -1;
01035 
01036           Vec3d proj = _state.project(ntrans + oldvec);
01037 
01038           Vec2d div = Vec2d (proj[0], proj[1]) - Vec2d (oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
01039 
01040           double scaleValue = div.norm () * 3.0 / qMin (_state.context_height(), _state.context_width());
01041           scaleValue *= positive;
01042 
01043 
01044           // revert last scale
01045           GLMatrixd m = localTransformation_;
01046           GLMatrixd mi = localTransformation_;
01047           mi.invert ();
01048 
01049           m.scale(Vec3d (1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
01050           m *= mi;
01051 
01052           scale (m);
01053 
01054           currentScale_ += Vec3d(scaleValue, 0.0, 0.0);
01055 
01056           m = localTransformation_;
01057           m.scale(currentScale_);
01058           m *= mi;
01059 
01060           scale(m);
01061         }else
01062           //translation
01063           translate(ntrans);
01064       }
01065 
01066       // y axis clicked change translation along axis
01067       if (trans[1]) {
01068 
01069         mapToCylinder(_state, oldPoint2D_, old_axis_hit);
01070         mapToCylinder(_state, newPoint2D,  new_axis_hit);
01071 
01072         // translate
01073         // Get screen coordinates of current mouse position and unproject them
01074         // into world coordinates. Project onto selected axis and apply resulting
01075         // vector as translation
01076 
01077         Vec3d d = _state.project(center());
01078                 Vec3d d_origin = _state.project(draggingOrigin3D_);
01079 
01080                 // Snap back to origin position if mouse cursor
01081                 // is near enough
01082                 if (abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE &&
01083                                 abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
01084                        && _event->modifiers() & Qt::AltModifier) {
01085                         newPoint2D = oldPoint2D_;
01086                         Vec3d backtrans = draggingOrigin3D_ - center();
01087                         if (mode_ != Resize) {
01088                                 translate(backtrans);
01089                         }
01090                 }
01091         Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
01092         Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
01093         Vec3d ntrans = newvec - oldvec;
01094 
01095         // project to current direction
01096         ntrans       = ( ntrans | directionY() ) * directionY();
01097 
01098         if (mode_ == Resize){
01099           //scaling
01100           double positive = -1;
01101           if ( (directionY() | ntrans) > 0 ) positive = 1;
01102 
01103           if (currentScale_[1] < 0)
01104             positive *= -1;
01105 
01106           Vec3d proj = _state.project(ntrans + oldvec);
01107 
01108           Vec2d div = Vec2d (proj[0], proj[1]) - Vec2d (oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
01109 
01110           double scaleValue = div.norm () * 3.0 / qMin (_state.context_height(), _state.context_width());
01111           scaleValue *= positive;
01112 
01113           // revert last scale
01114           GLMatrixd m = localTransformation_;
01115           GLMatrixd mi = localTransformation_;
01116           mi.invert ();
01117 
01118           m.scale(Vec3d (1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
01119           m *= mi;
01120 
01121           scale (m);
01122 
01123           currentScale_ += Vec3d(0.0, scaleValue, 0.0);
01124 
01125           m = localTransformation_;
01126           m.scale(currentScale_);
01127           m *= mi;
01128 
01129           scale(m);
01130 
01131         }else
01132           //translation
01133           translate(ntrans);
01134       }
01135 
01136       // z axis clicked change translation along axis
01137       if (trans[2]) {
01138 
01139         mapToCylinder(_state, oldPoint2D_, old_axis_hit);
01140         mapToCylinder(_state, newPoint2D,  new_axis_hit);
01141 
01142         // translate
01143         // Get screen coordinates of current mouse position and unproject them
01144         // into world coordinates. Project onto selected axis and apply resulting
01145         // vector as translation
01146 
01147         Vec3d d = _state.project(center());
01148                 Vec3d d_origin = _state.project(draggingOrigin3D_);
01149 
01150                 // Snap back to origin position if mouse cursor
01151                 // is near enough
01152                 if (abs(d_origin[0] - newPoint2D[0]) < SNAP_PIXEL_TOLERANCE &&
01153                                 abs(_state.context_height() - d_origin[1] - newPoint2D[1]) < SNAP_PIXEL_TOLERANCE
01154                        && _event->modifiers() & Qt::AltModifier) {
01155                         newPoint2D = oldPoint2D_;
01156                         Vec3d backtrans = draggingOrigin3D_ - center();
01157                         if (mode_ != Resize) {
01158                                 translate(backtrans);
01159                         }
01160                 }
01161         Vec3d oldvec = _state.unproject(Vec3d(oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]), d[2]));
01162         Vec3d newvec = _state.unproject(Vec3d(newPoint2D[0], (_state.context_height() - newPoint2D[1]), d[2]));
01163         Vec3d ntrans = newvec - oldvec;
01164 
01165         // project to current direction
01166         ntrans       = ( ntrans | directionZ() ) * directionZ();
01167 
01168         if (mode_ == Resize) {
01169           //scaling
01170           double positive = -1;
01171           if ( (directionZ() | ntrans) > 0 ) positive = 1;
01172 
01173           if (currentScale_[2] < 0)
01174             positive *= -1;
01175 
01176           Vec3d proj = _state.project(ntrans + oldvec);
01177 
01178           Vec2d div = Vec2d (proj[0], proj[1]) - Vec2d (oldPoint2D_[0], (_state.context_height() - oldPoint2D_[1]));
01179 
01180           double scaleValue = div.norm () * 3.0 / qMin (_state.context_height(), _state.context_width());
01181           scaleValue *= positive;
01182 
01183           // revert last scale
01184           GLMatrixd m = localTransformation_;
01185           GLMatrixd mi = localTransformation_;
01186           mi.invert ();
01187 
01188           m.scale(Vec3d (1.0 / currentScale_[0], 1.0 / currentScale_[1], 1.0 / currentScale_[2]));
01189           m *= mi;
01190 
01191           scale (m);
01192 
01193           currentScale_ += Vec3d(0.0, 0.0, scaleValue);
01194 
01195           m = localTransformation_;
01196           m.scale(currentScale_);
01197           m *= mi;
01198 
01199           scale(m);
01200 
01201         }else
01202           //translation
01203           translate(ntrans);
01204       }
01205 
01206       // x top clicked: rotate around x axis
01207       if (rot[0]) {
01208 
01209         mapToCylinder(_state, oldPoint2D_, old_axis_hit);
01210         mapToCylinder(_state, newPoint2D,  new_axis_hit);
01211 
01212 
01213         Vec2i dist = oldPoint2D_ - newPoint2D;
01214 
01215         // Shift has been pressed
01216         // Rotate manipulator but not parent node
01217         if (mode_ == LocalRotation) {
01218 
01219           // Update only local rotation
01220           localTransformation_.rotate( -dist[1], directionX(),ACG::MULT_FROM_LEFT);
01221 
01222         } else {
01223           // Rotate parent node but not manipulator
01224           _state.push_modelview_matrix();
01225           _state.translate(center()[0], center()[1], center()[2]);
01226           update_rotation(_state);
01227 
01228           rotate(dist[1], directionX() );
01229 
01230           _state.pop_modelview_matrix();
01231         }
01232 
01233       }
01234 
01235       // y top clicked: rotate around y axis
01236       // or outer ring on zx axis has been clicked
01237       if (rot[1]) {
01238 
01239         mapToCylinder(_state, oldPoint2D_, old_axis_hit);
01240         mapToCylinder(_state, newPoint2D,  new_axis_hit);
01241 
01242         Vec2i dist = oldPoint2D_ - newPoint2D;
01243 
01244 
01245         if (mode_ == LocalRotation) {
01246 
01247           // Update only local rotation
01248           localTransformation_.rotate( -dist[0], directionY(),ACG::MULT_FROM_LEFT);
01249 
01250         } else {
01251           _state.push_modelview_matrix();
01252           _state.translate(center()[0], center()[1], center()[2]);
01253 
01254           rotate(dist[0], directionY() );
01255 
01256           _state.pop_modelview_matrix();
01257         }
01258       }
01259 
01260       // z top clicked: rotate around z axis
01261       if (rot[2]) {
01262 
01263         mapToCylinder(_state, oldPoint2D_, old_axis_hit);
01264         mapToCylinder(_state, newPoint2D,  new_axis_hit);
01265 
01266 
01267         Vec2i dist = oldPoint2D_ - newPoint2D;
01268 
01269         if (mode_ == LocalRotation) {
01270 
01271           // Update only local rotation
01272           localTransformation_.rotate( (dist[0]+dist[1])/2, directionZ(),ACG::MULT_FROM_LEFT);
01273 
01274         } else {
01275           _state.push_modelview_matrix();
01276           _state.translate(center()[0], center()[1], center()[2]);
01277 
01278           rotate((dist[0]+dist[1])/2, directionZ());
01279 
01280           _state.pop_modelview_matrix();
01281         }
01282 
01283       }
01284 
01285       break;
01286     }
01287 
01288     default: // avoid warning
01289       break;
01290   }
01291 
01292   setDirty ();
01293 
01294   // save old Point
01295   oldPoint2D_   = newPoint2D;
01296 }
01297 
01298 
01299 //----------------------------------------------------------------------------
01300 
01302 bool TranslationManipulatorNode::hitSphere( GLState& _state,
01303               const Vec2i& _v2)
01304 {
01305   // Qt -> GL coordinate systems
01306   unsigned int x = _v2[0];
01307   unsigned int y = _state.context_height() - _v2[1];
01308 
01309 
01310   // get ray from eye through pixel, in sphere coords
01311   Vec3d origin, direction;
01312 
01313   _state.set_updateGL(false);
01314   _state.push_modelview_matrix();
01315 
01316   update_manipulator_system(_state);
01317   _state.scale(2*manipulator_radius_);
01318 
01319   _state.viewing_ray(x, y, origin, direction);
01320 
01321   _state.pop_modelview_matrix();
01322   _state.set_updateGL(true);
01323 
01324 
01325 
01326   // calc sphere-ray intersection
01327   // (sphere is centered at origin, has radius 1)
01328   double a = direction.sqrnorm(),
01329   b = 2.0 * (origin | direction),
01330   c = origin.sqrnorm() - 1.0,
01331   d = b*b - 4.0*a*c;
01332 
01333   return (d >= 0.0);
01334 }
01335 
01336 
01337 //------------------------------------------------------------------------------------
01338 
01339 
01341 
01342 bool TranslationManipulatorNode::hitOuterSphere( GLState& _state,
01343                                  const Vec2i& _v2)
01344 {
01345   // Qt -> GL coordinate systems
01346   unsigned int x = _v2[0];
01347   unsigned int y = _state.context_height() - _v2[1];
01348 
01349 
01350   // get ray from eye through pixel, in sphere coords
01351   Vec3d origin, direction;
01352 
01353   _state.set_updateGL(false);
01354   _state.push_modelview_matrix();
01355 
01356   update_manipulator_system(_state);
01357   _state.scale(manipulator_height_+4*manipulator_radius_);
01358 
01359   _state.viewing_ray(x, y, origin, direction);
01360 
01361   _state.pop_modelview_matrix();
01362   _state.set_updateGL(true);
01363 
01364 
01365   // calc sphere-ray intersection
01366   // (sphere is centered at origin, has radius 1)
01367   double a = direction.sqrnorm(),
01368         b = 2.0 * (origin | direction),
01369         c = origin.sqrnorm() - 1.0,
01370         d = b*b - 4.0*a*c;
01371 
01372   return (d >= 0.0);
01373 }
01374 
01375 
01376 //------------------------------------------------------------------------------------
01377 
01378 
01381 bool
01382 TranslationManipulatorNode::mapToCylinder( GLState&       _state,
01383                                            const Vec2i&   _v1,
01384                                            double&        _axis_hit,
01385                                            StateUpdates   _updateStates )
01386 {
01387   // Qt -> GL coordinate systems
01388   unsigned int x = _v1[0];
01389   unsigned int y = _state.context_height() - _v1[1];
01390 
01391 
01392   // get ray from eye through pixel (cylinder coords)
01393   Vec3d originX, directionX;
01394   Vec3d originY, directionY;
01395   Vec3d originZ, directionZ;
01396 
01397   _state.set_updateGL(false);
01398   _state.push_modelview_matrix();
01399 
01400   // Now that we have 3 different axes we have to test intersection with each of them
01401   // Z-Axis:
01402   update_manipulator_system(_state);
01403   _state.viewing_ray(x, y, originZ, directionZ);
01404 
01405   // Y-Axis:
01406   _state.rotate(-90, 1.0, 0.0, 0.0);
01407   _state.viewing_ray(x, y, originY, directionY);
01408 
01409   // X-Axis:
01410   _state.rotate(90, 0.0, 1.0, 0.0);
01411   _state.viewing_ray(x, y, originX, directionX);
01412 
01413   _state.pop_modelview_matrix();
01414   _state.set_updateGL(true);
01415 
01416 
01417   // get cylinder axis ray: it's in its own coord system!
01418   // Viewing ray function unprojects screen coordinates thorugh inverse viewport, projection and modelview
01419   // such that we end in local coordinate system of the manipulator.
01420   // local transformation of the manipulator is included in update_manipulator_system which applies the
01421   // local transformation to the current glstate used by viewing_ray
01422   const Vec3d origin2(0,0,0),
01423               cylinderAxis(0.0, 0.0, 1.0); // Always same but we change the coordinate system for the viewer
01424 
01425 
01426   // compute pseude-intersection (x axis)
01427   Vec3d normalX = (directionX % cylinderAxis).normalize();
01428   Vec3d vdX = ((origin2 - originX) % directionX);
01429   double axis_hitX = (normalX | vdX);
01430   double orthodistanceX = fabsf( ( origin2 - originX ) | normalX);
01431 
01432   // compute pseude-intersection (y axis)
01433   Vec3d normalY = (directionY % cylinderAxis).normalize();
01434   Vec3d vdY = ((origin2 - originY) % directionY);
01435   double axis_hitY = (normalY | vdY);
01436   double orthodistanceY = fabsf( ( origin2 - originY ) | normalY);
01437 
01438   // compute pseude-intersection (z axis)
01439   Vec3d normalZ = (directionZ % cylinderAxis).normalize();
01440   Vec3d vdZ = ((origin2 - originZ) % directionZ);
01441   double axis_hitZ = (normalZ | vdZ);
01442   double orthodistanceZ = fabsf( ( origin2 - originZ ) | normalZ);
01443 
01444   if ( _updateStates == None )
01445     return false;
01446 
01447   if ( ( orthodistanceX < manipulator_radius_ ) &&
01448             ( axis_hitX      >= 0 )                  &&
01449             ( axis_hitX      <= manipulator_height_ ) )
01450   {
01451 
01452     // z axis has been hit
01453     _axis_hit = axis_hitX;
01454     if ( _updateStates == Click)
01455       element_[XAxis].clicked_ = true;
01456     else
01457       element_[XAxis].over_ = true;
01458 
01459   } else if ( ( orthodistanceY < manipulator_radius_ ) &&
01460                    (   axis_hitY    >= 0 )                  &&
01461                    (   axis_hitY    <= manipulator_height_))
01462   {
01463 
01464     // y axis has been hit
01465     _axis_hit = axis_hitY;
01466     if ( _updateStates == Click)
01467       element_[YAxis].clicked_ = true;
01468     else
01469       element_[YAxis].over_ = true;
01470 
01471   } else if ( ( orthodistanceZ < manipulator_radius_ ) &&
01472                    ( axis_hitZ      >= 0 )                  &&
01473                    ( axis_hitZ      <= manipulator_height_ ) )
01474   {
01475     // x axis has been hit
01476     _axis_hit = axis_hitZ;
01477     if ( _updateStates == Click)
01478       element_[ZAxis].clicked_ = true;
01479     else
01480       element_[ZAxis].over_ = true;
01481 
01482   } else
01483          _axis_hit = 0.0;
01484 
01485   if ( _updateStates == Click)
01486     return (element_[XAxis].clicked_ || element_[YAxis].clicked_ || element_[ZAxis].clicked_);
01487 
01488   return (element_[XAxis].over_ || element_[YAxis].over_ || element_[ZAxis].over_);
01489 }
01490 
01491 
01492 //----------------------------------------------------------------------------
01495 // This method treats the top as cylinder
01496 // TODO: Adapt intersection test to cone shape
01497 bool
01498 TranslationManipulatorNode::mapToCylinderTop( GLState&       _state,
01499                                               const Vec2i&   _v1,
01500                                               double&        _axis_hit,
01501                                               StateUpdates   _updateStates )
01502 {
01503   // Qt -> GL coordinate systems
01504   unsigned int x = _v1[0];
01505   unsigned int y = _state.context_height() - _v1[1];
01506 
01507 
01508   // get ray from eye through pixel (cylinder coords)
01509   Vec3d originX, directionX;
01510   Vec3d originY, directionY;
01511   Vec3d originZ, directionZ;
01512 
01513   _state.set_updateGL(false);
01514   _state.push_modelview_matrix();
01515 
01516   // Z-Axis:
01517   update_manipulator_system(_state);
01518   _state.translate( 0.0, 0.0, manipulator_height_);
01519   _state.viewing_ray(x, y, originZ, directionZ);
01520   _state.translate( 0.0, 0.0, -manipulator_height_);
01521 
01522   // Y-Axis:
01523   _state.rotate(-90, 1.0, 0.0, 0.0);
01524   _state.translate(0.0, 0.0 , manipulator_height_ );
01525   _state.viewing_ray(x, y, originY, directionY);
01526   _state.translate(0.0, 0.0, -manipulator_height_);
01527 
01528   // X-Axis:
01529   _state.rotate(90, 0.0, 1.0, 0.0);
01530   _state.translate(0.0, 0.0, manipulator_height_);
01531   _state.viewing_ray(x, y, originX, directionX);
01532   _state.translate(0.0, 0.0, -manipulator_height_);
01533 
01534   _state.pop_modelview_matrix();
01535   _state.set_updateGL(true);
01536 
01537 
01538   // get cylinder axis ray: it's in its own coord system!
01539   // Viewing ray function unprojects screen coordinates thorugh inverse viewport, projection and modelview
01540   // such that we end in local coordinate system of the manipulator.
01541   // local transformation of the manipulator is included in update_manipulator_system which applies the
01542   // local transformation to the current glstate used by viewing_ray
01543   const Vec3d origin2(0,0,0),
01544               cylinderAxis(0.0, 0.0, 1.0);
01545 
01546   // compute pseude-intersection (x axis)
01547   Vec3d normalX = (directionX % cylinderAxis).normalize();
01548   Vec3d vdX = ((origin2 - originX) % directionX );
01549   double axis_hitX = (normalX | vdX);
01550   double orthodistanceX = fabsf( ( origin2 - originX ) | normalX);
01551 
01552   // compute pseude-intersection (y axis)
01553   Vec3d normalY = (directionY % cylinderAxis).normalize();
01554   Vec3d vdY = ((origin2 - originY) % directionY);
01555   double axis_hitY = (normalY | vdY);
01556   double orthodistanceY = fabsf( ( origin2 - originY ) | normalY);
01557 
01558   // compute pseude-intersection (z axis)
01559   Vec3d normalZ = (directionZ % cylinderAxis).normalize();
01560   Vec3d vdZ = ((origin2 - originZ) % directionZ);
01561   double axis_hitZ = (normalZ | vdZ);
01562   double orthodistanceZ = fabsf( ( origin2 - originZ ) | normalZ);
01563 
01564   if ( _updateStates == None )
01565     return false;
01566 
01567   // TODO: Work with cones :
01568 
01569   if ( ( orthodistanceX <  manipulator_radius_ * 2.0 ) &&
01570             ( axis_hitX      >= 0.0 )                       &&
01571             ( axis_hitX      <= manipulator_height_ / 2.0 ) )
01572   {
01573 
01574     // z top has been hit
01575     _axis_hit = axis_hitX;
01576     if ( _updateStates == Click)
01577       element_[XTop].clicked_ = true;
01578     else
01579       element_[XTop].over_ = true;
01580 
01581   } else if ( ( orthodistanceY <  manipulator_radius_ * 2.0 ) &&
01582                    ( axis_hitY      >= 0.0 )                      &&
01583                    ( axis_hitY      <= manipulator_height_ / 2.0 ) )
01584   {
01585 
01586     // y top has been hit
01587     _axis_hit = axis_hitY;
01588     if ( _updateStates == Click)
01589       element_[YTop].clicked_ = true;
01590     else
01591       element_[YTop].over_ = true;
01592 
01593   } else if ( ( orthodistanceZ <  manipulator_radius_ * 2.0 ) &&
01594                    ( axis_hitZ      >= 0.0 )                       &&
01595                    ( axis_hitZ      <= manipulator_height_ / 2.0 ) )
01596   {
01597 
01598     // x top has been hit
01599     _axis_hit = axis_hitZ;
01600     if ( _updateStates == Click)
01601       element_[ZTop].clicked_ = true;
01602     else
01603       element_[ZTop].over_ = true;
01604 
01605   } else
01606     _axis_hit = 0.0;
01607 
01608   if ( _updateStates == Click)
01609     return (element_[XTop].clicked_ || element_[YTop].clicked_ || element_[ZTop].clicked_);
01610   return (element_[XTop].over_ || element_[YTop].over_ || element_[ZTop].over_);
01611 }
01612 
01613 //----------------------------------------------------------------------------
01614 
01618 bool
01619 TranslationManipulatorNode::mapToSphere( GLState& _state,
01620                                          const Vec2i& _v2,
01621                                          Vec3d& _v3,
01622                                          StateUpdates _updateStates)
01623 {
01624   // Qt -> GL coordinate systems
01625   unsigned int x = _v2[0];
01626   unsigned int y = _state.context_height() - _v2[1];
01627 
01628   // get ray from eye through pixel
01629   Vec3d originXY, directionXY,
01630         originYZ, directionYZ,
01631         originZX, directionZX;
01632 
01633   _state.set_updateGL(false);
01634   _state.push_modelview_matrix();
01635 
01636   update_manipulator_system(_state);
01637 
01638   _state.viewing_ray(x, y, originXY, directionXY);
01639   _state.rotate(90, 0.0, 1.0, 0.0);
01640   _state.viewing_ray(x, y, originYZ, directionYZ);
01641   _state.rotate(90, 1.0, 0.0, 0.0);
01642   _state.viewing_ray(x, y, originZX, directionZX);
01643 
01644   _state.pop_modelview_matrix();
01645   _state.set_updateGL(true);
01646 
01647   // origin + direction * t = (x, y, 0) <=> t = -origin_z / direction_z
01648   // => Point on xy-plane p = (origin_x + direction_x*t, origin_y + direction_y*t, 0)
01649   double t1 = -originXY[2]/directionXY[2];
01650   Vec3d hitPointXY = originXY + directionXY*t1;
01651 
01652   double t2 = -originYZ[2]/directionYZ[2];
01653   Vec3d hitPointYZ = originYZ + directionYZ*t2;
01654 
01655   double t3 = -originZX[2]/directionZX[2];
01656   Vec3d hitPointZX = originZX + directionZX*t3;
01657 
01658   // Depth test: Take nearest object
01659   bool t1_near = false, t2_near = false, t3_near = false;
01660   if( t1 <= t2 && t1 <= t3)
01661     t1_near = true;
01662   if( t2 <= t1 && t2 <= t3)
01663     t2_near = true;
01664   if( t3 <= t1 && t3 <= t2)
01665       t3_near = true;
01666 
01667   bool xy_hit = hitPointXY.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
01668           hitPointXY.length() < 2*manipulator_height_;
01669 
01670   bool yz_hit = hitPointYZ.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
01671           hitPointYZ.length() < 2*manipulator_height_;
01672 
01673   bool zx_hit = hitPointZX.length() > 2*manipulator_height_ - manipulator_height_/4.0 &&
01674           hitPointZX.length() < 2*manipulator_height_;
01675 
01676 
01677   bool more_than_one_hit = (xy_hit && yz_hit) || (xy_hit && zx_hit) || (yz_hit && zx_hit);
01678 //   std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
01679 //        hitPointXY << " < " << 2*manipulator_height_ << std::endl;
01680 //
01681 //   std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
01682 //        hitPointYZ << " < " << 2*manipulator_height_ << std::endl;
01683 //
01684 //   std::cerr << 2*manipulator_height_ - manipulator_height_/3.0 << " < " <<
01685 //        hitPointZX << " < " << 2*manipulator_height_ << std::endl;
01686 
01687   // Test if hit point on x-y plane matches length of
01688   // manipulator radius_state
01689   if(xy_hit && (!more_than_one_hit || t1_near))
01690   {
01691       // Outer ring on xy plane has been hit
01692       if ( _updateStates == Click)
01693         element_[ZRing].clicked_ = true;
01694       else if ( _updateStates == Over)
01695         element_[ZRing].over_ = true;
01696       _v3 = hitPointXY;
01697       return true;
01698   }
01699 
01700   else if(yz_hit && (!more_than_one_hit || t2_near))
01701   {
01702       // Outer ring on yz plane has been hit
01703       if ( _updateStates == Click)
01704         element_[XRing].clicked_ = true;
01705       else if ( _updateStates == Over)
01706         element_[XRing].over_ = true;
01707       _v3 = hitPointYZ;
01708       return true;
01709   }
01710 
01711   else if(zx_hit && (!more_than_one_hit || t3_near))
01712   {
01713       // Outer ring around zx plane has been hit
01714       if ( _updateStates == Click)
01715         element_[YRing].clicked_ = true;
01716       else if ( _updateStates == Over)
01717         element_[YRing].over_ = true;
01718       _v3 = hitPointZX;
01719       return true;
01720   }
01721 
01722   return false;
01723 }
01724 
01725 //----------------------------------------------------------------------------
01726 
01727 void
01728 TranslationManipulatorNode::
01729 pick(GLState& _state, PickTarget _target)
01730 {
01731   if (_target == PICK_FACE ||
01732            _target == PICK_ANYTHING) {
01733 
01734     if (draw_manipulator_) {
01735 
01736         updateSize (_state);
01737 
01738         _state.pick_set_maximum(5);
01739 
01740         // Enable depth test but store original status
01741         glPushAttrib(GL_DEPTH_BUFFER_BIT);
01742         glEnable(GL_DEPTH_TEST);
01743         glDepthFunc(GL_LEQUAL);
01744 
01745         // Save modelview matrix
01746         _state.push_modelview_matrix();
01747 
01748         // Correctly align nodes local coordinate system
01749         update_manipulator_system(_state);
01750 
01751         _state.pick_set_name(0);
01752         //================================================================================================
01753         // Z-Axis
01754         //================================================================================================
01755         // gluCylinder draws into z direction so z-Axis first
01756 
01757         gluCylinder(axis_,
01758         manipulator_radius_,
01759         manipulator_radius_,
01760         manipulator_height_,
01761         manipulator_slices_,
01762         manipulator_stacks_);
01763 
01764         // Draw Top of z-axis
01765         _state.translate(0.0, 0.0, manipulator_height_);
01766         gluCylinder(axis_,
01767         manipulator_radius_*2,
01768         0,
01769         manipulator_height_/2,
01770         manipulator_slices_,
01771         manipulator_stacks_);
01772         _state.translate(0.0, 0.0, -manipulator_height_);
01773 
01774         _state.pick_set_name(1);
01775         //================================================================================================
01776         // Y-Axis
01777         //================================================================================================
01778         _state.rotate(-90, 1.0, 0.0, 0.0);
01779         gluCylinder(axis_,
01780                     manipulator_radius_,
01781         manipulator_radius_,
01782         manipulator_height_,
01783         manipulator_slices_,
01784         manipulator_stacks_);
01785 
01786         // Draw Top of y-axis
01787         _state.translate(0.0, 0.0, manipulator_height_);
01788         gluCylinder(axis_,
01789                     manipulator_radius_*2,
01790                     0,
01791                     manipulator_height_/2,
01792                     manipulator_slices_,
01793                     manipulator_stacks_);
01794         _state.translate(0.0, 0.0, -manipulator_height_);
01795 
01796 
01797         _state.pick_set_name(2);
01798         //================================================================================================
01799         // X-Axis
01800         //================================================================================================
01801         _state.rotate(90, 0.0, 1.0, 0.0);
01802 
01803         gluCylinder(axis_,
01804                     manipulator_radius_,
01805                     manipulator_radius_,
01806                     manipulator_height_,
01807                     manipulator_slices_,
01808                     manipulator_stacks_);
01809 
01810         // Draw Top of x-axis
01811         _state.translate(0.0, 0.0, manipulator_height_);
01812         gluCylinder(axis_,
01813                     manipulator_radius_*2,
01814         0,
01815         manipulator_height_/2,
01816         manipulator_slices_,
01817         manipulator_stacks_);
01818         _state.translate(0.0, 0.0, -manipulator_height_);
01819 
01820         _state.pick_set_name(3);
01821         //=================================================================================================
01822         // Sphere
01823         //=================================================================================================
01824 
01825         gluSphere( sphere_, manipulator_radius_*2, manipulator_slices_, manipulator_stacks_ );
01826 
01827         //=================================================================================================
01828         // Outer-Spheres
01829         //=================================================================================================
01830 
01831         _state.pick_set_name(4);
01832         drawCircle(2*manipulator_height_, 2*manipulator_height_ - manipulator_height_/4.0);
01833 
01834         _state.rotate(90, 0.0, 1.0, 0.0);
01835         drawCircle(2*manipulator_height_, 2*manipulator_height_ - manipulator_height_/4.0);
01836 
01837         _state.rotate(90, 1.0, 0.0, 0.0);
01838         drawCircle(2*manipulator_height_, 2*manipulator_height_ - manipulator_height_/4.0);
01839 
01840 
01841         // Restore old attributes and modelview
01842         glPopAttrib();
01843 
01844         _state.pop_modelview_matrix();
01845     }
01846   }
01847 }
01848 
01849 
01850 //----------------------------------------------------------------------------
01851 
01852 void
01853 TranslationManipulatorNode::set_direction(const Vec3d& _directionX, const Vec3d& _directionY)
01854 {
01855 
01856   localTransformation_.identity();
01857 
01858   double angle;
01859 
01860 //   std::cerr << "_directionX " << _directionX[0] << " " << _directionX[1] << " " << _directionX[2] << std::endl;
01861 //   std::cerr << "_directionY " << _directionY[0] << " " << _directionY[1] << " " << _directionY[2] << std::endl;
01862 //   std::cerr << "dirX_ " << dirX_[0] << " " << dirX_[1] << " " << dirX_[2] << std::endl;
01863 //   std::cerr << "dirY_ " << dirY_[0] << " " << dirY_[1] << " " << dirY_[2] << std::endl;
01864 
01865   angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(_directionX) | MathTools::sane_normalized(dirX_) )));
01866 
01867 // std::cerr << "X angle = " << angle << std::endl;
01868 
01869   Vec3d rotAxis = MathTools::sane_normalized( dirX_ % _directionX );
01870 
01871   if ( rotAxis.sqrnorm() == 0.0 )
01872     rotAxis = MathTools::sane_normalized( dirZ_ );
01873 
01874   localTransformation_.rotate( angle, rotAxis );
01875 
01876   Vec3d newDirY = MathTools::sane_normalized( localTransformation_.transform_vector(dirY_) );
01877 
01878   angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(_directionY) | MathTools::sane_normalized(newDirY) )));
01879 
01880 // std::cerr << "Y angle = " << angle <<  std::endl;
01881   Vec3d rotAxis2 = MathTools::sane_normalized( newDirY % _directionY );
01882 
01883   if ( rotAxis2.sqrnorm() == 0.0 )
01884     rotAxis2 = MathTools::sane_normalized( localTransformation_.transform_vector(dirX_) );
01885 
01886   localTransformation_.rotate( angle, rotAxis2 );
01887 }
01888 
01889 //----------------------------------------------------------------------------
01890 
01891 
01892 Vec3d
01893 TranslationManipulatorNode::directionX() const
01894 {
01895   return MathTools::sane_normalized( localTransformation_.transform_vector(dirX_) );
01896 }
01897 
01898 //----------------------------------------------------------------------------
01899 
01900 
01901 Vec3d
01902 TranslationManipulatorNode::directionY() const
01903 {
01904   return MathTools::sane_normalized( localTransformation_.transform_vector(dirY_) );
01905 }
01906 
01907 //----------------------------------------------------------------------------
01908 
01909 
01910 Vec3d
01911 TranslationManipulatorNode::directionZ() const
01912 {
01913   return MathTools::sane_normalized(localTransformation_.transform_vector(dirZ_));
01914 }
01915 
01916 //----------------------------------------------------------------------------
01917 
01918 double TranslationManipulatorNode::get_screen_length (GLState& _state, Vec3d& _point) const
01919 {
01920   Vec3d proj = _state.project (_point);
01921   proj[0] += 1.0;
01922   Vec3d uproj = _state.unproject (proj);
01923   uproj -= _point;
01924   return uproj.length ();
01925 }
01926 
01927 //----------------------------------------------------------------------------
01928 
01929 void TranslationManipulatorNode::updateSize (GLState& _state)
01930 {
01931   if (auto_size_ != TranslationManipulatorNode::Never)
01932   {
01933     Vec3d point = localTransformation_.transform_point(Vec3d (0.0, 0.0, 0.0));
01934 
01935     int tmp, width, height;
01936 
01937     _state.get_viewport (tmp, tmp, width, height);
01938 
01939     auto_size_length_ = get_screen_length (_state, point) * (width + height) * 0.02;
01940 
01941     if (auto_size_ == TranslationManipulatorNode::Once)
01942       auto_size_ = TranslationManipulatorNode::Never;
01943   }
01944 
01945   manipulator_radius_ = set_manipulator_radius_ * auto_size_length_;
01946   manipulator_height_ = set_manipulator_height_ * auto_size_length_;
01947 }
01948 
01949 //----------------------------------------------------------------------------
01950 
01951 
01952 void TranslationManipulatorNode::boundingBox( Vec3f & _bbMin, Vec3f & _bbMax )
01953 {
01954   if (!draw_manipulator_)
01955     return;
01956 
01957   float r = 2 * manipulator_height_;
01958 
01959   _bbMin.minimize(Vec3f(-r,-r,-r));
01960   _bbMax.maximize(Vec3f(r,r,r));
01961 }
01962 
01963 //----------------------------------------------------------------------------
01964 
01965 void TranslationManipulatorNode::setMode (ManipulatorMode _mode)
01966 {
01967   if (mode_ != _mode)
01968     ignoreTime_ = true;
01969   mode_ = _mode;
01970   setDirty ();
01971 }
01972 
01973 //=============================================================================
01974 } // namespace SceneGraph
01975 } // namespace ACG
01976 //=============================================================================

acg pic Project OpenFlipper, ©  Computer Graphics Group, RWTH Aachen. Documentation generated using doxygen .