tools.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 "interactive_markers/tools.h"
00031 
00032 #include <tf/LinearMath/Quaternion.h>
00033 #include <tf/LinearMath/Matrix3x3.h>
00034 
00035 #include <math.h>
00036 #include <assert.h>
00037 
00038 #include <set>
00039 #include <sstream>
00040 
00041 namespace interactive_markers
00042 {
00043 
00044 void autoComplete( visualization_msgs::InteractiveMarker &msg )
00045 {
00046   // this is a 'delete' message. no need for action.
00047   if ( msg.controls.empty() )
00048   {
00049     return;
00050   }
00051 
00052   // default size
00053   if ( msg.scale == 0 )
00054   {
00055     msg.scale = 1;
00056   }
00057 
00058   // correct empty orientation, normalize
00059   if ( msg.pose.orientation.w == 0 && msg.pose.orientation.x == 0 &&
00060       msg.pose.orientation.y == 0 && msg.pose.orientation.z == 0 )
00061   {
00062     msg.pose.orientation.w = 1;
00063   }
00064 
00065   //normalize quaternion
00066   tf::Quaternion int_marker_orientation( msg.pose.orientation.x, msg.pose.orientation.y,
00067       msg.pose.orientation.z, msg.pose.orientation.w );
00068   int_marker_orientation.normalize();
00069   msg.pose.orientation.x = int_marker_orientation.x();
00070   msg.pose.orientation.y = int_marker_orientation.y();
00071   msg.pose.orientation.z = int_marker_orientation.z();
00072   msg.pose.orientation.w = int_marker_orientation.w();
00073 
00074   // complete the controls
00075   for ( unsigned c=0; c<msg.controls.size(); c++ )
00076   {
00077     autoComplete( msg, msg.controls[c] );
00078   }
00079 
00080   uniqueifyControlNames( msg );
00081 }
00082 
00083 void uniqueifyControlNames( visualization_msgs::InteractiveMarker& msg )
00084 {
00085   int uniqueification_number = 0;
00086   std::set<std::string> names;
00087   for( unsigned c = 0; c < msg.controls.size(); c++ )
00088   {
00089     std::string name = msg.controls[c].name;
00090     while( names.find( name ) != names.end() )
00091     {
00092       std::stringstream ss;
00093       ss << name << "_u" << uniqueification_number++;
00094       name = ss.str();
00095     }
00096     msg.controls[c].name = name;
00097     names.insert( name );
00098   }
00099 }
00100 
00101 void autoComplete( const visualization_msgs::InteractiveMarker &msg,
00102     visualization_msgs::InteractiveMarkerControl &control )
00103 {
00104   // correct empty orientation
00105   if ( control.orientation.w == 0 && control.orientation.x == 0 &&
00106        control.orientation.y == 0 && control.orientation.z == 0 )
00107   {
00108     control.orientation.w = 1;
00109   }
00110 
00111   // add default tool tip if there is none
00112   if ( control.description.empty() )
00113   {
00114     switch ( control.interaction_mode )
00115     {
00116       case visualization_msgs::InteractiveMarkerControl::NONE:
00117         break;
00118 
00119       case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS:
00120         control.description = "Drag to move along the axis.";
00121         break;
00122 
00123       case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE:
00124         control.description = "Drag to move in the plane.";
00125         break;
00126 
00127       case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS:
00128         control.description = "Drag to rotate.";
00129         break;
00130 
00131       case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE:
00132         control.description = "Drag to rotate and move.";
00133         break;
00134 
00135       case visualization_msgs::InteractiveMarkerControl::BUTTON:
00136         control.description = "Click to activate.";
00137         break;
00138 
00139       case visualization_msgs::InteractiveMarkerControl::MENU:
00140         control.description = "Menu";
00141         break;
00142 
00143       default:
00144         break;
00145     }
00146   }
00147 
00148   // add default control handles if there are none
00149   if ( control.markers.empty() )
00150   {
00151     switch ( control.interaction_mode )
00152     {
00153       case visualization_msgs::InteractiveMarkerControl::NONE:
00154         break;
00155 
00156       case visualization_msgs::InteractiveMarkerControl::MOVE_AXIS:
00157         control.markers.reserve(2);
00158         makeArrow( msg, control, 1.0 );
00159         makeArrow( msg, control, -1.0 );
00160         break;
00161 
00162       case visualization_msgs::InteractiveMarkerControl::MOVE_PLANE:
00163       case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS:
00164       case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE:
00165         makeDisc( msg, control );
00166         break;
00167 
00168       case visualization_msgs::InteractiveMarkerControl::BUTTON:
00169         break;
00170 
00171       case visualization_msgs::InteractiveMarkerControl::MENU:
00172         makeViewFacingButton( msg, control, control.description );
00173         break;
00174 
00175       default:
00176         break;
00177     }
00178   }
00179 
00180   // get interactive marker pose for later
00181   tf::Quaternion int_marker_orientation( msg.pose.orientation.x, msg.pose.orientation.y,
00182       msg.pose.orientation.z, msg.pose.orientation.w );
00183   tf::Vector3 int_marker_position( msg.pose.position.x, msg.pose.position.y, msg.pose.position.z );
00184 
00185   // fill in missing pose information into the markers
00186   for ( unsigned m=0; m<control.markers.size(); m++ )
00187   {
00188     visualization_msgs::Marker &marker = control.markers[m];
00189 
00190     if ( marker.scale.x == 0 )
00191     {
00192       marker.scale.x = 1;
00193     }
00194     if ( marker.scale.y == 0 )
00195     {
00196       marker.scale.y = 1;
00197     }
00198     if ( marker.scale.z == 0 )
00199     {
00200       marker.scale.z = 1;
00201     }
00202 
00203     marker.ns = msg.name;
00204 
00205     // correct empty orientation
00206     if ( marker.pose.orientation.w == 0 && marker.pose.orientation.x == 0 &&
00207         marker.pose.orientation.y == 0 && marker.pose.orientation.z == 0 )
00208     {
00209       marker.pose.orientation.w = 1;
00210     }
00211 
00212     //normalize orientation
00213     tf::Quaternion marker_orientation( marker.pose.orientation.x, marker.pose.orientation.y,
00214         marker.pose.orientation.z, marker.pose.orientation.w );
00215     tf::Vector3 marker_position( marker.pose.position.x, marker.pose.position.y, marker.pose.position.z );
00216 
00217     marker_orientation.normalize();
00218 
00219     // if the header is empty, interpret as local coordinates relative to interactive marker pose
00220     if ( marker.header.frame_id.empty() )
00221     {
00222       marker.header = msg.header;
00223 
00224       // interpret marker pose as relative to interactive marker pose
00225       if ( control.orientation_mode == visualization_msgs::InteractiveMarkerControl::INHERIT )
00226       {
00227         marker_orientation = int_marker_orientation * marker_orientation;
00228       }
00229       marker_position = int_marker_position + ( tf::Matrix3x3(int_marker_orientation) * marker_position);
00230     }
00231 
00232     // write back corrected pose
00233     marker.pose.position.x = marker_position.x();
00234     marker.pose.position.y = marker_position.y();
00235     marker.pose.position.z = marker_position.z();
00236 
00237     marker.pose.orientation.x = marker_orientation.x();
00238     marker.pose.orientation.y = marker_orientation.y();
00239     marker.pose.orientation.z = marker_orientation.z();
00240     marker.pose.orientation.w = marker_orientation.w();
00241 
00242     static volatile unsigned id = 0;
00243     marker.id = id++;
00244     marker.ns = msg.name;
00245   }
00246 }
00247 
00248 void makeArrow( const visualization_msgs::InteractiveMarker &msg,
00249     visualization_msgs::InteractiveMarkerControl &control, float pos )
00250 {
00251   visualization_msgs::Marker marker;
00252 
00253   // rely on the auto-completion for the correct orientation
00254   marker.pose.orientation = control.orientation;
00255 
00256   marker.type = visualization_msgs::Marker::ARROW;
00257   marker.scale.x = msg.scale * 0.3;
00258   marker.scale.y = msg.scale * 0.5;
00259   marker.scale.z = msg.scale * 0.2;
00260 
00261   assignDefaultColor(marker, control.orientation);
00262 
00263   float dist = fabs(pos);
00264   float dir = pos > 0 ? 1 : -1;
00265 
00266   float inner = 0.5 * dist;
00267   float outer = inner + 0.4;
00268 
00269   marker.points.resize(2);
00270   marker.points[0].x = dir * msg.scale * inner;
00271   marker.points[1].x = dir * msg.scale * outer;
00272 
00273   control.markers.push_back( marker );
00274 }
00275 
00276 void makeDisc( const visualization_msgs::InteractiveMarker &msg,
00277     visualization_msgs::InteractiveMarkerControl &control, float width )
00278 {
00279   visualization_msgs::Marker marker;
00280 
00281   // rely on the auto-completion for the correct orientation
00282   marker.pose.orientation = control.orientation;
00283 
00284   marker.type = visualization_msgs::Marker::TRIANGLE_LIST;
00285   marker.scale.x = msg.scale;
00286   marker.scale.y = msg.scale;
00287   marker.scale.z = msg.scale;
00288 
00289   assignDefaultColor(marker, control.orientation);
00290 
00291   // compute points on a circle in the y-z plane
00292   int steps = 36;
00293   std::vector<geometry_msgs::Point> circle1, circle2;
00294   circle1.reserve(steps);
00295   circle2.reserve(steps);
00296 
00297   geometry_msgs::Point v1,v2;
00298 
00299   for ( int i=0; i<steps; i++ )
00300   {
00301     float a = float(i)/float(steps) * M_PI * 2.0;
00302 
00303     v1.y = 0.5 * cos(a);
00304     v1.z = 0.5 * sin(a);
00305 
00306     v2.y = (1+width) * v1.y;
00307     v2.z = (1+width) * v1.z;
00308 
00309     circle1.push_back( v1 );
00310     circle2.push_back( v2 );
00311   }
00312 
00313   //construct disc from several segments, as otherwise z sorting won't work nicely
00314   control.markers.reserve( control.markers.size() + steps );
00315 
00316   switch ( control.interaction_mode )
00317   {
00318     case visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS:
00319     {
00320       marker.points.resize(6);
00321       std_msgs::ColorRGBA base_color = marker.color;
00322       for ( int i=0; i<steps; i++ )
00323       {
00324         int i1 = i;
00325         int i2 = (i+1) % steps;
00326         int i3 = (i+2) % steps;
00327 
00328         marker.points[0] = circle1[i1];
00329         marker.points[1] = circle2[i2];
00330         marker.points[2] = circle1[i2];
00331 
00332         marker.points[3] = circle1[i2];
00333         marker.points[4] = circle2[i2];
00334         marker.points[5] = circle2[i3];
00335 
00336         float t = 0.6 + 0.4 * (i%2);
00337         marker.color.r = base_color.r * t;
00338         marker.color.g = base_color.g * t;
00339         marker.color.b = base_color.b * t;
00340         control.markers.push_back(marker);
00341       }
00342       break;
00343     }
00344 
00345     case visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE:
00346     {
00347       marker.points.resize(6);
00348       std_msgs::ColorRGBA base_color = marker.color;
00349       for ( int i=0; i<steps-1; i+=2 )
00350       {
00351         int i1 = i;
00352         int i2 = (i+1) % steps;
00353         int i3 = (i+2) % steps;
00354 
00355         marker.points[0] = circle1[i1];
00356         marker.points[1] = circle2[i2];
00357         marker.points[2] = circle1[i2];
00358 
00359         marker.points[3] = circle1[i2];
00360         marker.points[4] = circle2[i2];
00361         marker.points[5] = circle1[i3];
00362 
00363         marker.color.r = base_color.r * 0.6;
00364         marker.color.g = base_color.g * 0.6;
00365         marker.color.b = base_color.b * 0.6;
00366         control.markers.push_back(marker);
00367 
00368         marker.points[0] = circle2[i1];
00369         marker.points[1] = circle2[i2];
00370         marker.points[2] = circle1[i1];
00371 
00372         marker.points[3] = circle2[i2];
00373         marker.points[4] = circle2[i3];
00374         marker.points[5] = circle1[i3];
00375 
00376         marker.color = base_color;
00377         control.markers.push_back(marker);
00378       }
00379       break;
00380     }
00381 
00382     default:
00383       marker.points.resize(6);
00384 
00385       for ( int i=0; i<steps; i++ )
00386       {
00387         int i1 = i;
00388         int i2 = (i+1) % steps;
00389 
00390         marker.points[0] = circle1[i1];
00391         marker.points[1] = circle2[i1];
00392         marker.points[2] = circle1[i2];
00393 
00394         marker.points[3] = circle2[i1];
00395         marker.points[4] = circle2[i2];
00396         marker.points[5] = circle1[i2];
00397 
00398         control.markers.push_back(marker);
00399       }
00400   }
00401 }
00402 
00403 void makeViewFacingButton( const visualization_msgs::InteractiveMarker &msg,
00404     visualization_msgs::InteractiveMarkerControl &control, std::string text )
00405 {
00406   control.orientation_mode = visualization_msgs::InteractiveMarkerControl::VIEW_FACING;
00407   control.independent_marker_orientation = false;
00408 
00409   visualization_msgs::Marker marker;
00410 
00411   float base_scale = 0.25 * msg.scale;
00412   float base_z = 1.2 * msg.scale;
00413 
00414   marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00415   marker.scale.x = base_scale;
00416   marker.scale.y = base_scale;
00417   marker.scale.z = base_scale;
00418   marker.color.r = 1.0;
00419   marker.color.g = 1.0;
00420   marker.color.b = 1.0;
00421   marker.color.a = 1.0;
00422   marker.pose.position.x = base_scale * -0.1;
00423   marker.pose.position.z = base_z + base_scale * -0.1;
00424   marker.text = text;
00425 
00426   control.markers.push_back( marker );
00427 }
00428 
00429 
00430 void assignDefaultColor(visualization_msgs::Marker &marker, const geometry_msgs::Quaternion &quat )
00431 {
00432   geometry_msgs::Vector3 v;
00433 
00434   tf::Quaternion bt_quat( quat.x, quat.y, quat.z, quat.w );
00435   tf::Vector3 bt_x_axis = tf::Matrix3x3(bt_quat) * tf::Vector3(1,0,0);
00436 
00437   float x,y,z;
00438   x = fabs(bt_x_axis.x());
00439   y = fabs(bt_x_axis.y());
00440   z = fabs(bt_x_axis.z());
00441 
00442   float max_xy = x>y ? x : y;
00443   float max_yz = y>z ? y : z;
00444   float max_xyz = max_xy > max_yz ? max_xy : max_yz;
00445 
00446   marker.color.r = x / max_xyz;
00447   marker.color.g = y / max_xyz;
00448   marker.color.b = z / max_xyz;
00449   marker.color.a = 0.5;
00450 }
00451 
00452 
00453 visualization_msgs::InteractiveMarkerControl makeTitle( visualization_msgs::InteractiveMarker &msg )
00454 {
00455   visualization_msgs::Marker marker;
00456 
00457   marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
00458   marker.scale.x = msg.scale * 0.15;
00459   marker.scale.y = msg.scale * 0.15;
00460   marker.scale.z = msg.scale * 0.15;
00461   marker.color.r = 1.0;
00462   marker.color.g = 1.0;
00463   marker.color.b = 1.0;
00464   marker.color.a = 1.0;
00465   marker.pose.position.z = msg.scale * 1.4;
00466   marker.text = msg.description;
00467 
00468   visualization_msgs::InteractiveMarkerControl control;
00469   control.interaction_mode = visualization_msgs::InteractiveMarkerControl::NONE;
00470   control.orientation_mode = visualization_msgs::InteractiveMarkerControl::VIEW_FACING;
00471   control.always_visible = true;
00472   control.markers.push_back( marker );
00473 
00474   autoComplete( msg, control );
00475 
00476   return control;
00477 }
00478 
00479 }


interactive_markers
Author(s): David Gossow (C++), Michael Ferguson (Python)
autogenerated on Mon Jan 6 2014 11:54:25