00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 #ifndef INVT_HAVE_LIBGLUT
00053
00054 #include "Robots/LoBot/ui/LoLaserWindow.H"
00055 #include "Robots/LoBot/misc/LoExcept.H"
00056
00057 namespace lobot {
00058
00059 void LaserWindow::create(const std::string&)
00060 {
00061 throw missing_libs(MISSING_OPENGL) ;
00062 }
00063
00064
00065
00066
00067
00068
00069 }
00070
00071 #else // OpenGL and GLUT available ==> the real McCoy
00072
00073
00074
00075
00076 #include "Robots/LoBot/ui/LoLaserWindow.H"
00077 #include "Robots/LoBot/config/LoConfigHelpers.H"
00078
00079 #include "Robots/LoBot/misc/LoTypes.H"
00080 #include "Robots/LoBot/misc/factory.hh"
00081 #include "Robots/LoBot/util/LoMath.H"
00082
00083
00084 #include <GL/glut.h>
00085
00086
00087
00088 namespace lobot {
00089
00090
00091
00092
00093 std::string LaserWindow::m_title ;
00094
00095
00096
00097
00098
00099 void LaserWindow::create(const std::string& title)
00100 {
00101 m_title = title ;
00102 instance() ;
00103 }
00104
00105
00106 LaserWindow::LaserWindow()
00107 : m_lrf(new LaserRangeFinder(Params::device(), Params::baud_rate())),
00108 m_window(glutCreateWindow(m_title.c_str())),
00109 m_canvas(new GLCanvas()),
00110 m_markings(factory<LaserWindowMarkings>::create(Params::markings_type())),
00111 m_paused(false),
00112 m_drag_button(-1),
00113 m_drag_modifiers(-1)
00114 {
00115 const int M = m_lrf->get_distance_range().max() ;
00116 m_canvas->set_window(-M, M, -M, M) ;
00117
00118 m_markings->use_canvas(m_canvas) ;
00119 m_markings->set_maximum(M) ;
00120
00121 glutReshapeFunc(reshape_callback) ;
00122 glutDisplayFunc(render_callback) ;
00123 glutKeyboardFunc(keyboard_callback) ;
00124 glutMouseFunc(click_callback) ;
00125 glutMotionFunc(drag_callback) ;
00126 setup_timer() ;
00127
00128 typedef LaserWindow me ;
00129 m_keymap['r'] = & me::reset_zoom_pan ;
00130 m_keymap['p'] = & me::pause ;
00131
00132 m_keymap['q'] = & me::quit ;
00133 m_keymap['Q'] = & me::quit ;
00134 m_keymap[27] = & me::quit ;
00135
00136 m_drag_prev[0] = m_drag_prev[1] = -1 ;
00137 }
00138
00139
00140
00141 void LaserWindow::reshape(int W, int H)
00142 {
00143 m_canvas->set_viewport(0, W, 0, H) ;
00144 }
00145
00146
00147
00148 void LaserWindow::update()
00149 {
00150 m_lrf->update() ;
00151 glutPostRedisplay() ;
00152 if (! m_paused)
00153 setup_timer() ;
00154 }
00155
00156 void LaserWindow::setup_timer()
00157 {
00158 glutTimerFunc(Params::update_frequency(), timer_callback, 0) ;
00159 }
00160
00161
00162
00163
00164 void draw_measurements(const LaserRangeFinder*, const range<int>&, int,
00165 const GLColor&) ;
00166 void draw_lrf(float, const GLColor&) ;
00167
00168
00169
00170 void LaserWindow::render()
00171 {
00172 glClear(GL_COLOR_BUFFER_BIT) ;
00173
00174 glPushMatrix() ;
00175 glRotatef(Params::lrf_direction(), 0, 0, 1) ;
00176 m_markings->render() ;
00177 draw_measurements(m_lrf, Params::angles_range(), Params::angles_step(),
00178 Params::measurements_color()) ;
00179 draw_lrf(Params::lrf_size(), Params::lrf_color()) ;
00180 glPopMatrix() ;
00181
00182 glutSwapBuffers() ;
00183 }
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 void draw_measurements(const LaserRangeFinder* lrf,
00195 const range<int>& angles, int step,
00196 const GLColor& color)
00197 {
00198 glPushAttrib(GL_COLOR_BUFFER_BIT) ;
00199 glBegin(GL_LINES) ;
00200 glColor3fv(color.rgb()) ;
00201
00202 for (float angle = angles.min(); angle <= angles.max(); angle += step)
00203 {
00204 int D = lrf->get_distance(static_cast<int>(angle)) ;
00205 if (D < 0)
00206 continue ;
00207 glVertex2i(0, 0) ;
00208 glVertex2f(D * cos(angle), D * sin(angle)) ;
00209 }
00210
00211
00212
00213 int D = lrf->get_distance(0) ;
00214 if (D > 0) {
00215 glVertex2i(0, 0) ;
00216 glVertex2i(0, D) ;
00217 }
00218 glEnd() ;
00219 glPopAttrib() ;
00220 }
00221
00222
00223
00224
00225
00226
00227
00228 void draw_lrf(float R, const GLColor& color)
00229 {
00230 glPushAttrib(GL_COLOR_BUFFER_BIT) ;
00231 glBegin(GL_TRIANGLES) ;
00232 glColor3fv(color.rgb()) ;
00233
00234
00235 glVertex2f(R, 0) ;
00236 glVertex2f(0, R) ;
00237 glVertex2f(0, -R) ;
00238
00239
00240 glVertex2f( 0, R) ;
00241 glVertex2f(-R, R) ;
00242 glVertex2f( 0, -R) ;
00243 glVertex2f(-R, R) ;
00244 glVertex2f(-R, -R) ;
00245 glVertex2f( 0, -R) ;
00246 glEnd() ;
00247 glPopAttrib() ;
00248 }
00249
00250
00251
00252
00253 void LaserWindow::handle_key(unsigned char key)
00254 {
00255 KeyMap::iterator handler = m_keymap.find(key) ;
00256 if (handler == m_keymap.end())
00257 return ;
00258 (this->*(handler->second))() ;
00259 glutPostRedisplay() ;
00260 }
00261
00262 void LaserWindow::reset_zoom_pan()
00263 {
00264 m_canvas->reset_zoom_pan() ;
00265 }
00266
00267 void LaserWindow::pause()
00268 {
00269 m_paused = ! m_paused ;
00270 if (! m_paused)
00271 setup_timer() ;
00272 }
00273
00274 void LaserWindow::quit()
00275 {
00276 exit(0) ;
00277 }
00278
00279
00280
00281 void LaserWindow::left_click(int state, int modifiers, int x, int y)
00282 {
00283 switch (state)
00284 {
00285 case GLUT_DOWN:
00286 m_drag_button = GLUT_LEFT_BUTTON ;
00287 m_drag_modifiers = modifiers ;
00288 m_drag_prev[0] = x ;
00289 m_drag_prev[1] = y ;
00290 break ;
00291 case GLUT_UP:
00292 m_drag_button = -1 ;
00293 m_drag_modifiers = -1 ;
00294 m_drag_prev[0] = -1 ;
00295 m_drag_prev[1] = -1 ;
00296 break ;
00297 }
00298 }
00299
00300 void LaserWindow::middle_click(int state, int modifiers, int x, int y)
00301 {
00302 switch (state)
00303 {
00304 case GLUT_DOWN:
00305 m_drag_button = GLUT_MIDDLE_BUTTON ;
00306 m_drag_modifiers = modifiers ;
00307 m_drag_prev[0] = x ;
00308 m_drag_prev[1] = y ;
00309 break ;
00310 case GLUT_UP:
00311 m_drag_button = -1 ;
00312 m_drag_modifiers = -1 ;
00313 m_drag_prev[0] = -1 ;
00314 m_drag_prev[1] = -1 ;
00315 break ;
00316 }
00317 }
00318
00319 void LaserWindow::right_click(int state, int modifiers, int x, int y)
00320 {
00321 switch (state)
00322 {
00323 case GLUT_DOWN:
00324 m_drag_button = GLUT_RIGHT_BUTTON ;
00325 m_drag_modifiers = modifiers ;
00326 m_drag_prev[0] = x ;
00327 m_drag_prev[1] = y ;
00328 break ;
00329 case GLUT_UP:
00330 m_drag_button = -1 ;
00331 m_drag_modifiers = -1 ;
00332 m_drag_prev[0] = -1 ;
00333 m_drag_prev[1] = -1 ;
00334 break ;
00335 }
00336 }
00337
00338 void LaserWindow::left_drag(int x, int y)
00339 {
00340 if (m_drag_modifiers & GLUT_ACTIVE_SHIFT)
00341 {
00342 const float dy = y - m_drag_prev[1] ;
00343 m_canvas->zoom_by(-dy * Params::zoom_drag_factor()) ;
00344 }
00345 else
00346 {
00347 double curr_x, curr_y ;
00348 m_canvas->screen_to_world(x, y, & curr_x, & curr_y) ;
00349
00350 double prev_x, prev_y ;
00351 m_canvas->screen_to_world(m_drag_prev[0], m_drag_prev[1],
00352 & prev_x, & prev_y) ;
00353
00354 const float dx = static_cast<float>(curr_x - prev_x) ;
00355 const float dy = static_cast<float>(curr_y - prev_y) ;
00356 m_canvas->pan(-dx, -dy) ;
00357 }
00358
00359 m_drag_prev[0] = x ;
00360 m_drag_prev[1] = y ;
00361
00362 glutPostRedisplay() ;
00363 }
00364
00365 void LaserWindow::middle_drag(int x, int y)
00366 {
00367 const float dy = y - m_drag_prev[1] ;
00368 m_canvas->zoom_by(-dy * Params::zoom_drag_factor()) ;
00369
00370 m_drag_prev[0] = x ;
00371 m_drag_prev[1] = y ;
00372
00373 glutPostRedisplay() ;
00374 }
00375
00376 void LaserWindow::right_drag(int, int)
00377 {
00378 }
00379
00380
00381
00382 void LaserWindow::reshape_callback(int width, int height)
00383 {
00384 instance().reshape(width, height) ;
00385 }
00386
00387 void LaserWindow::render_callback()
00388 {
00389 instance().render() ;
00390 }
00391
00392 void LaserWindow::keyboard_callback(unsigned char key, int, int)
00393 {
00394 instance().handle_key(key) ;
00395 }
00396
00397 void LaserWindow::click_callback(int button, int state, int x, int y)
00398 {
00399 switch (button)
00400 {
00401 case GLUT_LEFT_BUTTON:
00402 instance().left_click(state, glutGetModifiers(), x, y) ;
00403 break ;
00404 case GLUT_MIDDLE_BUTTON:
00405 instance().middle_click(state, glutGetModifiers(), x, y) ;
00406 break ;
00407 case GLUT_RIGHT_BUTTON:
00408 instance().right_click(state, glutGetModifiers(), x, y) ;
00409 break ;
00410 }
00411 }
00412
00413 void LaserWindow::drag_callback(int x, int y)
00414 {
00415 switch (instance().m_drag_button)
00416 {
00417 case GLUT_LEFT_BUTTON:
00418 instance().left_drag(x, y) ;
00419 break ;
00420 case GLUT_MIDDLE_BUTTON:
00421 instance().middle_drag(x, y) ;
00422 break ;
00423 case GLUT_RIGHT_BUTTON:
00424 instance().right_drag(x, y) ;
00425 break ;
00426 }
00427 }
00428
00429
00430 void LaserWindow::timer_callback(int)
00431 {
00432 instance().update() ;
00433 }
00434
00435
00436
00437 LaserWindow::~LaserWindow()
00438 {
00439 delete m_markings ;
00440 delete m_canvas ;
00441 glutDestroyWindow(m_window) ;
00442 delete m_lrf ;
00443 }
00444
00445
00446
00447
00448 LaserWindow::Params::Params()
00449 : m_device(get_conf<std::string>("device", "port", "/dev/ttyACM0")),
00450 m_baud_rate(get_conf("device", "baud_rate", 115200)),
00451 m_markings_type(get_conf<std::string>("markings", "type", "rings")),
00452 m_update_frequency(clamp(get_conf("device", "update_frequency", 250),
00453 100, 60000)),
00454 m_angles_range(get_conf<int>("measurements", "angles_range",
00455 make_range(-135, 135))),
00456 m_angles_step(clamp(get_conf("measurements", "angles_step", 5), 1, 30)),
00457 m_measurements_color(get_conf<int>("measurements", "color",
00458 make_triple(0, 128, 128))),
00459 m_lrf_size(clamp(get_conf("device", "lrf_size", 100.0f), 10.0f, 250.0f)),
00460 m_lrf_direction(clamp_angle(get_conf("device", "lrf_direction", 90.0f))),
00461 m_lrf_color(get_conf<int>("device", "lrf_color",
00462 make_triple(242, 13, 26))),
00463 m_zoom_drag_factor(clamp(get_conf("zoom_pan", "zoom_drag_factor", 0.1f),
00464 0.1f, 2.5f))
00465 {}
00466
00467
00468 LaserWindow::Params::~Params(){}
00469
00470
00471 const std::string& LaserWindow::Params::device()
00472 {
00473 return instance().m_device ;
00474 }
00475
00476 int LaserWindow::Params::baud_rate()
00477 {
00478 return instance().m_baud_rate ;
00479 }
00480
00481 const std::string& LaserWindow::Params::markings_type()
00482 {
00483 return instance().m_markings_type ;
00484 }
00485
00486 int LaserWindow::Params::update_frequency()
00487 {
00488 return instance().m_update_frequency ;
00489 }
00490
00491 const range<int>& LaserWindow::Params::angles_range()
00492 {
00493 return instance().m_angles_range ;
00494 }
00495
00496 int LaserWindow::Params::angles_step()
00497 {
00498 return instance().m_angles_step ;
00499 }
00500
00501 const GLColor& LaserWindow::Params::measurements_color()
00502 {
00503 return instance().m_measurements_color ;
00504 }
00505
00506 float LaserWindow::Params::lrf_size()
00507 {
00508 return instance().m_lrf_size ;
00509 }
00510
00511 float LaserWindow::Params::lrf_direction()
00512 {
00513 return instance().m_lrf_direction ;
00514 }
00515
00516 const GLColor& LaserWindow::Params::lrf_color()
00517 {
00518 return instance().m_lrf_color ;
00519 }
00520
00521 float LaserWindow::Params::zoom_drag_factor()
00522 {
00523 return instance().m_zoom_drag_factor ;
00524 }
00525
00526
00527
00528 }
00529
00530 #endif // #ifndef INVT_HAVE_LIBGLUT
00531
00532
00533
00534
00535