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 #include <tile_map/tile_map_view.h>
00031
00032 #include <cmath>
00033
00034 #include <boost/make_shared.hpp>
00035
00036 #include <GL/gl.h>
00037
00038 #include <ros/ros.h>
00039
00040 #include <swri_math_util/constants.h>
00041 #include <swri_math_util/trig_util.h>
00042 #include <swri_transform_util/earth_constants.h>
00043
00044 #include <tile_map/image_cache.h>
00045
00046 namespace tile_map
00047 {
00048 TileMapView::TileMapView() :
00049 level_(-1),
00050 width_(100),
00051 height_(100)
00052 {
00053 ImageCachePtr image_cache = boost::make_shared<ImageCache>("/tmp/tile_map");
00054 tile_cache_ = boost::make_shared<TextureCache>(image_cache);
00055 }
00056
00057 void TileMapView::ResetCache()
00058 {
00059 tile_cache_->Clear();
00060 }
00061
00062 void TileMapView::SetTileSource(const boost::shared_ptr<TileSource>& tile_source)
00063 {
00064 tile_source_ = tile_source;
00065 level_ = -1;
00066 }
00067
00068 void TileMapView::SetTransform(const swri_transform_util::Transform& transform)
00069 {
00070 if (transform.GetOrigin() == transform_.GetOrigin() &&
00071 transform.GetOrientation() == transform_.GetOrientation())
00072 {
00073 return;
00074 }
00075
00076 transform_ = transform;
00077
00078 for (size_t i = 0; i < tiles_.size(); i++)
00079 {
00080 for (size_t j = 0; j < tiles_[i].points_t.size(); j++)
00081 {
00082 tiles_[i].points_t[j] = transform_ * tiles_[i].points[j];
00083 }
00084 }
00085
00086 for (size_t i = 0; i < precache_.size(); i++)
00087 {
00088 for (size_t j = 0; j < precache_[i].points_t.size(); j++)
00089 {
00090 precache_[i].points_t[j] = transform_ * precache_[i].points[j];
00091 }
00092 }
00093 }
00094
00095 void TileMapView::SetView(
00096 double latitude,
00097 double longitude,
00098 double scale,
00099 int32_t width,
00100 int32_t height)
00101 {
00102 latitude = std::max(-90.0, std::min(90.0, latitude));
00103 longitude = std::max(-180.0, std::min(180.0, longitude));
00104
00105 double lat = swri_math_util::ToRadians(latitude);
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 double lat_circumference =
00116 swri_transform_util::_earth_equator_circumference * std::cos(lat) / scale;
00117 int32_t level = std::min(tile_source_->GetMaxZoom(),
00118 std::max(tile_source_->GetMinZoom(), static_cast<int32_t>(std::ceil(std::log(lat_circumference) / std::log(2) - 8))));
00119 int64_t max_size = std::pow(2, level);
00120
00121 int64_t center_x = std::min(max_size - 1, static_cast<int64_t>(
00122 std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level))));
00123 int64_t center_y = std::min(max_size - 1, static_cast<int64_t>(
00124 std::floor((1.0 - std::log(std::tan(lat) + 1.0 / std::cos(lat)) / swri_math_util::_pi) / 2.0 * std::pow(2.0, level))));
00125
00126 width_ = width;
00127 height_ = height;
00128
00129 double max_dimension = std::max(width, height);
00130
00131 double meters_per_pixel = swri_transform_util::_earth_equator_circumference * std::cos(lat) / std::pow(2, level + 8);
00132 double tile_size = 256.0 * (meters_per_pixel / scale);
00133
00134 int64_t size = std::max(static_cast<int64_t>(1L), std::min(max_size, static_cast<int64_t>(
00135 std::ceil(0.5 * max_dimension / tile_size) * 2 + 1)));
00136
00137 if (size > 50)
00138 {
00139 ROS_ERROR("Invalid map size: %ld", size);
00140 return;
00141 }
00142
00143 if (size_ != size || level_ != level || center_x_ != center_x || center_y_ != center_y)
00144 {
00145 size_ = size;
00146 level_ = level;
00147 center_x_ = center_x;
00148 center_y_ = center_y;
00149
00150 int64_t top = std::max(static_cast<int64_t>(0L), center_y_ - size_ / 2);
00151 int64_t left = std::max(static_cast<int64_t>(0L), center_x_ - size_ / 2);
00152
00153 int64_t right = std::min(max_size, left + size_);
00154 int64_t bottom = std::min(max_size, top + size_);
00155
00156 for (size_t i = 0; i < tiles_.size(); i++)
00157 {
00158 tile_cache_->AddTexture(tiles_[i].texture);
00159 }
00160 tiles_.clear();
00161
00162 for (int64_t i = top; i < bottom; i++)
00163 {
00164 for (int64_t j = left; j < right; j++)
00165 {
00166 Tile tile;
00167 InitializeTile(level_, j, i, tile);
00168 tiles_.push_back(tile);
00169 }
00170 }
00171
00172 for (size_t i = 0; i < precache_.size(); i++)
00173 {
00174 tile_cache_->AddTexture(precache_[i].texture);
00175 }
00176 precache_.clear();
00177
00178 if (level_ > 0)
00179 {
00180 int64_t precache_x = std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level - 1));
00181 int64_t precache_y = std::floor((1.0 - std::log(std::tan(lat) + 1.0 / std::cos(lat)) / swri_math_util::_pi) / 2.0 * std::pow(2.0, level - 1));
00182
00183 int64_t precache_max_size = std::pow(2, level - 1);
00184
00185 int64_t precache_top = std::max(static_cast<int64_t>(0L), precache_y - (size_ - 1) / 2);
00186 int64_t precache_left = std::max(static_cast<int64_t>(0L), precache_x - (size_ - 1) / 2);
00187
00188 int64_t precache_right = std::min(precache_max_size, precache_left + size_);
00189 int64_t precache_bottom = std::min(precache_max_size, precache_top + size_);
00190
00191 for (int64_t i = precache_top; i < precache_bottom; i++)
00192 {
00193 for (int64_t j = precache_left; j < precache_right; j++)
00194 {
00195 Tile tile;
00196 InitializeTile(level_ - 1, j, i, tile);
00197 precache_.push_back(tile);
00198 }
00199 }
00200 }
00201 }
00202 }
00203
00204 void TileMapView::Draw()
00205 {
00206 if (!tile_source_)
00207 {
00208 return;
00209 }
00210
00211 glEnable(GL_TEXTURE_2D);
00212
00213 for (size_t i = 0; i < precache_.size(); i++)
00214 {
00215 TexturePtr texture = precache_[i].texture;
00216
00217 if (!texture)
00218 {
00219 bool failed;
00220 texture = tile_cache_->GetTexture(precache_[i].url_hash, precache_[i].url, failed);
00221 if (failed)
00222 {
00223 tile_source_->SetMaxZoom(std::min(tile_source_->GetMaxZoom(), precache_[i].level - 1));
00224 ROS_WARN("===== SETTING MAX LEVEL TO %d =====", tile_source_->GetMaxZoom());
00225 }
00226 }
00227
00228 if (texture)
00229 {
00230 glBindTexture(GL_TEXTURE_2D, texture->id);
00231
00232 glBegin(GL_TRIANGLES);
00233
00234 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
00235
00236 for (int32_t row = 0; row < precache_[i].subdiv_count; row++)
00237 {
00238 for (int32_t col = 0; col < precache_[i].subdiv_count; col++)
00239 {
00240 double u_0 = col * precache_[i].subwidth;
00241 double v_0 = 1.0 - row * precache_[i].subwidth;
00242 double u_1 = (col + 1.0) * precache_[i].subwidth;
00243 double v_1 = 1.0 - (row + 1.0) * precache_[i].subwidth;
00244
00245 const tf::Vector3& tl = precache_[i].points_t[row * (precache_[i].subdiv_count + 1) + col];
00246 const tf::Vector3& tr = precache_[i].points_t[row * (precache_[i].subdiv_count + 1) + col + 1];
00247 const tf::Vector3& br = precache_[i].points_t[(row + 1) * (precache_[i].subdiv_count + 1) + col + 1];
00248 const tf::Vector3& bl = precache_[i].points_t[(row + 1) * (precache_[i].subdiv_count + 1) + col];
00249
00250
00251 glTexCoord2f(u_0, v_0); glVertex2d(tl.x(), tl.y());
00252 glTexCoord2f(u_1, v_0); glVertex2d(tr.x(), tr.y());
00253 glTexCoord2f(u_1, v_1); glVertex2d(br.x(), br.y());
00254
00255
00256 glTexCoord2f(u_0, v_0); glVertex2d(tl.x(), tl.y());
00257 glTexCoord2f(u_1, v_1); glVertex2d(br.x(), br.y());
00258 glTexCoord2f(u_0, v_1); glVertex2d(bl.x(), bl.y());
00259 }
00260 }
00261
00262 glEnd();
00263
00264 glBindTexture(GL_TEXTURE_2D, 0);
00265 }
00266 }
00267
00268 for (size_t i = 0; i < tiles_.size(); i++)
00269 {
00270 TexturePtr texture = tiles_[i].texture;
00271
00272 if (!texture)
00273 {
00274 bool failed;
00275 texture = tile_cache_->GetTexture(tiles_[i].url_hash, tiles_[i].url, failed);
00276 if (failed)
00277 {
00278 tile_source_->SetMaxZoom(std::min(tile_source_->GetMaxZoom(), tiles_[i].level - 1));
00279 ROS_WARN("===== SETTING MAX LEVEL TO %d =====", tile_source_->GetMaxZoom());
00280 }
00281 }
00282
00283 if (texture)
00284 {
00285 glBindTexture(GL_TEXTURE_2D, texture->id);
00286
00287 glBegin(GL_TRIANGLES);
00288
00289 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
00290
00291 for (int32_t row = 0; row < tiles_[i].subdiv_count; row++)
00292 {
00293 for (int32_t col = 0; col < tiles_[i].subdiv_count; col++)
00294 {
00295 double u_0 = col * tiles_[i].subwidth;
00296 double v_0 = 1.0 - row * tiles_[i].subwidth;
00297 double u_1 = (col + 1.0) * tiles_[i].subwidth;
00298 double v_1 = 1.0 - (row + 1.0) * tiles_[i].subwidth;
00299
00300 const tf::Vector3& tl = tiles_[i].points_t[row * (tiles_[i].subdiv_count + 1) + col];
00301 const tf::Vector3& tr = tiles_[i].points_t[row * (tiles_[i].subdiv_count + 1) + col + 1];
00302 const tf::Vector3& br = tiles_[i].points_t[(row + 1) * (tiles_[i].subdiv_count + 1) + col + 1];
00303 const tf::Vector3& bl = tiles_[i].points_t[(row + 1) * (tiles_[i].subdiv_count + 1) + col];
00304
00305
00306 glTexCoord2f(u_0, v_0); glVertex2d(tl.x(), tl.y());
00307 glTexCoord2f(u_1, v_0); glVertex2d(tr.x(), tr.y());
00308 glTexCoord2f(u_1, v_1); glVertex2d(br.x(), br.y());
00309
00310
00311 glTexCoord2f(u_0, v_0); glVertex2d(tl.x(), tl.y());
00312 glTexCoord2f(u_1, v_1); glVertex2d(br.x(), br.y());
00313 glTexCoord2f(u_0, v_1); glVertex2d(bl.x(), bl.y());
00314 }
00315 }
00316
00317 glEnd();
00318
00319 glBindTexture(GL_TEXTURE_2D, 0);
00320 }
00321 }
00322
00323 glDisable(GL_TEXTURE_2D);
00324 }
00325
00326 void TileMapView::ToLatLon(int32_t level, double x, double y, double& latitude, double& longitude)
00327 {
00328 double n = std::pow(2, level);
00329 longitude = x / n * 360.0 - 180.0;
00330
00331 double r = swri_math_util::_pi - swri_math_util::_2pi * y / n;
00332 latitude = swri_math_util::_rad_2_deg * std::atan(0.5 * (std::exp(r) - std::exp(-r)));
00333 }
00334
00335 void TileMapView::InitializeTile(int32_t level, int64_t x, int64_t y, Tile& tile)
00336 {
00337 tile.url = tile_source_->GenerateTileUrl(level, x, y);
00338
00339 tile.url_hash = tile_source_->GenerateTileHash(level, x, y);
00340
00341 tile.level = level;
00342
00343 bool failed;
00344 tile.texture = tile_cache_->GetTexture(tile.url_hash, tile.url, failed);
00345 if (failed)
00346 {
00347 tile_source_->SetMaxZoom(std::min(tile_source_->GetMaxZoom(), level - 1));
00348 ROS_WARN("===== SETTING MAX LEVEL TO %d =====", tile_source_->GetMaxZoom());
00349 }
00350
00351 int32_t subdivs = std::max(0, 4 - level);
00352 tile.subwidth = 1.0 / (subdivs + 1.0);
00353 tile.subdiv_count = std::pow(2, subdivs);
00354 for (int32_t row = 0; row <= tile.subdiv_count; row++)
00355 {
00356 for (int32_t col = 0; col <= tile.subdiv_count; col++)
00357 {
00358 double t_lat, t_lon;
00359 ToLatLon(level, x + col * tile.subwidth, y + row * tile.subwidth, t_lat, t_lon);
00360 tile.points.push_back(tf::Vector3(t_lon, t_lat, 0));
00361 }
00362 }
00363
00364 tile.points_t = tile.points;
00365 for (size_t i = 0; i < tile.points_t.size(); i++)
00366 {
00367 tile.points_t[i] = transform_ * tile.points_t[i];
00368 }
00369 }
00370 }