interactive_marker_control.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #include <OgreViewport.h>
00031 #include <OgreCamera.h>
00032 #include <OgreSceneNode.h>
00033 #include <OgreSceneManager.h>
00034 #include <OgrePass.h>
00035 #include <OgreMaterial.h>
00036 #include <OgreEntity.h>
00037 #include <OgreSubEntity.h>
00038 #include <OgreSharedPtr.h>
00039 #include <OgreTechnique.h>
00040 
00041 #include "rviz/display_context.h"
00042 #include "rviz/selection/selection_manager.h"
00043 #include "rviz/render_panel.h"
00044 #include "rviz/load_resource.h"
00045 #include "rviz/window_manager_interface.h"
00046 #include "rviz/geometry.h"
00047 #include "rviz/frame_manager.h"
00048 
00049 #include "rviz/ogre_helpers/line.h"
00050 
00051 #include "rviz/default_plugin/markers/shape_marker.h"
00052 #include "rviz/default_plugin/markers/arrow_marker.h"
00053 #include "rviz/default_plugin/markers/line_list_marker.h"
00054 #include "rviz/default_plugin/markers/line_strip_marker.h"
00055 #include "rviz/default_plugin/markers/points_marker.h"
00056 #include "rviz/default_plugin/markers/text_view_facing_marker.h"
00057 #include "rviz/default_plugin/markers/mesh_resource_marker.h"
00058 #include "rviz/default_plugin/markers/triangle_list_marker.h"
00059 #include "rviz/default_plugin/markers/marker_base.h"
00060 
00061 #include "rviz/default_plugin/interactive_markers/interactive_marker_control.h"
00062 #include "rviz/default_plugin/interactive_markers/interactive_marker.h"
00063 
00064 #define NO_HIGHLIGHT_VALUE 0.0
00065 #define ACTIVE_HIGHLIGHT_VALUE 0.5
00066 #define HOVER_HIGHLIGHT_VALUE 0.3
00067 
00068 namespace rviz
00069 {
00070 
00071 InteractiveMarkerControl::InteractiveMarkerControl( DisplayContext* context,
00072                                                     Ogre::SceneNode *reference_node,
00073                                                     InteractiveMarker *parent )
00074 : mouse_dragging_(false)
00075 , drag_viewport_( NULL )
00076 , context_( context )
00077 , reference_node_(reference_node)
00078 , control_frame_node_(reference_node_->createChildSceneNode())
00079 , markers_node_(reference_node_->createChildSceneNode())
00080 , parent_(parent)
00081 , rotation_(0)
00082 , grab_point_in_reference_frame_(0,0,0)
00083 , interaction_enabled_(false)
00084 , visible_(true)
00085 , view_facing_( false )
00086 , mouse_down_(false)
00087 , show_visual_aids_(false)
00088 , line_(new Line(context->getSceneManager(),control_frame_node_))
00089 {
00090   line_->setVisible(false);
00091 }
00092 
00093 void InteractiveMarkerControl::makeMarkers( const visualization_msgs::InteractiveMarkerControl& message )
00094 {
00095   for (unsigned i = 0; i < message.markers.size(); i++)
00096   {
00097     MarkerBasePtr marker;
00098 
00099     // create a marker with the given type
00100     switch (message.markers[i].type)
00101     {
00102       case visualization_msgs::Marker::CUBE:
00103       case visualization_msgs::Marker::CYLINDER:
00104       case visualization_msgs::Marker::SPHERE:
00105       {
00106         marker.reset(new ShapeMarker(0, context_, markers_node_));
00107       }
00108         break;
00109 
00110       case visualization_msgs::Marker::ARROW:
00111       {
00112         marker.reset(new ArrowMarker(0, context_, markers_node_));
00113       }
00114         break;
00115 
00116       case visualization_msgs::Marker::LINE_STRIP:
00117       {
00118         marker.reset(new LineStripMarker(0, context_, markers_node_));
00119       }
00120         break;
00121       case visualization_msgs::Marker::LINE_LIST:
00122       {
00123         marker.reset(new LineListMarker(0, context_, markers_node_));
00124       }
00125         break;
00126       case visualization_msgs::Marker::SPHERE_LIST:
00127       case visualization_msgs::Marker::CUBE_LIST:
00128       case visualization_msgs::Marker::POINTS:
00129       {
00130         PointsMarkerPtr points_marker;
00131         points_marker.reset(new PointsMarker(0, context_, markers_node_));
00132         points_markers_.push_back( points_marker );
00133         marker = points_marker;
00134       }
00135         break;
00136       case visualization_msgs::Marker::TEXT_VIEW_FACING:
00137       {
00138         marker.reset(new TextViewFacingMarker(0, context_, markers_node_));
00139       }
00140         break;
00141       case visualization_msgs::Marker::MESH_RESOURCE:
00142       {
00143         marker.reset(new MeshResourceMarker(0, context_, markers_node_));
00144       }
00145         break;
00146 
00147       case visualization_msgs::Marker::TRIANGLE_LIST:
00148       {
00149         marker.reset(new TriangleListMarker(0, context_, markers_node_));
00150       }
00151         break;
00152       default:
00153         ROS_ERROR( "Unknown marker type: %d", message.markers[i].type );
00154         break;
00155     }
00156 
00157     visualization_msgs::MarkerPtr marker_msg( new visualization_msgs::Marker(message.markers[ i ]) );
00158 
00159     if ( marker_msg->header.frame_id.empty() )
00160     {
00161       // Put Marker into fixed frame, so the constructor does not apply any tf transform.
00162       // This effectively discards any tf information in the Marker and interprets its pose
00163       // as relative to the Interactive Marker.
00164       marker_msg->header.frame_id = context_->getFrameManager()->getFixedFrame();
00165       marker->setMessage( marker_msg );
00166     }
00167     else
00168     {
00169       marker->setMessage( marker_msg );
00170       // The marker will set its position relative to the fixed frame,
00171       // but we have attached it our own scene node, so we will have to
00172       // correct for that.
00173       marker->setPosition( markers_node_->convertWorldToLocalPosition( marker->getPosition() ) );
00174       marker->setOrientation( markers_node_->convertWorldToLocalOrientation( marker->getOrientation() ) );
00175     }
00176     marker->setInteractiveObject( shared_from_this() );
00177 
00178     addHighlightPass(marker->getMaterials());
00179 
00180     markers_.push_back(marker);
00181   }
00182 }
00183 
00184 InteractiveMarkerControl::~InteractiveMarkerControl()
00185 {
00186   context_->getSceneManager()->destroySceneNode(control_frame_node_);
00187   context_->getSceneManager()->destroySceneNode(markers_node_);
00188 
00189   if( view_facing_ )
00190   {
00191     context_->getSceneManager()->removeListener(this);
00192   }
00193 }
00194 
00195 void InteractiveMarkerControl::processMessage( const visualization_msgs::InteractiveMarkerControl &message )
00196 {
00197   name_ = message.name;
00198   description_ = QString::fromStdString( message.description );
00199   interaction_mode_ = message.interaction_mode;
00200   always_visible_ = message.always_visible;
00201   orientation_mode_ = message.orientation_mode;
00202 
00203   control_orientation_ = Ogre::Quaternion(message.orientation.w,
00204       message.orientation.x, message.orientation.y, message.orientation.z);
00205   control_orientation_.normalise();
00206 
00207   bool new_view_facingness = (message.orientation_mode == visualization_msgs::InteractiveMarkerControl::VIEW_FACING);
00208   if( new_view_facingness != view_facing_ )
00209   {
00210     if( new_view_facingness )
00211     {
00212       context_->getSceneManager()->addListener(this);
00213     }
00214     else
00215     {
00216       context_->getSceneManager()->removeListener(this);
00217     }
00218     view_facing_ = new_view_facingness;
00219   }
00220   
00221   independent_marker_orientation_ = message.independent_marker_orientation;
00222 
00223   // highlight_passes_ have raw pointers into the markers_, so must
00224   // clear them at the same time.
00225   highlight_passes_.clear();
00226   markers_.clear();
00227   points_markers_.clear();
00228 
00229   // Initially, the pose of this marker's node and the interactive
00230   // marker are identical, but that may change.
00231   control_frame_node_->setPosition(parent_->getPosition());
00232   markers_node_->setPosition(parent_->getPosition());
00233 
00234   if ( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::INHERIT )
00235   {
00236     control_frame_node_->setOrientation(parent_->getOrientation());
00237     markers_node_->setOrientation(parent_->getOrientation());
00238   }
00239   else
00240   {
00241     control_frame_node_->setOrientation( Ogre::Quaternion::IDENTITY );
00242     markers_node_->setOrientation( Ogre::Quaternion::IDENTITY );
00243   }
00244 
00245   makeMarkers( message );
00246 
00247   status_msg_ = description_+" ";
00248 
00249   Ogre::Vector3 control_dir = control_orientation_.xAxis()*10000.0;
00250   line_->setPoints( control_dir, -1*control_dir );
00251   line_->setVisible(false);
00252 
00253   // Create our own custom cursor
00254   switch( interaction_mode_ )
00255   {
00256   case visualization_msgs::InteractiveMarkerControl::NONE:
00257     cursor_ = rviz::getDefaultCursor();
00258     break;
00259   case visualization_msgs::InteractiveMarkerControl::MENU:
00260     cursor_ = rviz::makeIconCursor( "package://rviz/icons/menu.svg" );
00261     status_msg_ += "<b>Left-Click:</b> Show menu.";
00262     break;
00263   case visualization_msgs::InteractiveMarkerControl::BUTTON:
00264     cursor_ = rviz::getDefaultCursor();
00265     status_msg_ += "<b>Left-Click:</b> Activate. ";
00266     break;
00267   case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS:
00268     cursor_ = rviz::makeIconCursor( "package://rviz/icons/move1d.svg" );
00269     status_msg_ += "<b>Left-Click:</b> Move. ";
00270     break;
00271   case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE:
00272     cursor_ = rviz::makeIconCursor( "package://rviz/icons/move2d.svg" );
00273     status_msg_ += "<b>Left-Click:</b> Move. ";
00274     break;
00275   case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS:
00276     cursor_ = rviz::makeIconCursor( "package://rviz/icons/rotate.svg" );
00277     status_msg_ += "<b>Left-Click:</b> Rotate. ";
00278     break;
00279   case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE:
00280     cursor_ = rviz::makeIconCursor( "package://rviz/icons/moverotate.svg" );
00281     status_msg_ += "<b>Left-Click:</b> Move / Rotate. ";
00282     break;
00283   case visualization_msgs::InteractiveMarkerControl::MOVE_3D:
00284     cursor_ = rviz::makeIconCursor( "package://rviz/icons/move2d.svg" );
00285     status_msg_ += "<b>Left-Click:</b> Move X/Y. <b>Shift + Left-Click / Left-Click + Wheel:</b> Move Z. ";
00286     break;
00287   case visualization_msgs::InteractiveMarkerControl::ROTATE_3D:
00288     cursor_ = rviz::makeIconCursor( "package://rviz/icons/rotate.svg" );
00289     status_msg_ += "<b>Left-Click:</b> Rotate around X/Y. <b>Shift-Left-Click:</b> Rotate around Z. ";
00290     break;
00291   case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D:
00292     cursor_ = rviz::makeIconCursor( "package://rviz/icons/moverotate.svg" );
00293     status_msg_ += "<b>Left-Click:</b> Move X/Y. <b>Shift + Left-Click / Left-Click + Wheel:</b> Move Z. <b>Ctrl + Left-Click:</b> Rotate around X/Y. <b>Ctrl + Shift + Left-Click:</b> Rotate around Z. ";
00294     break;
00295   }
00296 
00297   if ( parent_->hasMenu() && interaction_mode_ != visualization_msgs::InteractiveMarkerControl::MENU )
00298   {
00299     status_msg_ += "<b>Right-Click:</b> Show context menu.";
00300   }
00301 
00302   // It's not clear to me why this one setOrientation() call needs to
00303   // be here and not above makeMarkers() with the other
00304   // setOrientation() calls, but it works correctly when here and
00305   // incorrectly when there.  Sorry. -hersh
00306   if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
00307       independent_marker_orientation_ )
00308   {
00309     markers_node_->setOrientation( parent_->getOrientation() );
00310   }
00311 
00312   enableInteraction(context_->getSelectionManager()->getInteractionEnabled());
00313 }
00314 
00315 // This is an Ogre::SceneManager::Listener function, and is configured
00316 // to be called only if this is a VIEW_FACING control.
00317 void InteractiveMarkerControl::preFindVisibleObjects(
00318     Ogre::SceneManager *source,
00319     Ogre::SceneManager::IlluminationRenderStage irs, Ogre::Viewport *v )
00320 {
00321   updateControlOrientationForViewFacing( v );
00322 }
00323 
00324 void InteractiveMarkerControl::updateControlOrientationForViewFacing( Ogre::Viewport* v )
00325 {
00326   Ogre::Quaternion x_view_facing_rotation =
00327       control_orientation_.xAxis().getRotationTo( v->getCamera()->getDerivedDirection());
00328 
00329   // rotate so z axis is up
00330   Ogre::Vector3 z_axis_2 = x_view_facing_rotation * control_orientation_.zAxis();
00331   Ogre::Quaternion align_yz_rotation = z_axis_2.getRotationTo(v->getCamera()->getDerivedUp());
00332 
00333   // rotate
00334   Ogre::Quaternion rotate_around_x = Ogre::Quaternion(rotation_, v->getCamera()->getDerivedDirection());
00335 
00336   Ogre::Quaternion rotation = reference_node_->convertWorldToLocalOrientation(
00337       rotate_around_x * align_yz_rotation * x_view_facing_rotation );
00338 
00339   control_frame_node_->setOrientation( rotation );
00340 
00341   if ( !independent_marker_orientation_ )
00342   {
00343     markers_node_->setOrientation( rotation );
00344     // we need to refresh the node manually, since the scene manager will only do this one frame
00345     // later otherwise
00346     markers_node_->_update(true, false);
00347   }
00348 }
00349 
00350 bool InteractiveMarkerControl::getVisible()
00351 {
00352   return visible_ || always_visible_;
00353 }
00354 
00355 void InteractiveMarkerControl::setVisible( bool visible )
00356 {
00357   visible_ = visible;
00358 
00359   if (always_visible_)
00360   {
00361     markers_node_->setVisible(visible_);
00362   } else
00363   {
00364     markers_node_->setVisible(interaction_enabled_ && visible_);
00365   }
00366 }
00367 
00368 void InteractiveMarkerControl::update()
00369 {
00370   if( mouse_dragging_ )
00371   {
00372     handleMouseMovement( dragging_in_place_event_ );
00373   }
00374 }
00375 
00376 void InteractiveMarkerControl::enableInteraction( bool enable )
00377 {
00378   if (mouse_down_)
00379   {
00380     return;
00381   }
00382 
00383   interaction_enabled_ = enable;
00384   setVisible(visible_);
00385   if (!enable)
00386   {
00387     setHighlight(NO_HIGHLIGHT_VALUE);
00388   }
00389 }
00390 
00391 void InteractiveMarkerControl::interactiveMarkerPoseChanged(
00392     Ogre::Vector3 int_marker_position, Ogre::Quaternion int_marker_orientation )
00393 {
00394   control_frame_node_->setPosition(int_marker_position);
00395   markers_node_->setPosition(int_marker_position);
00396 
00397   switch (orientation_mode_)
00398   {
00399     case visualization_msgs::InteractiveMarkerControl::INHERIT:
00400       control_frame_node_->setOrientation(int_marker_orientation);
00401       markers_node_->setOrientation(control_frame_node_->getOrientation());
00402       break;
00403 
00404     case visualization_msgs::InteractiveMarkerControl::FIXED:
00405     {
00406       control_frame_node_->setOrientation( Ogre::Quaternion( rotation_, control_orientation_.xAxis() ));
00407       markers_node_->setOrientation(control_frame_node_->getOrientation());
00408       break;
00409     }
00410 
00411     case visualization_msgs::InteractiveMarkerControl::VIEW_FACING:
00412       if( drag_viewport_ )
00413       {
00414         updateControlOrientationForViewFacing( drag_viewport_ );
00415       }
00416       if ( independent_marker_orientation_ )
00417       {
00418         markers_node_->setOrientation(int_marker_orientation);
00419       }
00420       break;
00421 
00422     default:
00423       break;
00424   }
00425 }
00426 
00427 Ogre::Vector3 InteractiveMarkerControl::closestPointOnLineToPoint( const Ogre::Vector3& line_start,
00428                                                                    const Ogre::Vector3& line_dir,
00429                                                                    const Ogre::Vector3& test_point )
00430 {
00431   // Find closest point on projected ray to mouse point
00432   // Math: if P is the start of the ray, v is the direction vector of
00433   //       the ray (not normalized), and X is the test point, then the
00434   //       closest point on the line to X is given by:
00435   //
00436   //               (X-P).v
00437   //       P + v * -------
00438   //                 v.v
00439   //       where "." is the dot product.
00440   double factor = ( test_point - line_start ).dotProduct( line_dir ) / line_dir.dotProduct( line_dir );
00441   Ogre::Vector3 closest_point = line_start + line_dir * factor;
00442   return closest_point;
00443 }
00444 
00445 void InteractiveMarkerControl::rotate( Ogre::Ray &mouse_ray )
00446 {
00447   Ogre::Vector3 intersection_3d;
00448   Ogre::Vector2 intersection_2d;
00449   float ray_t;
00450 
00451   Ogre::Vector3 rotation_axis = control_frame_orientation_at_mouse_down_ * control_orientation_.xAxis();
00452 
00453   // Find rotation_center = 3D point closest to grab_point_ which is
00454   // on the rotation axis, relative to the reference frame.
00455   Ogre::Vector3 rotation_center = closestPointOnLineToPoint( control_frame_node_->getPosition(),
00456                                                              rotation_axis,
00457                                                              grab_point_in_reference_frame_ );
00458 
00459   // Find intersection of mouse_ray with plane centered at rotation_center.
00460   if( intersectSomeYzPlane( mouse_ray, rotation_center, control_frame_orientation_at_mouse_down_,
00461                             intersection_3d, intersection_2d, ray_t ))
00462   {
00463     // Not that efficient, but reduces code duplication...
00464     rotate(intersection_3d);
00465   }
00466 }
00467 
00468 void InteractiveMarkerControl::rotate( const Ogre::Vector3& cursor_in_reference_frame )
00469 {
00470   Ogre::Vector3 rotation_axis = control_frame_orientation_at_mouse_down_ * control_orientation_.xAxis();
00471 
00472   // Find rotation_center = 3D point closest to grab_point_ which is
00473   // on the rotation axis, relative to the reference frame.
00474   Ogre::Vector3 rotation_center = closestPointOnLineToPoint( control_frame_node_->getPosition(),
00475                                                              rotation_axis,
00476                                                              grab_point_in_reference_frame_ );
00477 
00478 
00479   Ogre::Vector3 grab_rel_center = grab_point_in_reference_frame_ - rotation_center;
00480   Ogre::Vector3 center_to_cursor = cursor_in_reference_frame - rotation_center;
00481   Ogre::Vector3 center_to_cursor_radial = center_to_cursor - center_to_cursor.dotProduct(rotation_axis)*rotation_axis;
00482 
00483   Ogre::Quaternion orientation_change_since_mouse_down =
00484     grab_rel_center.getRotationTo( center_to_cursor_radial, rotation_axis );
00485 
00486   Ogre::Radian rot;
00487   Ogre::Vector3 axis;
00488   orientation_change_since_mouse_down.ToAngleAxis( rot, axis );
00489   // Quaternion::ToAngleAxis() always gives a positive angle.  The
00490   // axis it emits (in this case) will either be equal to
00491   // rotation_axis or will be the negative of it.  Doing the
00492   // dot-product then gives either 1.0 or -1.0, which is just what
00493   // we need to get the sign for our angle.
00494   Ogre::Radian rotation_since_mouse_down = rot * axis.dotProduct( rotation_axis );
00495 
00496   rotation_ = rotation_at_mouse_down_ + rotation_since_mouse_down;
00497   parent_->setPose( parent_->getPosition(),
00498                     orientation_change_since_mouse_down * parent_orientation_at_mouse_down_,
00499                     name_ );
00500 }
00501 
00502 Ogre::Ray InteractiveMarkerControl::getMouseRayInReferenceFrame( const ViewportMouseEvent& event, int x, int y )
00503 {
00504   float width = event.viewport->getActualWidth() - 1;
00505   float height = event.viewport->getActualHeight() - 1;
00506 
00507   Ogre::Ray mouse_ray = event.viewport->getCamera()->getCameraToViewportRay( (x + .5) / width,
00508                                                                              (y + .5) / height );
00509 
00510   // convert ray into reference frame
00511   mouse_ray.setOrigin( reference_node_->convertWorldToLocalPosition( mouse_ray.getOrigin() ) );
00512   mouse_ray.setDirection( reference_node_->convertWorldToLocalOrientation( Ogre::Quaternion::IDENTITY ) * mouse_ray.getDirection() );
00513 
00514   return mouse_ray;
00515 }
00516 
00517 void InteractiveMarkerControl::beginRelativeMouseMotion( const ViewportMouseEvent& event )
00518 {
00519   mouse_x_at_drag_begin_ = event.x;
00520   mouse_y_at_drag_begin_ = event.y;
00521   modifiers_at_drag_begin_ = event.modifiers;
00522 
00523   mouse_ray_at_drag_begin_ = getMouseRayInReferenceFrame( event, event.x, event.y );
00524 
00525   // ensure direction is unit vector
00526   mouse_ray_at_drag_begin_.setDirection(mouse_ray_at_drag_begin_.getDirection().normalisedCopy());
00527 }
00528 
00529 bool InteractiveMarkerControl::getRelativeMouseMotion( const ViewportMouseEvent& event, int& dx, int& dy )
00530 {
00531   dx = event.x - mouse_x_at_drag_begin_;
00532   dy = event.y - mouse_y_at_drag_begin_;
00533   if (dx == 0 && dy == 0)
00534     return false;
00535 
00536   QCursor::setPos( mouse_x_at_drag_begin_ + mouse_relative_to_absolute_x_,
00537                    mouse_y_at_drag_begin_ + mouse_relative_to_absolute_y_ );
00538   return true;
00539 }
00540 
00541 void InteractiveMarkerControl::rotateXYRelative( const ViewportMouseEvent& event )
00542 {
00543   int dx;
00544   int dy;
00545 
00546   if (!getRelativeMouseMotion( event, dx, dy ))
00547     return;
00548 
00549   static const double MOUSE_SCALE = 2 * 3.14 / 300; // 300 pixels = 360deg
00550   Ogre::Radian rx(dx * MOUSE_SCALE);
00551   Ogre::Radian ry(dy * MOUSE_SCALE);
00552 
00553   Ogre::Quaternion up_rot(rx, event.viewport->getCamera()->getRealUp());
00554   Ogre::Quaternion right_rot(ry, event.viewport->getCamera()->getRealRight());
00555 
00556   parent_->setPose( parent_->getPosition(),
00557                     up_rot * right_rot * parent_->getOrientation(),
00558                     name_ );
00559 }
00560 
00561 void InteractiveMarkerControl::rotateZRelative( const ViewportMouseEvent& event )
00562 {
00563   int dx;
00564   int dy;
00565 
00566   getRelativeMouseMotion( event, dx, dy );
00567   if (std::abs(dy) > std::abs(dx))
00568     dx = dy;
00569   if (dx == 0)
00570     return;
00571 
00572   static const double MOUSE_SCALE = 2 * 3.14 / 300; // 300 pixels = 360deg
00573   Ogre::Radian rx(dx * MOUSE_SCALE);
00574 
00575   Ogre::Quaternion rot(rx, event.viewport->getCamera()->getRealDirection());
00576 
00577   parent_->setPose( parent_->getPosition(),
00578                     rot * parent_->getOrientation(),
00579                     name_ );
00580 }
00581 
00582 void InteractiveMarkerControl::moveZAxisRelative( const ViewportMouseEvent& event )
00583 {
00584   int dx;
00585   int dy;
00586 
00587   getRelativeMouseMotion( event, dx, dy );
00588   if (std::abs(dx) > std::abs(dy))
00589     dy = -dx;
00590   if (dy == 0)
00591     return;
00592 
00593   double distance = -dy * mouse_z_scale_;
00594   Ogre::Vector3 delta = distance * mouse_ray_at_drag_begin_.getDirection();
00595 
00596   parent_->setPose( parent_->getPosition() + delta,
00597                     parent_->getOrientation(),
00598                     name_ );
00599 
00600   parent_position_at_mouse_down_ = parent_->getPosition();
00601 }
00602 
00603 void InteractiveMarkerControl::moveZAxisWheel( const ViewportMouseEvent& event )
00604 {
00605   // wheel_delta is in 1/8 degree and usually jumps 15 degrees at a time
00606   static const double WHEEL_TO_PIXEL_SCALE = (1.0/8.0) * (2.0/15.0);   // 2 pixels per click
00607 
00608   double distance = event.wheel_delta * WHEEL_TO_PIXEL_SCALE;
00609   Ogre::Vector3 delta = distance * mouse_ray_at_drag_begin_.getDirection();
00610 
00611   parent_->setPose( parent_->getPosition() + delta,
00612                     parent_->getOrientation(),
00613                     name_ );
00614 
00615   parent_position_at_mouse_down_ = parent_->getPosition();
00616 }
00617 
00618 void InteractiveMarkerControl::moveViewPlane( Ogre::Ray &mouse_ray, const ViewportMouseEvent& event )
00619 {
00620   // find plane on which mouse is moving
00621   Ogre::Plane plane( event.viewport->getCamera()->getRealDirection(),
00622                      parent_position_at_mouse_down_ + parent_to_grab_position_);
00623 
00624   // find intersection of mouse with the plane
00625   std::pair<bool, Ogre::Real> intersection = mouse_ray.intersects(plane);
00626   if (!intersection.first)
00627     return;
00628   Ogre::Vector3 mouse_position_on_plane = mouse_ray.getPoint(intersection.second);
00629 
00630   // move parent so grab position relative to parent coincides with new mouse position.
00631   parent_->setPose( mouse_position_on_plane - parent_to_grab_position_,
00632                     parent_->getOrientation(),
00633                     name_ );
00634 }
00635 
00636 void InteractiveMarkerControl::movePlane( Ogre::Ray &mouse_ray )
00637 {
00638   if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
00639       drag_viewport_ )
00640   {
00641     updateControlOrientationForViewFacing( drag_viewport_ );
00642   }
00643 
00644   Ogre::Vector3 intersection_3d;
00645   Ogre::Vector2 intersection_2d;
00646   float ray_t;
00647 
00648   if( intersectSomeYzPlane( mouse_ray, grab_point_in_reference_frame_, control_frame_node_->getOrientation(),
00649                             intersection_3d, intersection_2d, ray_t ))
00650   {
00651     parent_->setPose( intersection_3d - grab_point_in_reference_frame_ + parent_position_at_mouse_down_, parent_->getOrientation(), name_ );
00652   }
00653 }
00654 
00655 void InteractiveMarkerControl::movePlane( const Ogre::Vector3& cursor_position_in_reference_frame )
00656 {
00657   if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
00658       drag_viewport_ )
00659   {
00660     updateControlOrientationForViewFacing( drag_viewport_ );
00661   }
00662 
00663   Ogre::Vector3 plane_normal = (control_frame_node_->getOrientation() * control_orientation_.xAxis());
00664   Ogre::Vector3 displacement = (cursor_position_in_reference_frame - grab_point_in_reference_frame_);
00665   Ogre::Vector3 displacement_on_plane =  displacement - displacement.dotProduct(plane_normal) * plane_normal;
00666 
00667   // set position of parent to parent_position_at_mouse_down_ + displacement_on_plane.
00668   parent_->setPose( parent_position_at_mouse_down_ + displacement_on_plane,
00669                     parent_->getOrientation(), name_ );
00670 }
00671 
00674 void InteractiveMarkerControl::worldToScreen( const Ogre::Vector3& pos_rel_reference,
00675                                               const Ogre::Viewport* viewport,
00676                                               Ogre::Vector2& screen_pos )
00677 {
00678   Ogre::Vector3 world_pos = reference_node_->convertLocalToWorldPosition( pos_rel_reference );
00679 
00680   const Ogre::Camera* cam = viewport->getCamera();
00681   Ogre::Vector3 homogeneous_screen_position = cam->getProjectionMatrix() * (cam->getViewMatrix() * world_pos);
00682 
00683   double half_width = viewport->getActualWidth() / 2.0;
00684   double half_height = viewport->getActualHeight() / 2.0;
00685 
00686   screen_pos.x = half_width + (half_width * homogeneous_screen_position.x) - .5;
00687   screen_pos.y = half_height + (half_height * -homogeneous_screen_position.y) - .5;
00688 }
00689 
00693 bool InteractiveMarkerControl::findClosestPoint( const Ogre::Ray& target_ray,
00694                                                  const Ogre::Ray& mouse_ray,
00695                                                  Ogre::Vector3& closest_point )
00696 {
00697   // Find the closest point on target_ray to any point on mouse_ray.
00698   //
00699   // Math taken from http://paulbourke.net/geometry/lineline3d/
00700   // line P1->P2 is target_ray
00701   // line P3->P4 is mouse_ray
00702 
00703   Ogre::Vector3 v13 = target_ray.getOrigin() - mouse_ray.getOrigin();
00704   Ogre::Vector3 v43 = mouse_ray.getDirection();
00705   Ogre::Vector3 v21 = target_ray.getDirection();
00706   double d1343 = v13.dotProduct( v43 );
00707   double d4321 = v43.dotProduct( v21 );
00708   double d1321 = v13.dotProduct( v21 );
00709   double d4343 = v43.dotProduct( v43 );
00710   double d2121 = v21.dotProduct( v21 );
00711 
00712   double denom = d2121 * d4343 - d4321 * d4321;
00713   if( fabs( denom ) <= Ogre::Matrix3::EPSILON )
00714   {
00715     return false;
00716   }
00717   double numer = d1343 * d4321 - d1321 * d4343;
00718 
00719   double mua = numer / denom;
00720   closest_point = target_ray.getPoint( mua );
00721   return true;
00722 }
00723 
00724 void InteractiveMarkerControl::moveAxis( const Ogre::Ray& mouse_ray, const ViewportMouseEvent& event )
00725 {
00726   // compute control-axis ray based on grab_point_, etc.
00727   Ogre::Ray control_ray;
00728   control_ray.setOrigin( grab_point_in_reference_frame_ );
00729   control_ray.setDirection( control_frame_node_->getOrientation() * control_orientation_.xAxis() );
00730   
00731   // project control-axis ray onto screen.
00732   Ogre::Vector2 control_ray_screen_start, control_ray_screen_end;
00733   worldToScreen( control_ray.getOrigin(), event.viewport, control_ray_screen_start );
00734   worldToScreen( control_ray.getPoint( 1 ), event.viewport, control_ray_screen_end );
00735 
00736   Ogre::Vector2 mouse_point( event.x, event.y );
00737 
00738   // Find closest point on projected ray to mouse point
00739   // Math: if P is the start of the ray, v is the direction vector of
00740   //       the ray (not normalized), and X is the test point, then the
00741   //       closest point on the line to X is given by:
00742   //
00743   //               (X-P).v
00744   //       P + v * -------
00745   //                 v.v
00746   //       where "." is the dot product.
00747   Ogre::Vector2 control_ray_screen_dir = control_ray_screen_end - control_ray_screen_start;
00748   double denominator = control_ray_screen_dir.dotProduct( control_ray_screen_dir );
00749   if( fabs( denominator ) > Ogre::Matrix3::EPSILON ) // If the control ray is not straight in line with the view.
00750   {
00751     double factor =
00752       ( mouse_point - control_ray_screen_start ).dotProduct( control_ray_screen_dir ) / denominator;
00753     
00754     Ogre::Vector2 closest_screen_point = control_ray_screen_start + control_ray_screen_dir * factor;
00755 
00756     // make a new "mouse ray" for the point on the projected ray
00757     Ogre::Ray new_mouse_ray = getMouseRayInReferenceFrame( event, closest_screen_point.x, closest_screen_point.y );
00758 
00759     // find closest point on control-axis ray to new mouse ray (should intersect actually)
00760     Ogre::Vector3 closest_point;
00761     if( findClosestPoint( control_ray, new_mouse_ray, closest_point ))
00762     {
00763       // set position of parent to closest_point - grab_point_ + parent_position_at_mouse_down_.
00764       parent_->setPose( closest_point - grab_point_in_reference_frame_ + parent_position_at_mouse_down_,
00765                         parent_->getOrientation(), name_ );
00766     }
00767   }
00768 }
00769 
00770 void InteractiveMarkerControl::moveAxis( const Ogre::Vector3& cursor_position_in_reference_frame )
00771 {
00772   Ogre::Vector3 control_unit_direction = (control_frame_node_->getOrientation() * control_orientation_.xAxis());
00773   Ogre::Vector3 displacement_along_axis = (cursor_position_in_reference_frame - grab_point_in_reference_frame_).dotProduct(control_unit_direction) * control_unit_direction;
00774 
00775   // set position of parent to closest_point - grab_point_ + parent_position_at_mouse_down_.
00776   parent_->setPose( parent_position_at_mouse_down_ + displacement_along_axis,
00777                     parent_->getOrientation(), name_ );
00778 
00779 }
00780 
00781 void InteractiveMarkerControl::moveRotate( Ogre::Ray &mouse_ray )
00782 {
00783   if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
00784       drag_viewport_ )
00785   {
00786     updateControlOrientationForViewFacing( drag_viewport_ );
00787   }
00788 
00789   Ogre::Vector3 new_drag_rel_ref;
00790   Ogre::Vector2 intersection_2d;
00791   float ray_t;
00792 
00793   // get rotation axis rel ref (constant for entire drag)
00794   //  - rotation_axis_
00795 
00796   // get current rotation center rel ref
00797   //  - compute rotation center rel control frame at mouse-down (constant for entire drag)
00798   //  - current rotation center rel ref = current control frame * above
00799   Ogre::Matrix4 control_rel_ref;
00800   control_rel_ref.makeTransform( control_frame_node_->getPosition(),
00801                                  Ogre::Vector3::UNIT_SCALE,
00802                                  control_frame_node_->getOrientation() );
00803   Ogre::Vector3 rotation_center = control_rel_ref * rotation_center_rel_control_;
00804 
00805   // get previous 3D drag point rel ref
00806   //  - compute grab point rel control frame at mouse-down (constant for entire drag)
00807   //  - prev_drag_rel_ref = current control frame + above
00808   Ogre::Vector3 prev_drag_rel_ref = control_rel_ref * grab_point_rel_control_;
00809 
00810   // get new 3D drag point rel ref (this is "intersection_3d" in rotate().)
00811   //  - intersectSomeYzPlane( mouse_ray, rotation_center, control_frame_orientation )
00812   if( intersectSomeYzPlane( mouse_ray, rotation_center, control_frame_node_->getOrientation(),
00813                             new_drag_rel_ref, intersection_2d, ray_t ))
00814   {
00815     // compute rotation angle from old drag point to new.
00816     //  - prev_rel_center = prev_drag_rel_ref - rotation_center
00817     //  - new_rel_center = new_drag_rel_ref - rotation_center
00818     //  - rotation_change = prev_rel_center.getRotationTo( new_rel_center, rotation_axis )
00819     //  - get Radians of angle change
00820     //  - rotation_ += angle_change
00821     //  - parent_->rotate(rotation_change)
00822     Ogre::Vector3 prev_rel_center = prev_drag_rel_ref - rotation_center;
00823     Ogre::Vector3 new_rel_center = new_drag_rel_ref - rotation_center;
00824     if( new_rel_center.length() > Ogre::Matrix3::EPSILON )
00825     {
00826       Ogre::Quaternion rotation_change = prev_rel_center.getRotationTo( new_rel_center, rotation_axis_ );
00827       Ogre::Radian rot;
00828       Ogre::Vector3 axis;
00829       rotation_change.ToAngleAxis( rot, axis );
00830       // Quaternion::ToAngleAxis() always gives a positive angle.  The
00831       // axis it emits (in this case) will either be equal to
00832       // rotation_axis or will be the negative of it.  Doing the
00833       // dot-product then gives either 1.0 or -1.0, which is just what
00834       // we need to get the sign for our angle.
00835       Ogre::Radian angle_change = rot * axis.dotProduct( rotation_axis_ );
00836       rotation_ += angle_change;
00837       parent_->rotate( rotation_change, name_ );
00838 
00839       // compute translation from rotated old drag point to new drag point.
00840       //  - pos_change = new_rel_center * (1.0 - prev_rel_center.length() / new_rel_center.length())
00841       //  - parent_->translate(pos_change)
00842       parent_->translate( new_rel_center * (1.0 - prev_rel_center.length() / new_rel_center.length()), name_ );
00843     }    
00844   }
00845 }
00846 
00847 void InteractiveMarkerControl::moveRotate( const Ogre::Vector3& cursor_position_in_reference_frame, bool lock_axis )
00848 {
00849   if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
00850       drag_viewport_ )
00851   {
00852     updateControlOrientationForViewFacing( drag_viewport_ );
00853   }
00854 
00855   // get rotation axis rel ref (constant for entire drag)
00856   //  - rotation_axis_
00857 
00858   // get current rotation center rel ref
00859   //  - compute rotation center rel control frame at mouse-down (constant for entire drag)
00860   //  - current rotation center rel ref = current control frame * above
00861   Ogre::Matrix4 control_rel_ref;
00862   control_rel_ref.makeTransform( control_frame_node_->getPosition(),
00863                                  Ogre::Vector3::UNIT_SCALE,
00864                                  control_frame_node_->getOrientation() );
00865   Ogre::Vector3 rotation_center = control_rel_ref * rotation_center_rel_control_;
00866 
00867   // get previous 3D drag point rel ref
00868   //  - compute grab point rel control frame at mouse-down (constant for entire drag)
00869   //  - prev_drag_rel_ref = current control frame + above
00870   Ogre::Vector3 prev_drag_rel_ref = control_rel_ref * grab_point_rel_control_;
00871 
00872 
00873   Ogre::Vector3 new_drag_rel_ref = cursor_position_in_reference_frame;
00874   if (lock_axis)
00875   {
00876     Ogre::Vector3 plane_normal = (control_frame_node_->getOrientation() * control_orientation_.xAxis());
00877     Ogre::Vector3 perpendicular_offset = (new_drag_rel_ref - prev_drag_rel_ref)
00878                                           .dotProduct(plane_normal)*plane_normal;
00879     new_drag_rel_ref -= perpendicular_offset;
00880   }
00881 
00882   //Ogre::Vector3 new_drag_rel_ref = cursor_position_in_reference_frame;
00883   // compute rotation angle from old drag point to new.
00884   //  - prev_rel_center = prev_drag_rel_ref - rotation_center
00885   //  - new_rel_center = new_drag_rel_ref - rotation_center
00886   //  - rotation_change = prev_rel_center.getRotationTo( new_rel_center, rotation_axis )
00887   //  - get Radians of angle change
00888   //  - rotation_ += angle_change
00889   //  - parent_->rotate(rotation_change)
00890   Ogre::Vector3 prev_rel_center = prev_drag_rel_ref - rotation_center;
00891   Ogre::Vector3 new_rel_center = new_drag_rel_ref - rotation_center;
00892   if( new_rel_center.length() > Ogre::Matrix3::EPSILON )
00893   {
00894     Ogre::Quaternion rotation_change = prev_rel_center.getRotationTo( new_rel_center, rotation_axis_ );
00895     Ogre::Radian rot;
00896     Ogre::Vector3 axis;
00897     rotation_change.ToAngleAxis( rot, axis );
00898     // Quaternion::ToAngleAxis() always gives a positive angle.  The
00899     // axis it emits (in this case) will either be equal to
00900     // rotation_axis or will be the negative of it.  Doing the
00901     // dot-product then gives either 1.0 or -1.0, which is just what
00902     // we need to get the sign for our angle.
00903     Ogre::Radian angle_change = rot * axis.dotProduct( rotation_axis_ );
00904     rotation_ += angle_change;
00905     parent_->rotate( rotation_change, name_ );
00906 
00907     // compute translation from rotated old drag point to new drag point.
00908     //  - pos_change = new_rel_center * (1.0 - prev_rel_center.length() / new_rel_center.length())
00909     //  - parent_->translate(pos_change)
00910     parent_->translate( new_rel_center * (1.0 - prev_rel_center.length() / new_rel_center.length()), name_ );
00911   }
00912 }
00913 
00914 void InteractiveMarkerControl::move3D( const Ogre::Vector3& cursor_position_in_reference_frame,
00915                                        const Ogre::Quaternion& cursor_orientation_in_reference_frame )
00916 {
00917     if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
00918         drag_viewport_ )
00919     {
00920       updateControlOrientationForViewFacing( drag_viewport_ );
00921     }
00922 
00923     //parent_to_cursor_in_cursor_frame_at_grab_ =  cursor_3D_orientation.Inverse()*(cursor_3D_pos - parent_->getPosition());
00924     //rotation_cursor_to_parent_at_grab_ =  cursor_3D_orientation.Inverse()*parent->getOrientation();
00925 
00926 
00927     Ogre::Vector3 world_to_cursor_in_world_frame = reference_node_->convertLocalToWorldPosition(cursor_position_in_reference_frame);
00928     Ogre::Quaternion rotation_world_to_cursor = reference_node_->convertLocalToWorldOrientation(cursor_orientation_in_reference_frame);
00929 
00930     //Ogre::Vector3 marker_to_cursor_in_cursor_frame = orientation_world_to_cursor.Inverse()*reference_node_->getOrientation()*grab_point_in_reference_frame_;
00931 
00932     Ogre::Vector3    world_to_cursor_in_cursor_frame = rotation_world_to_cursor.Inverse()*world_to_cursor_in_world_frame;
00933     Ogre::Vector3    world_to_marker_in_world_frame = rotation_world_to_cursor*(world_to_cursor_in_cursor_frame - parent_to_cursor_in_cursor_frame_at_grab_);
00934     Ogre::Vector3    marker_position_in_reference_frame = reference_node_->convertWorldToLocalPosition(world_to_marker_in_world_frame);
00935     //Ogre::Quaternion marker_orientation_in_reference_frame = reference_node_->convertWorldToLocalOrientation(rotation_world_to_cursor*rotation_cursor_to_parent_at_grab_);
00936 
00937     parent_->setPose( marker_position_in_reference_frame,
00938                       parent_->getOrientation(), name_ );
00939 }
00940 
00941 void InteractiveMarkerControl::rotate3D( const Ogre::Vector3& cursor_position_in_reference_frame,
00942                                          const Ogre::Quaternion& cursor_orientation_in_reference_frame )
00943 {
00944     if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
00945         drag_viewport_ )
00946     {
00947       updateControlOrientationForViewFacing( drag_viewport_ );
00948     }
00949 
00950     //parent_to_cursor_in_cursor_frame_at_grab_ =  cursor_3D_orientation.Inverse()*(cursor_3D_pos - parent_->getPosition());
00951     //rotation_cursor_to_parent_at_grab_ =  cursor_3D_orientation.Inverse()*parent->getOrientation();
00952 
00953 
00954     Ogre::Vector3 world_to_cursor_in_world_frame = reference_node_->convertLocalToWorldPosition(cursor_position_in_reference_frame);
00955     Ogre::Quaternion rotation_world_to_cursor = reference_node_->convertLocalToWorldOrientation(cursor_orientation_in_reference_frame);
00956 
00957     //Ogre::Vector3 marker_to_cursor_in_cursor_frame = orientation_world_to_cursor.Inverse()*reference_node_->getOrientation()*grab_point_in_reference_frame_;
00958 
00959     Ogre::Vector3    world_to_cursor_in_cursor_frame = rotation_world_to_cursor.Inverse()*world_to_cursor_in_world_frame;
00960     Ogre::Vector3    world_to_marker_in_world_frame = rotation_world_to_cursor*(world_to_cursor_in_cursor_frame - parent_to_cursor_in_cursor_frame_at_grab_);
00961     Ogre::Vector3    marker_position_in_reference_frame = reference_node_->convertWorldToLocalPosition(world_to_marker_in_world_frame);
00962     Ogre::Quaternion marker_orientation_in_reference_frame = reference_node_->convertWorldToLocalOrientation(rotation_world_to_cursor*rotation_cursor_to_parent_at_grab_);
00963 
00964     parent_->setPose( parent_->getPosition(),
00965                       marker_orientation_in_reference_frame, name_ );
00966 }
00967 
00968 
00969 void InteractiveMarkerControl::moveRotate3D( const Ogre::Vector3& cursor_position_in_reference_frame,
00970                                              const Ogre::Quaternion& cursor_orientation_in_reference_frame )
00971 {
00972     if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
00973         drag_viewport_ )
00974     {
00975       updateControlOrientationForViewFacing( drag_viewport_ );
00976     }
00977 
00978     //parent_to_cursor_in_cursor_frame_at_grab_ =  cursor_3D_orientation.Inverse()*(cursor_3D_pos - parent_->getPosition());
00979     //rotation_cursor_to_parent_at_grab_ =  cursor_3D_orientation.Inverse()*parent->getOrientation();
00980 
00981 
00982     Ogre::Vector3 world_to_cursor_in_world_frame = reference_node_->convertLocalToWorldPosition(cursor_position_in_reference_frame);
00983     Ogre::Quaternion rotation_world_to_cursor = reference_node_->convertLocalToWorldOrientation(cursor_orientation_in_reference_frame);
00984 
00985     //Ogre::Vector3 marker_to_cursor_in_cursor_frame = orientation_world_to_cursor.Inverse()*reference_node_->getOrientation()*grab_point_in_reference_frame_;
00986 
00987     Ogre::Vector3    world_to_cursor_in_cursor_frame = rotation_world_to_cursor.Inverse()*world_to_cursor_in_world_frame;
00988     Ogre::Vector3    world_to_marker_in_world_frame = rotation_world_to_cursor*(world_to_cursor_in_cursor_frame - parent_to_cursor_in_cursor_frame_at_grab_);
00989     Ogre::Vector3    marker_position_in_reference_frame = reference_node_->convertWorldToLocalPosition(world_to_marker_in_world_frame);
00990     Ogre::Quaternion marker_orientation_in_reference_frame = reference_node_->convertWorldToLocalOrientation(rotation_world_to_cursor*rotation_cursor_to_parent_at_grab_);
00991 
00992     parent_->setPose( marker_position_in_reference_frame,
00993                       marker_orientation_in_reference_frame, name_ );
00994 }
00995 
00996 void InteractiveMarkerControl::setHighlight( const ControlHighlight &hl  ){
00997   if(hl == NO_HIGHLIGHT) setHighlight(NO_HIGHLIGHT_VALUE);
00998   if(hl == HOVER_HIGHLIGHT) setHighlight(HOVER_HIGHLIGHT_VALUE);
00999   if(hl == ACTIVE_HIGHLIGHT) setHighlight(ACTIVE_HIGHLIGHT_VALUE);
01000 }
01001 
01002 void InteractiveMarkerControl::setHighlight( float a )
01003 {
01004   std::set<Ogre::Pass*>::iterator it;
01005   for (it = highlight_passes_.begin(); it != highlight_passes_.end(); it++)
01006   {
01007     (*it)->setAmbient(a,a,a);
01008   }
01009 
01010   std::vector<PointsMarkerPtr>::iterator pm_it;
01011   for( pm_it = points_markers_.begin(); pm_it != points_markers_.end(); pm_it++ )
01012   {
01013     (*pm_it)->setHighlightColor( a, a, a );
01014   }
01015 }
01016 
01017 void InteractiveMarkerControl::recordDraggingInPlaceEvent( ViewportMouseEvent& event )
01018 {
01019   dragging_in_place_event_ = event;
01020   dragging_in_place_event_.type = QEvent::MouseMove;
01021 }
01022 
01023 void InteractiveMarkerControl::stopDragging( bool force )
01024 {
01025   // aleeper: Why is this check here? What happens when this mouse_dragging_ check isn't done at all?
01026   // Or as an alternative to this minor API change, we could just manually set mouse_dragging_
01027   // to true before calling this function from the 3D cursor code.
01028   // BUT that would be a hack...
01029   if ( mouse_dragging_ || force )
01030   {
01031     line_->setVisible(false);
01032     mouse_dragging_ = false;
01033     drag_viewport_ = NULL;
01034     parent_->stopDragging();
01035   }
01036 }
01037 
01038 // Almost a wholesale copy of the mouse event code... can these be combined?
01039 void InteractiveMarkerControl::handle3DCursorEvent( ViewportMouseEvent event,
01040                                                     const Ogre::Vector3& cursor_3D_pos,
01041                                                     const Ogre::Quaternion& cursor_3D_orientation)
01042 {
01043   // change dragging state
01044   switch( interaction_mode_ )
01045   {
01046   case visualization_msgs::InteractiveMarkerControl::BUTTON:
01047     if( event.leftUp() )
01048     {
01049       Ogre::Vector3 point_rel_world = cursor_3D_pos;
01050       bool got_3D_point = true;
01051 
01052       visualization_msgs::InteractiveMarkerFeedback feedback;
01053       feedback.event_type = visualization_msgs::InteractiveMarkerFeedback::BUTTON_CLICK;
01054       feedback.control_name = name_;
01055       feedback.marker_name = parent_->getName();
01056       parent_->publishFeedback( feedback, got_3D_point, point_rel_world );
01057     }
01058     break;
01059 
01060   case visualization_msgs::InteractiveMarkerControl::MENU:
01061     if( event.leftUp() )
01062     {
01063       // Save the 3D mouse point to send with the menu feedback, if any.
01064       Ogre::Vector3 three_d_point = cursor_3D_pos;
01065       bool valid_point = true;
01066       Ogre::Vector2 mouse_pos = project3DPointToViewportXY(event.viewport, three_d_point);
01067       QCursor::setPos(event.panel->mapToGlobal(QPoint(mouse_pos.x, mouse_pos.y)));
01068       parent_->showMenu( event, name_, three_d_point, valid_point );
01069     }
01070     break;
01071 
01072   case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS:
01073   case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE:
01074   case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE:
01075   case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS:
01076   case visualization_msgs::InteractiveMarkerControl::MOVE_3D:
01077   case visualization_msgs::InteractiveMarkerControl::ROTATE_3D:
01078   case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D:
01079     if( event.leftDown() )
01080     {
01081       parent_->startDragging();
01082       drag_viewport_ = event.viewport;
01083 
01084       //recordDraggingInPlaceEvent( event );
01085       grab_point_in_reference_frame_ = reference_node_->convertWorldToLocalPosition( cursor_3D_pos );
01086       grab_orientation_in_reference_frame_ = reference_node_->convertWorldToLocalOrientation( cursor_3D_orientation );
01087 
01088       parent_to_cursor_in_cursor_frame_at_grab_ =  cursor_3D_orientation.Inverse()*(cursor_3D_pos - reference_node_->convertLocalToWorldPosition(parent_->getPosition()));
01089       rotation_cursor_to_parent_at_grab_ =  cursor_3D_orientation.Inverse()*reference_node_->convertLocalToWorldOrientation(parent_->getOrientation());
01090 
01091       parent_position_at_mouse_down_ = parent_->getPosition();
01092       parent_orientation_at_mouse_down_ = parent_->getOrientation();
01093 
01094       if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
01095           drag_viewport_ )
01096       {
01097         updateControlOrientationForViewFacing( drag_viewport_ );
01098       }
01099       control_frame_orientation_at_mouse_down_ = control_frame_node_->getOrientation();
01100       rotation_at_mouse_down_ = rotation_;
01101 
01102       rotation_axis_ = control_frame_node_->getOrientation() * control_orientation_.xAxis();
01103 
01104       // Find rotation_center = 3D point closest to grab_point_ which is
01105       // on the rotation axis, relative to the reference frame.
01106       Ogre::Vector3 rotation_center_rel_ref = closestPointOnLineToPoint( parent_->getPosition(),
01107                                                                          rotation_axis_,
01108                                                                          grab_point_in_reference_frame_ );
01109       Ogre::Matrix4 reference_rel_control_frame;
01110       reference_rel_control_frame.makeInverseTransform( control_frame_node_->getPosition(),
01111                                                         Ogre::Vector3::UNIT_SCALE,
01112                                                         control_frame_node_->getOrientation() );
01113       rotation_center_rel_control_ = reference_rel_control_frame * rotation_center_rel_ref;
01114       grab_point_rel_control_ = reference_rel_control_frame * grab_point_in_reference_frame_;
01115     }
01116     if( event.leftUp() )
01117     {
01118       // Alternatively, could just manually set mouse_dragging_ to true.
01119       stopDragging( true );
01120     }
01121     break;
01122 
01123   default:
01124     break;
01125   }
01126 
01127   if( event.leftDown() )
01128   {
01129     setHighlight( ACTIVE_HIGHLIGHT_VALUE );
01130   }
01131   else if( event.leftUp() )
01132   {
01133     setHighlight( HOVER_HIGHLIGHT_VALUE );
01134   }
01135 
01136   if (!parent_->handle3DCursorEvent(event, cursor_3D_pos, cursor_3D_orientation, name_))
01137   {
01138     if( event.type == QEvent::MouseMove && event.left()) // && mouse_dragging_)
01139     {
01140       Ogre::Vector3 cursor_position_in_reference_frame = reference_node_->convertWorldToLocalPosition( cursor_3D_pos );
01141       Ogre::Quaternion cursor_orientation_in_reference_frame = reference_node_->convertWorldToLocalOrientation( cursor_3D_orientation );
01142 
01143       switch (interaction_mode_)
01144       {
01145       case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS:
01146         rotate( cursor_position_in_reference_frame );
01147         break;
01148 
01149       case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS:
01150         moveAxis( cursor_position_in_reference_frame );
01151         break;
01152 
01153       case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE:
01154         movePlane( cursor_position_in_reference_frame );
01155         break;
01156 
01157       case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE:
01158         moveRotate( cursor_position_in_reference_frame, true );
01159         break;
01160 
01161       case visualization_msgs::InteractiveMarkerControl::MOVE_3D:
01162         move3D( cursor_position_in_reference_frame, cursor_orientation_in_reference_frame );
01163         break;
01164 
01165       case visualization_msgs::InteractiveMarkerControl::ROTATE_3D:
01166         rotate3D( cursor_position_in_reference_frame, cursor_orientation_in_reference_frame );
01167         break;
01168 
01169       case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D:
01170         moveRotate3D( cursor_position_in_reference_frame, cursor_orientation_in_reference_frame );
01171         break;
01172 
01173       default:
01174         break;
01175       }
01176     }
01177   }
01178 }
01179 
01180 void InteractiveMarkerControl::handleMouseEvent( ViewportMouseEvent& event )
01181 {
01182   // REMOVE ME ROS_INFO("Mouse event!");
01183   // * check if this is just a receive/lost focus event
01184   // * try to hand over the mouse event to the parent interactive marker
01185   // * otherwise, execute mouse move handling
01186 
01187   // handle receive/lose focus
01188   if( event.type == QEvent::FocusIn )
01189   {
01190     has_focus_ = true;
01191     std::set<Ogre::Pass*>::iterator it;
01192     setHighlight( HOVER_HIGHLIGHT_VALUE );
01193     context_->setStatus( status_msg_ );
01194   }
01195   else if( event.type == QEvent::FocusOut )
01196   {
01197     stopDragging();
01198     has_focus_ = false;
01199     setHighlight(0.0);
01200     return;
01201   }
01202 
01203   mouse_down_ = event.left() || event.middle() || event.right();
01204 
01205   // change dragging state
01206   switch( interaction_mode_ )
01207   {
01208   case visualization_msgs::InteractiveMarkerControl::BUTTON:
01209     if( event.leftUp() )
01210     {
01211       Ogre::Vector3 point_rel_world;
01212       bool got_3D_point = context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, point_rel_world );
01213 
01214       visualization_msgs::InteractiveMarkerFeedback feedback;
01215       feedback.event_type = visualization_msgs::InteractiveMarkerFeedback::BUTTON_CLICK;
01216       feedback.control_name = name_;
01217       feedback.marker_name = parent_->getName();
01218       parent_->publishFeedback( feedback, got_3D_point, point_rel_world );
01219     }
01220     break;
01221 
01222   case visualization_msgs::InteractiveMarkerControl::MENU:
01223     if( event.leftUp() )
01224     {
01225       Ogre::Vector3 point_rel_world;
01226       bool got_3D_point = context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, point_rel_world );
01227       parent_->showMenu( event, name_, point_rel_world, got_3D_point );
01228     }
01229     break;
01230 
01231   case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS:
01232   case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE:
01233   case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS:
01234     if ( event.leftDown() )
01235       beginMouseMovement( event,
01236                           show_visual_aids_ &&
01237                           orientation_mode_ != visualization_msgs::InteractiveMarkerControl::VIEW_FACING);
01238     break;
01239 
01240   case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE:
01241     if( event.leftDown() )
01242       beginMouseMovement( event, false);
01243     break;
01244 
01245   case visualization_msgs::InteractiveMarkerControl::MOVE_3D:
01246   case visualization_msgs::InteractiveMarkerControl::ROTATE_3D:
01247   case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D:
01248     if ( event.leftDown() )
01249     {
01250       // aleeper: This line was causing badness
01251       //orientation_mode_ = visualization_msgs::InteractiveMarkerControl::VIEW_FACING;
01252       beginMouseMovement( event, false );
01253     }
01254     else if ( event.left() &&
01255               ((modifiers_at_drag_begin_ ^ event.modifiers) & (Qt::ShiftModifier | Qt::ControlModifier)) )
01256     {
01257       // modifier buttons changed.  Restart the drag.
01258       beginRelativeMouseMotion( event );
01259     }
01260     break;
01261 
01262   default:
01263     break;
01264   }
01265 
01266   if (!parent_->handleMouseEvent(event, name_))
01267   {
01268     if( event.type == QEvent::MouseMove && event.left() && mouse_dragging_)
01269     {
01270       recordDraggingInPlaceEvent( event );
01271       handleMouseMovement( event );
01272     }
01273     else if( event.type == QEvent::Wheel && event.left() && mouse_dragging_)
01274     {
01275       handleMouseWheelMovement( event );
01276     }
01277   }
01278 
01279   if( event.leftDown() )
01280   {
01281     setHighlight( ACTIVE_HIGHLIGHT_VALUE );
01282   }
01283   else if( event.leftUp() )
01284   {
01285     setHighlight( HOVER_HIGHLIGHT_VALUE );
01286     stopDragging();
01287   }
01288 }
01289 
01290 void InteractiveMarkerControl::beginMouseMovement( ViewportMouseEvent& event, bool line_visible )
01291 {
01292   line_->setVisible(line_visible);
01293 
01294   parent_->startDragging();
01295   mouse_dragging_ = true;
01296   drag_viewport_ = event.viewport;
01297 
01298   recordDraggingInPlaceEvent( event );
01299   Ogre::Vector3 grab_point_in_world_frame;
01300   if( ! context_->getSelectionManager()->get3DPoint( event.viewport, event.x, event.y, grab_point_in_world_frame ))
01301   {
01302     // If we couldn't get a 3D point for the grab, just use the
01303     // current relative position of the control frame.
01304     grab_point_in_reference_frame_ = control_frame_node_->getPosition();
01305     parent_to_grab_position_ = Ogre::Vector3(0,0,0);
01306   }
01307   else
01308   {
01309     // If we could get a 3D point for the grab, convert it from
01310     // the world frame to the reference frame (in case those are different).
01311     grab_point_in_reference_frame_ = reference_node_->convertWorldToLocalPosition(grab_point_in_world_frame);
01312     parent_to_grab_position_ = grab_point_in_world_frame - parent_->getPosition();
01313   }
01314   parent_position_at_mouse_down_ = parent_->getPosition();
01315   parent_orientation_at_mouse_down_ = parent_->getOrientation();
01316 
01317   QPoint absolute_mouse = QCursor::pos();
01318   mouse_relative_to_absolute_x_ = absolute_mouse.x() - event.x;
01319   mouse_relative_to_absolute_y_ = absolute_mouse.y() - event.y;
01320   beginRelativeMouseMotion( event );
01321 
01322   if( orientation_mode_ == visualization_msgs::InteractiveMarkerControl::VIEW_FACING &&
01323       drag_viewport_ )
01324   {
01325     updateControlOrientationForViewFacing( drag_viewport_ );
01326   }
01327   control_frame_orientation_at_mouse_down_ = control_frame_node_->getOrientation();
01328   rotation_at_mouse_down_ = rotation_;
01329 
01330   rotation_axis_ = control_frame_node_->getOrientation() * control_orientation_.xAxis();
01331 
01332   // Find rotation_center = 3D point closest to grab_point_ which is
01333   // on the rotation axis, relative to the reference frame.
01334   Ogre::Vector3 rotation_center_rel_ref = closestPointOnLineToPoint( parent_->getPosition(),
01335                                                                      rotation_axis_,
01336                                                                      grab_point_in_reference_frame_ );
01337   Ogre::Matrix4 reference_rel_control_frame;
01338   reference_rel_control_frame.makeInverseTransform( control_frame_node_->getPosition(),
01339                                                     Ogre::Vector3::UNIT_SCALE,
01340                                                     control_frame_node_->getOrientation() );
01341   rotation_center_rel_control_ = reference_rel_control_frame * rotation_center_rel_ref;
01342   grab_point_rel_control_ = reference_rel_control_frame * grab_point_in_reference_frame_;
01343 
01344 
01345   // find mouse_z_scale_
01346   static const double DEFAULT_MOUSE_Z_SCALE = 0.001;  // default to 1mm per pixel
01347   mouse_z_scale_ = DEFAULT_MOUSE_Z_SCALE;
01348 
01349   Ogre::Ray mouse_ray = getMouseRayInReferenceFrame( event, event.x, event.y );
01350   Ogre::Ray mouse_ray_10 = getMouseRayInReferenceFrame( event, event.x, event.y + 10 );
01351 
01352   Ogre::Vector3 intersection_3d;
01353   Ogre::Vector3 intersection_3d_10;
01354   Ogre::Vector2 intersection_2d;
01355   float ray_t;
01356 
01357   if( intersectSomeYzPlane( mouse_ray,
01358                             grab_point_in_reference_frame_,
01359                             control_frame_node_->getOrientation(),
01360                             intersection_3d,
01361                             intersection_2d,
01362                             ray_t ))
01363   {
01364     if( intersectSomeYzPlane( mouse_ray_10,
01365                               grab_point_in_reference_frame_,
01366                               control_frame_node_->getOrientation(),
01367                               intersection_3d_10,
01368                               intersection_2d,
01369                               ray_t ))
01370     {
01371       mouse_z_scale_ = (intersection_3d_10 - intersection_3d).length() / 10.0;
01372       if (mouse_z_scale_ < std::numeric_limits<float>::min() * 100.0)
01373         mouse_z_scale_ = DEFAULT_MOUSE_Z_SCALE;
01374     }
01375   }
01376 }
01377 
01378 void InteractiveMarkerControl::handleMouseMovement( ViewportMouseEvent& event )
01379 {
01380   Ogre::Ray mouse_ray = getMouseRayInReferenceFrame( event, event.x, event.y );
01381   Ogre::Ray last_mouse_ray = getMouseRayInReferenceFrame( event, event.last_x, event.last_y );
01382 
01383   bool do_rotation = false;
01384   switch (interaction_mode_)
01385   {
01386   case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS:
01387     moveAxis( mouse_ray, event );
01388     break;
01389 
01390   case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE:
01391     movePlane( mouse_ray );
01392     break;
01393 
01394   case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE:
01395     moveRotate( mouse_ray );
01396     break;
01397 
01398   case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS:
01399     rotate( mouse_ray );
01400     break;
01401 
01402   case visualization_msgs::InteractiveMarkerControl::ROTATE_3D:
01403     do_rotation = true;
01404     // fall through
01405   case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D:
01406     if ( event.control() )
01407       do_rotation = true;
01408     // fall through
01409   case visualization_msgs::InteractiveMarkerControl::MOVE_3D:
01410     if ( do_rotation )
01411     {
01412       if (event.shift())
01413         rotateZRelative( event );
01414       else
01415         rotateXYRelative( event );
01416     }
01417     else
01418     {
01419       if (event.shift())
01420         moveZAxisRelative( event );
01421       else
01422         moveViewPlane( mouse_ray, event );
01423     }
01424     break;
01425 
01426   default:
01427     break;
01428   }
01429 }
01430 
01431 void InteractiveMarkerControl::handleMouseWheelMovement( ViewportMouseEvent& event )
01432 {
01433   switch (interaction_mode_)
01434   {
01435   case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D:
01436   case visualization_msgs::InteractiveMarkerControl::MOVE_3D:
01437     moveZAxisWheel( event );
01438     break;
01439 
01440   default:
01441     break;
01442   }
01443 }
01444 
01445 bool InteractiveMarkerControl::intersectYzPlane( const Ogre::Ray& mouse_ray,
01446                                                  Ogre::Vector3& intersection_3d,
01447                                                  Ogre::Vector2& intersection_2d,
01448                                                  float &ray_t )
01449 {
01450   return intersectSomeYzPlane( mouse_ray,
01451                                control_frame_node_->getPosition(),
01452                                control_frame_node_->getOrientation(),
01453                                intersection_3d, intersection_2d, ray_t );
01454 }
01455 
01456 bool InteractiveMarkerControl::intersectSomeYzPlane( const Ogre::Ray& mouse_ray,
01457                                                      const Ogre::Vector3& point_on_plane,
01458                                                      const Ogre::Quaternion& plane_orientation,
01459                                                      Ogre::Vector3& intersection_3d,
01460                                                      Ogre::Vector2& intersection_2d,
01461                                                      float& ray_t )
01462 {
01463   Ogre::Vector3 normal = plane_orientation * control_orientation_.xAxis();
01464   Ogre::Vector3 axis_1 = plane_orientation * control_orientation_.yAxis();
01465   Ogre::Vector3 axis_2 = plane_orientation * control_orientation_.zAxis();
01466 
01467   Ogre::Plane plane(normal, point_on_plane);
01468 
01469   Ogre::Vector2 origin_2d(point_on_plane.dotProduct(axis_1), point_on_plane.dotProduct(axis_2));
01470 
01471   std::pair<bool, Ogre::Real> intersection = mouse_ray.intersects(plane);
01472   if (intersection.first)
01473   {
01474     intersection_3d = mouse_ray.getPoint(intersection.second);
01475     intersection_2d = Ogre::Vector2(intersection_3d.dotProduct(axis_1), intersection_3d.dotProduct(axis_2));
01476     intersection_2d -= origin_2d;
01477 
01478     ray_t = intersection.second;
01479     return true;
01480   }
01481 
01482   ray_t = 0;
01483   return false;
01484 }
01485 
01486 void InteractiveMarkerControl::addHighlightPass( S_MaterialPtr materials )
01487 {
01488   S_MaterialPtr::iterator it;
01489 
01490   for (it = materials.begin(); it != materials.end(); it++)
01491   {
01492     Ogre::MaterialPtr material = *it;
01493     Ogre::Pass *original_pass = material->getTechnique(0)->getPass(0);
01494     Ogre::Pass *pass = material->getTechnique(0)->createPass();
01495 
01496     pass->setSceneBlending(Ogre::SBT_ADD);
01497     pass->setDepthWriteEnabled(false);
01498     pass->setDepthCheckEnabled(true);
01499     pass->setLightingEnabled(true);
01500     pass->setAmbient(0, 0, 0);
01501     pass->setDiffuse(0, 0, 0, 0);
01502     pass->setSpecular(0, 0, 0, 0);
01503     pass->setCullingMode(original_pass->getCullingMode());
01504 
01505     highlight_passes_.insert(pass);
01506   }
01507 }
01508 
01509 }


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Thu Aug 27 2015 15:02:27