00001 /** 00002 \file Robots/LoBot/ui/LoLaserViz.C 00003 00004 This file defines the non-inline member functions of the 00005 lobot::LaserViz class used for visualizing the laser range finder 00006 measurements. 00007 */ 00008 00009 // //////////////////////////////////////////////////////////////////// // 00010 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00011 // by the University of Southern California (USC) and the iLab at USC. // 00012 // See http://iLab.usc.edu for information about this project. // 00013 // //////////////////////////////////////////////////////////////////// // 00014 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00015 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00016 // in Visual Environments, and Applications'' by Christof Koch and // 00017 // Laurent Itti, California Institute of Technology, 2001 (patent // 00018 // pending; application number 09/912,225 filed July 23, 2001; see // 00019 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00020 // //////////////////////////////////////////////////////////////////// // 00021 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00024 // redistribute it and/or modify it under the terms of the GNU General // 00025 // Public License as published by the Free Software Foundation; either // 00026 // version 2 of the License, or (at your option) any later version. // 00027 // // 00028 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00029 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00030 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00031 // PURPOSE. See the GNU General Public License for more details. // 00032 // // 00033 // You should have received a copy of the GNU General Public License // 00034 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00035 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00036 // Boston, MA 02111-1307 USA. // 00037 // //////////////////////////////////////////////////////////////////// // 00038 // 00039 // Primary maintainer for this file: mviswana usc edu 00040 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/ui/LoLaserViz.C $ 00041 // $Id: LoLaserViz.C 13674 2010-07-18 22:13:22Z mviswana $ 00042 // 00043 00044 //------------------------------ HEADERS -------------------------------- 00045 00046 // lobot headers 00047 #include "Robots/LoBot/ui/LoLaserViz.H" 00048 00049 #include "Robots/LoBot/config/LoConfigHelpers.H" 00050 00051 #include "Robots/LoBot/misc/LoExcept.H" 00052 #include "Robots/LoBot/misc/LoTypes.H" 00053 #include "Robots/LoBot/misc/factory.hh" 00054 #include "Robots/LoBot/util/LoMath.H" 00055 00056 // OpenGL headers 00057 #ifdef INVT_HAVE_LIBGL 00058 #include <GL/gl.h> 00059 #endif 00060 00061 //----------------------------- NAMESPACE ------------------------------- 00062 00063 namespace lobot { 00064 00065 //-------------------------- INITIALIZATION ----------------------------- 00066 00067 LaserViz::LaserViz(const LaserRangeFinder* lrf) 00068 : Drawable("laser_viz", Params::geometry()), 00069 m_lrf(lrf), 00070 m_canvas(new GLCanvas()), 00071 m_markings(factory<LaserWindowMarkings>::create(Params::markings_type())) 00072 { 00073 if (! lrf) 00074 throw misc_error(LASER_RANGE_FINDER_MISSING) ; 00075 00076 m_markings->use_canvas(m_canvas.get()) ; 00077 m_markings->set_maximum(m_lrf->get_distance_range().max()) ; 00078 } 00079 00080 void LaserViz::gl_init() 00081 { 00082 const int M = m_lrf->get_distance_range().max() ; 00083 m_canvas->set_window(-M, M, -M, M) ; 00084 } 00085 00086 //----------------------------- RENDERING ------------------------------- 00087 00088 #ifdef INVT_HAVE_LIBGL 00089 00090 // This function draws the measurements made by the laser range finder, 00091 // showing them as rays emanating from the origin of the world coordinate 00092 // system (where the laser range finder is positioned; yes, the laser 00093 // range finder is the center of the world). 00094 // 00095 // Since drawing each and every measurement can make the resulting 00096 // picture crowded, this function only draws the distance measurements 00097 // corresponding to angles within the [min, max] range with the specified 00098 // step size. 00099 static void draw_rays(const LaserRangeFinder* lrf, 00100 const range<int>& angles, int step, const GLColor& color) 00101 { 00102 glPushAttrib(GL_COLOR_BUFFER_BIT) ; 00103 glBegin(GL_LINES) ; 00104 glColor3fv(color.rgb()) ; 00105 00106 for (float angle = angles.min(); angle <= angles.max(); angle += step) 00107 { 00108 int D = lrf->get_distance(static_cast<int>(angle)) ; 00109 if (D < 0) // didn't get a valid reading in this direction 00110 continue ; 00111 glVertex2i(0, 0) ; 00112 glVertex2f(D * cos(angle), D * sin(angle)) ; 00113 } 00114 00115 // In case the above loop missed zero degrees, i.e., straight in 00116 // front of the laser range finder... 00117 int D = lrf->get_distance(0) ; 00118 if (D > 0) { 00119 glVertex2i(0, 0) ; 00120 glVertex2i(0, D) ; 00121 } 00122 glEnd() ; 00123 glPopAttrib() ; 00124 } 00125 00126 // This function draws the measurements made by the laser range finder, 00127 // showing them as an outline hull. 00128 // 00129 // Since drawing each and every measurement can make the resulting 00130 // picture crowded, this function only draws the distance measurements 00131 // corresponding to angles within the [min, max] range with the specified 00132 // step size. 00133 static void draw_hull(const LaserRangeFinder* lrf, 00134 const range<int>& angles, int step, const GLColor& color) 00135 { 00136 glPushAttrib(GL_COLOR_BUFFER_BIT) ; 00137 glBegin(GL_LINE_LOOP) ; 00138 glColor3fv(color.rgb()) ; 00139 00140 glVertex2i(0, 0) ; 00141 for (float angle = angles.min(); angle <= angles.max(); angle += step) 00142 { 00143 int D = lrf->get_distance(static_cast<int>(angle)) ; 00144 if (D < 0) // didn't get a valid reading in this direction 00145 continue ; 00146 glVertex2f(D * cos(angle), D * sin(angle)) ; 00147 } 00148 glEnd() ; 00149 glPopAttrib() ; 00150 } 00151 00152 // The laser range finder is depicted as a rectangle with a triangle on 00153 // it serving to let users know where the front of the device is. This 00154 // function expects to be passed the half-size R of a square inside of 00155 // which the entire rectangle + triangle combo is to inscribed. The 00156 // rectangle is drawn with sides R and 2R; the triangle is drawn with 00157 // height R and base length 2R. 00158 static void draw_lrf(float R, const GLColor& color) 00159 { 00160 glPushAttrib(GL_COLOR_BUFFER_BIT) ; 00161 glBegin(GL_TRIANGLES) ; 00162 glColor3fv(color.rgb()) ; 00163 00164 // The triangle 00165 glVertex2f(R, 0) ; // apex 00166 glVertex2f(0, R) ; // base 00167 glVertex2f(0, -R) ; 00168 00169 // The rectangle (drawn as two triangles) 00170 glVertex2f( 0, R) ; 00171 glVertex2f(-R, R) ; 00172 glVertex2f( 0, -R) ; 00173 glVertex2f(-R, R) ; 00174 glVertex2f(-R, -R) ; 00175 glVertex2f( 0, -R) ; 00176 glEnd() ; 00177 glPopAttrib() ; 00178 } 00179 00180 // This method draws the latest set of distance measurements from the 00181 // laser range finder. 00182 void LaserViz::render_me() 00183 { 00184 glPushMatrix() ; 00185 glRotatef(Params::lrf_direction(), 0, 0, 1) ; 00186 m_markings->render() ; 00187 if (Params::draw_rays()) 00188 draw_rays(m_lrf, Params::angles_range(), Params::angles_step(), 00189 Params::measurements_color()) ; 00190 else 00191 draw_hull(m_lrf, Params::angles_range(), Params::angles_step(), 00192 Params::measurements_color()) ; 00193 draw_lrf(Params::lrf_size(), Params::lrf_color()) ; 00194 glPopMatrix() ; 00195 } 00196 00197 #endif // INVT_HAVE_LIBGL 00198 00199 //----------------------------- ZOOM/PAN -------------------------------- 00200 00201 void LaserViz::zoom_by(float dz) 00202 { 00203 m_canvas->zoom_by(dz) ; 00204 } 00205 00206 void LaserViz::pan(int cx, int cy, int px, int py) 00207 { 00208 double curr_x, curr_y ; 00209 m_canvas->screen_to_world(cx, cy, &curr_x, &curr_y) ; 00210 00211 double prev_x, prev_y ; 00212 m_canvas->screen_to_world(px, py, &prev_x, &prev_y) ; 00213 00214 const float dx = static_cast<float>(curr_x - prev_x) ; 00215 const float dy = static_cast<float>(curr_y - prev_y) ; 00216 m_canvas->pan(-dx, -dy) ; 00217 } 00218 00219 void LaserViz::reset_zoom_pan() 00220 { 00221 m_canvas->reset_zoom_pan() ; 00222 } 00223 00224 //----------------------------- CLEAN-UP -------------------------------- 00225 00226 void LaserViz::gl_cleanup() 00227 { 00228 // Force auto_ptr to delete the markings object now rather than in 00229 // destructor to ensure that any GL resources held by it are cleaned 00230 // up here. Otherwise, depending on the order in which the thread 00231 // scheduler shuts down different threads, the GL rendering context 00232 // could disappear before we get around to properly cleaning up... 00233 m_markings.reset(0) ; 00234 00235 // Ditto for the GL canvas 00236 m_canvas.reset(0) ; 00237 } 00238 00239 LaserViz::~LaserViz(){} 00240 00241 //-------------------------- KNOB TWIDDLING ----------------------------- 00242 00243 // Retrieve settings from laser_viz section of config file 00244 template<typename T> 00245 static inline T viz_conf(const std::string& key, const T& default_value) 00246 { 00247 return get_conf<T>("laser_viz", key, default_value) ; 00248 } 00249 00250 // Overload of above function for retrieving ranges 00251 template<typename T> 00252 static inline range<T> 00253 viz_conf(const std::string& key, const range<T>& default_value) 00254 { 00255 return get_conf<T>("laser_viz", key, default_value) ; 00256 } 00257 00258 // Overload for retrieving triples 00259 template<typename T> 00260 static inline triple<T, T, T> 00261 viz_conf(const std::string& key, const triple<T, T, T>& default_value) 00262 { 00263 return get_conf<T>("laser_viz", key, default_value) ; 00264 } 00265 00266 // Retrieve settings from markings section of config file 00267 template<typename T> 00268 static inline T markings_conf(const std::string& key, const T& default_value) 00269 { 00270 return get_conf<T>("markings", key, default_value) ; 00271 } 00272 00273 // Parameters initialization 00274 LaserViz::Params::Params() 00275 : m_geometry(viz_conf<std::string>("geometry", "0 0 480 480")), 00276 m_measurements_style(downstring( 00277 viz_conf<std::string>("measurements_style", "rays"))), 00278 m_markings_type(downstring(markings_conf<std::string>("type", "rings"))), 00279 m_angles_range(viz_conf<int>("angles_range", make_range(-119, 135))), 00280 m_angles_step(clamp(viz_conf("angles_step", 5), 1, 30)), 00281 m_measurements_color(viz_conf<int>("measurements_color", 00282 make_triple(0, 128, 128))), 00283 m_lrf_size(clamp(viz_conf("lrf_size", 100.0f), 10.0f, 250.0f)), 00284 m_lrf_direction(clamp_angle(viz_conf("lrf_direction", 90.0f))), 00285 m_lrf_color(viz_conf<int>("lrf_color", make_triple(242, 13, 26))) 00286 {} 00287 00288 // Parameters clean-up 00289 LaserViz::Params::~Params(){} 00290 00291 //----------------------------------------------------------------------- 00292 00293 } // end of namespace encapsulating this file's definitions 00294 00295 /* So things look consistent in everyone's emacs... */ 00296 /* Local Variables: */ 00297 /* indent-tabs-mode: nil */ 00298 /* End: */