tile_map_view.cpp
Go to the documentation of this file.
00001 // *****************************************************************************
00002 //
00003 // Copyright (c) 2015, Southwest Research Institute® (SwRI®)
00004 // All rights reserved.
00005 //
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
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 Southwest Research Institute® (SwRI®) nor the
00014 //       names of its contributors may be used to endorse or promote products
00015 //       derived from 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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00021 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00022 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00023 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00024 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00026 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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     // Calculate the current zoom level:
00108     // 
00109     // According to http://wiki.openstreetmap.org/wiki/Zoom_levels:
00110     //   meters_per_pixel = earth_circumference * cos(lat) / 2^(level + 8)
00111     //
00112     // Therefore,
00113     //   level = log2(earth_circumference * cos(lat) / meters_per_pixel) - 8
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             // Triangle 1
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             // Triangle 2
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             // Triangle 1
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             // Triangle 2
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 }


tile_map
Author(s): Marc Alban
autogenerated on Thu Aug 24 2017 02:46:24