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 #include "Robots/LoBot/slam/LoMap.H"
00046 #include "Robots/LoBot/slam/LoOccGrid.H"
00047 #include "Robots/LoBot/slam/LoCoords.H"
00048 #include "Robots/LoBot/slam/LoSlamParams.H"
00049
00050 #include "Robots/LoBot/config/LoConfigHelpers.H"
00051 #include "Robots/LoBot/util/LoGL.H"
00052 #include "Robots/LoBot/util/LoMath.H"
00053 #include "Robots/LoBot/misc/LoTypes.H"
00054 #include "Robots/LoBot/misc/singleton.hh"
00055 #include "Robots/LoBot/util/triple.hh"
00056
00057
00058 #ifdef INVT_HAVE_LIBGLU
00059 #include <GL/glu.h>
00060 #endif
00061
00062 #ifdef INVT_HAVE_LIBGL
00063 #include <GL/gl.h>
00064 #endif
00065
00066
00067 #include <boost/bind.hpp>
00068
00069
00070 #include <string>
00071 #include <algorithm>
00072 #include <functional>
00073 #include <iterator>
00074
00075
00076
00077 namespace lobot {
00078
00079
00080
00081 namespace {
00082
00083
00084 template<typename T>
00085 inline T conf(const std::string& key, T default_value)
00086 {
00087 return get_conf<T>("map", key, default_value) ;
00088 }
00089
00090
00091 template<typename T>
00092 inline triple<T, T, T>
00093 conf(const std::string& key, const triple<T, T, T>& default_value)
00094 {
00095 return get_conf<T>("map", key, default_value) ;
00096 }
00097
00098
00099
00100 class MapParams : public singleton<MapParams> {
00101
00102
00103
00104
00105 bool m_draw_pose ;
00106
00107
00108
00109
00110 bool m_draw_labels ;
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121 float m_grid_spacing ;
00122
00123
00124
00125
00126
00127
00128
00129 float m_grid_color ;
00130
00131
00132
00133
00134
00135
00136
00137 bool m_draw_border ;
00138
00139
00140
00141
00142
00143 GLColor m_border_color ;
00144 typedef const GLColor& Color ;
00145
00146
00147 MapParams() ;
00148 friend class singleton<MapParams> ;
00149
00150 public:
00151
00152
00153 static bool draw_pose() {return instance().m_draw_pose ;}
00154 static bool draw_labels() {return instance().m_draw_labels ;}
00155 static bool draw_border() {return instance().m_draw_border ;}
00156 static Color border_color() {return instance().m_border_color ;}
00157 static float grid_spacing() {return instance().m_grid_spacing ;}
00158 static float grid_color() {return instance().m_grid_color ;}
00159 static bool draw_grid() {return instance().m_grid_spacing > 0 ;}
00160
00161 } ;
00162
00163
00164 MapParams::MapParams()
00165 : m_draw_pose(conf("draw_pose", true)),
00166 m_draw_labels(conf("draw_labels", true)),
00167 m_grid_spacing(conf("grid_spacing", -1.0f)),
00168 m_grid_color(clamp(conf("grid_color", 0.75f), 0.25f, 0.95f)),
00169 m_draw_border(conf("draw_border", true)),
00170 m_border_color(conf<int>("border_color", make_triple(255, 255, 0)))
00171 {
00172 if (m_grid_spacing > 0)
00173 m_grid_spacing = clamp(m_grid_spacing, 1.0f, 1000.0f) ;
00174 }
00175
00176 }
00177
00178
00179
00180 Map::Map()
00181 : Drawable("occupancy_grid", SlamParams::map_geometry()),
00182 m_pose(SlamParams::initial_pose())
00183 {
00184 const int N = SlamParams::map_width() * SlamParams::map_height() ;
00185 m_grid.reserve(N) ;
00186 std::fill_n(std::back_inserter(m_grid), N, 128) ;
00187
00188 Drawable::m_border = MapParams::draw_border() ;
00189 Drawable::m_border_color = MapParams::border_color() ;
00190 }
00191
00192 void Map::add_pose_hook(const Map::PoseHook& H)
00193 {
00194 AutoMutex M(m_pose_hooks_mutex) ;
00195 m_pose_hooks.push_back(H) ;
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 static unsigned char log_odds_to_byte(float log_odds)
00212 {
00213 return round(255 * (1 - log_odds_to_prob(log_odds))) ;
00214 }
00215
00216
00217
00218 void Map::update(const OccGrid& g)
00219 {
00220 AutoMutex M(m_grid_mutex) ;
00221 std::transform(g.begin(), g.end(), m_grid.begin(), log_odds_to_byte) ;
00222 }
00223
00224
00225 static void trigger_pose_hook(const Map::PoseHook& H, const Pose& p)
00226 {
00227 H.first(p, H.second) ;
00228 }
00229
00230
00231 void Map::update(const Pose& p)
00232 {
00233
00234
00235
00236
00237
00238
00239 {
00240 AutoWriteLock L(m_pose_lock) ;
00241 m_pose = p ;
00242 }
00243
00244
00245
00246
00247
00248
00249 AutoMutex M(m_pose_hooks_mutex) ;
00250 std::for_each(m_pose_hooks.begin(), m_pose_hooks.end(),
00251 boost::bind(trigger_pose_hook, _1, p)) ;
00252 }
00253
00254
00255
00256 Pose Map::current_pose() const
00257 {
00258 AutoReadLock L(m_pose_lock) ;
00259 return m_pose ;
00260 }
00261
00262
00263 std::vector<unsigned char> Map::submap(int w) const
00264 {
00265 std::vector<unsigned char> M ;
00266 M.reserve(sqr(w * 2 + 1)) ;
00267
00268 int X, Y ;
00269 Pose p = current_pose() ;
00270 Coords::to_grid(p.x(), p.y(), &X, &Y) ;
00271
00272 const int W = SlamParams::map_width() ;
00273 const int H = SlamParams::map_height() ;
00274
00275 AutoMutex mutex(m_grid_mutex) ;
00276 int k = (Y - w) * W + (X - w) ;
00277 for (int y = Y - w; y <= Y + w; ++y, k += W - 2*w - 1)
00278 for (int x = X - w; x <= X + w; ++x, ++k)
00279 {
00280 if (x < 0 || x >= W || y < 0 || y >= H)
00281 M.push_back(0) ;
00282 else
00283 M.push_back(m_grid[k]) ;
00284 }
00285
00286 return M ;
00287 }
00288
00289
00290
00291 #ifdef INVT_HAVE_LIBGLU
00292
00293 namespace {
00294
00295
00296
00297 class MapTexture {
00298 unsigned int m_name ;
00299 int m_width, m_height ;
00300 public:
00301 MapTexture() ;
00302 void init(int width, int height) ;
00303 int width() const {return m_width ;}
00304 int height() const {return m_height ;}
00305 void update(const std::vector<unsigned char>&) ;
00306 void render(float left, float right, float bottom, float top) const ;
00307 void cleanup() ;
00308 } ;
00309
00310 MapTexture::MapTexture()
00311 : m_name(0), m_width(0), m_height(0)
00312 {}
00313
00314 void MapTexture::init(int width, int height)
00315 {
00316 m_width = width ;
00317 m_height = height ;
00318
00319 glGenTextures(1, &m_name) ;
00320
00321 glBindTexture(GL_TEXTURE_2D, m_name) ;
00322 glPixelStorei(GL_UNPACK_ALIGNMENT, 1) ;
00323 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP) ;
00324 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP) ;
00325 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) ;
00326 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) ;
00327
00328 const int W = next_power_of_two(m_width) ;
00329 const int H = next_power_of_two(m_height) ;
00330 const int N = W * H ;
00331 GLubyte* texture = new GLubyte[N] ;
00332 std::fill_n(texture, N, GLubyte(0)) ;
00333 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, W, H, 0,
00334 GL_LUMINANCE, GL_UNSIGNED_BYTE, texture) ;
00335 delete[] texture ;
00336 }
00337
00338
00339 void MapTexture::update(const std::vector<unsigned char>& grid)
00340 {
00341 typedef std::vector<unsigned char> Texture ;
00342 std::vector<unsigned char> texture(grid.size()) ;
00343
00344
00345
00346
00347 Texture::iterator dst = texture.end() - m_width ;
00348 Texture::const_iterator src = grid.begin() ;
00349 for (; src != grid.end(); src += m_width, dst -= m_width)
00350 std::copy(src, src + m_width, dst) ;
00351
00352 glBindTexture(GL_TEXTURE_2D, m_name) ;
00353 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height,
00354 GL_LUMINANCE, GL_UNSIGNED_BYTE, &texture[0]) ;
00355 }
00356
00357
00358 void MapTexture::render(float left, float right, float bottom, float top) const
00359 {
00360 glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT) ;
00361 glEnable(GL_TEXTURE_2D) ;
00362 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE) ;
00363 glBindTexture(GL_TEXTURE_2D, m_name) ;
00364
00365 const float S = static_cast<float>(m_width)/next_power_of_two(m_width) ;
00366 const float T = static_cast<float>(m_height)/next_power_of_two(m_height) ;
00367 glBegin(GL_QUADS) ;
00368 glTexCoord2i(0, 0) ;
00369 glVertex2f(left, bottom) ;
00370
00371 glTexCoord2f(S, 0) ;
00372 glVertex2f(right, bottom) ;
00373
00374 glTexCoord2f(S, T) ;
00375 glVertex2f(right, top) ;
00376
00377 glTexCoord2f(0, T) ;
00378 glVertex2f(left, top) ;
00379 glEnd() ;
00380
00381 glDisable(GL_TEXTURE_2D) ;
00382 glPopAttrib() ;
00383 }
00384
00385
00386 void MapTexture::cleanup()
00387 {
00388 glDeleteTextures(1, &m_name) ;
00389 }
00390
00391
00392 void draw_grid(float L, float R, float B, float T)
00393 {
00394 glMatrixMode(GL_PROJECTION) ;
00395 glLoadIdentity() ;
00396 gluOrtho2D(T, B, L, R) ;
00397
00398 glMatrixMode(GL_MODELVIEW) ;
00399 glLoadIdentity() ;
00400
00401 const float C = MapParams::grid_color() ;
00402 const float S = MapParams::grid_spacing() ;
00403
00404 glPushAttrib(GL_CURRENT_BIT) ;
00405 glColor3f(C, C, C) ;
00406 glBegin(GL_LINES) ;
00407 for (float x = T - S; x > B; x -= S) {
00408 glVertex2f(x, L) ;
00409 glVertex2f(x, R) ;
00410 }
00411 for (float y = L + S; y < R; y += S) {
00412 glVertex2f(T, y) ;
00413 glVertex2f(B, y) ;
00414 }
00415 glEnd() ;
00416 glPopAttrib() ;
00417 }
00418
00419
00420 void draw_pose(const Pose& P, const Drawable::Geometry& G, const float ext[])
00421 {
00422 float x = (P.y() - ext[3])/(ext[2] - ext[3]) * (G.width - 1) ;
00423 float y = (P.x() - ext[0])/(ext[1] - ext[0]) * (G.height - 1) ;
00424
00425 glMatrixMode(GL_PROJECTION) ;
00426 glLoadIdentity() ;
00427 gluOrtho2D(0, G.width - 1, 0, G.height - 1) ;
00428
00429 glMatrixMode(GL_MODELVIEW) ;
00430 glLoadIdentity() ;
00431 glTranslatef(x, y, 0) ;
00432 glRotatef(90 + P.heading(), 0, 0, 1) ;
00433
00434 glPushAttrib(GL_CURRENT_BIT) ;
00435 glColor3f(1, 0, 0) ;
00436 glBegin(GL_TRIANGLES) ;
00437 glVertex2i(-10, 0) ;
00438 glVertex2i( 0, 0) ;
00439 glVertex2f(-17.5f, 5.0f) ;
00440
00441 glVertex2i( 0, 0) ;
00442 glVertex2i(-10, 0) ;
00443 glVertex2f(-17.5f, -5.0f) ;
00444 glEnd() ;
00445 glPopAttrib() ;
00446 }
00447
00448
00449 static std::string pose_label(const Pose& P)
00450 {
00451 std::ostringstream str ;
00452 str << "Pose: ("
00453 << round(P.x()) << ", "
00454 << round(P.y()) << ", "
00455 << round((P.t() < 180) ? P.t() : P.t() - 360) << ')' ;
00456 return str.str() ;
00457 }
00458
00459
00460 MapTexture map_texture ;
00461
00462 }
00463
00464 void Map::gl_init()
00465 {
00466 map_texture.init(SlamParams::map_width(), SlamParams::map_height()) ;
00467 }
00468
00469
00470
00471 void Map::render_me()
00472 {
00473
00474 setup_view_volume(0, 1, 0, 1) ;
00475 glRotatef(90, 0, 0, 1) ;
00476 glTranslatef(0, -1, 0) ;
00477 m_grid_mutex.acquire() ;
00478 std::vector<unsigned char> grid = m_grid ;
00479 m_grid_mutex.release() ;
00480 map_texture.update(grid) ;
00481 map_texture.render(0, 1, 0, 1) ;
00482
00483
00484 float ext[4] ;
00485 SlamParams::map_extents(ext) ;
00486 if (MapParams::draw_grid())
00487 draw_grid(ext[0], ext[1], ext[2], ext[3]) ;
00488
00489
00490 Pose P = current_pose() ;
00491 if (MapParams::draw_pose())
00492 draw_pose(P, m_geometry, ext) ;
00493
00494
00495 if (MapParams::draw_labels()) {
00496 restore_view_volume() ;
00497 text_view_volume() ;
00498 glColor3f(1, 0, 0) ;
00499 draw_label(3, 12, "Map") ;
00500 if (MapParams::draw_pose())
00501 draw_label(3, 24, pose_label(P).c_str()) ;
00502 }
00503 restore_view_volume() ;
00504 }
00505
00506 void Map::gl_cleanup()
00507 {
00508 map_texture.cleanup() ;
00509 }
00510
00511 #endif
00512
00513
00514
00515 }
00516
00517
00518
00519
00520