tile_map_view.cpp
Go to the documentation of this file.
1 // *****************************************************************************
2 //
3 // Copyright (c) 2015, Southwest Research Institute® (SwRI®)
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Southwest Research Institute® (SwRI®) nor the
14 // names of its contributors may be used to endorse or promote products
15 // derived from this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28 // *****************************************************************************
29 
30 #include <tile_map/tile_map_view.h>
31 
32 #include <cmath>
33 
34 #include <boost/make_shared.hpp>
35 
36 #include <GL/glew.h>
37 #include <GL/gl.h>
38 #include <GL/glu.h>
39 
40 #include <ros/ros.h>
41 
45 
46 #include <tile_map/image_cache.h>
47 
48 namespace tile_map
49 {
51  level_(-1),
52  width_(100),
53  height_(100)
54  {
55  ImageCachePtr image_cache = boost::make_shared<ImageCache>("/tmp/tile_map");
56  tile_cache_ = boost::make_shared<TextureCache>(image_cache);
57  }
58 
60  {
61  tile_cache_->Clear();
62  }
63 
65  {
66  tile_source_ = tile_source;
67  level_ = -1;
68  }
69 
71  {
72  if (transform.GetOrigin() == transform_.GetOrigin() &&
73  transform.GetOrientation() == transform_.GetOrientation())
74  {
75  return;
76  }
77 
78  transform_ = transform;
79 
80  for (size_t i = 0; i < tiles_.size(); i++)
81  {
82  for (size_t j = 0; j < tiles_[i].points_t.size(); j++)
83  {
84  tiles_[i].points_t[j] = transform_ * tiles_[i].points[j];
85  }
86  }
87 
88  for (size_t i = 0; i < precache_.size(); i++)
89  {
90  for (size_t j = 0; j < precache_[i].points_t.size(); j++)
91  {
92  precache_[i].points_t[j] = transform_ * precache_[i].points[j];
93  }
94  }
95  }
96 
98  double latitude,
99  double longitude,
100  double scale,
101  int32_t width,
102  int32_t height)
103  {
104  latitude = std::max(-90.0, std::min(90.0, latitude));
105  longitude = std::max(-180.0, std::min(180.0, longitude));
106 
107  double lat = swri_math_util::ToRadians(latitude);
108 
109  // Calculate the current zoom level:
110  //
111  // According to http://wiki.openstreetmap.org/wiki/Zoom_levels:
112  // meters_per_pixel = earth_circumference * cos(lat) / 2^(level + 8)
113  //
114  // Therefore,
115  // level = log2(earth_circumference * cos(lat) / meters_per_pixel) - 8
116  //
117  double lat_circumference =
119  int32_t level = std::min(tile_source_->GetMaxZoom(),
120  std::max(tile_source_->GetMinZoom(), static_cast<int32_t>(std::ceil(std::log(lat_circumference) / std::log(2) - 8))));
121  int64_t max_size = std::pow(2, level);
122 
123  int64_t center_x = std::min(max_size - 1, static_cast<int64_t>(
124  std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level))));
125  int64_t center_y = std::min(max_size - 1, static_cast<int64_t>(
126  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))));
127 
128  width_ = width;
129  height_ = height;
130 
131  double max_dimension = std::max(width, height);
132 
133  double meters_per_pixel = swri_transform_util::_earth_equator_circumference * std::cos(lat) / std::pow(2, level + 8);
134  double tile_size = 256.0 * (meters_per_pixel / scale);
135 
136  int64_t size = std::max(static_cast<int64_t>(1L), std::min(max_size, static_cast<int64_t>(
137  std::ceil(0.5 * max_dimension / tile_size) * 2 + 1)));
138 
139  if (size > 50)
140  {
141  ROS_ERROR("Invalid map size: %ld", size);
142  return;
143  }
144 
145  if (size_ != size || level_ != level || center_x_ != center_x || center_y_ != center_y)
146  {
147  size_ = size;
148  level_ = level;
149  center_x_ = center_x;
150  center_y_ = center_y;
151 
152  int64_t top = std::max(static_cast<int64_t>(0L), center_y_ - size_ / 2);
153  int64_t left = std::max(static_cast<int64_t>(0L), center_x_ - size_ / 2);
154 
155  int64_t right = std::min(max_size, left + size_);
156  int64_t bottom = std::min(max_size, top + size_);
157 
158  for (size_t i = 0; i < tiles_.size(); i++)
159  {
160  tile_cache_->AddTexture(tiles_[i].texture);
161  }
162  tiles_.clear();
163 
164  for (int64_t i = top; i < bottom; i++)
165  {
166  for (int64_t j = left; j < right; j++)
167  {
168  Tile tile;
169  InitializeTile(level_, j, i, tile, 10000);
170  tiles_.push_back(tile);
171  }
172  }
173 
174  for (size_t i = 0; i < precache_.size(); i++)
175  {
176  tile_cache_->AddTexture(precache_[i].texture);
177  }
178  precache_.clear();
179 
180  if (level_ > 0)
181  {
182  int64_t precache_x = std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level - 1));
183  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));
184 
185  int64_t precache_max_size = std::pow(2, level - 1);
186 
187  int64_t precache_top = std::max(static_cast<int64_t>(0L), precache_y - (size_ - 1) / 2);
188  int64_t precache_left = std::max(static_cast<int64_t>(0L), precache_x - (size_ - 1) / 2);
189 
190  int64_t precache_right = std::min(precache_max_size, precache_left + size_);
191  int64_t precache_bottom = std::min(precache_max_size, precache_top + size_);
192 
193  for (int64_t i = precache_top; i < precache_bottom; i++)
194  {
195  for (int64_t j = precache_left; j < precache_right; j++)
196  {
197  Tile tile;
198  InitializeTile(level_ - 1, j, i, tile, 0);
199  precache_.push_back(tile);
200  }
201  }
202  }
203  }
204  }
205 
206  void TileMapView::DrawTiles(std::vector<Tile>& tiles, int priority)
207  {
208  for (size_t i = 0; i < tiles.size(); i++)
209  {
210  TexturePtr& texture = tiles[i].texture;
211 
212  if (!texture)
213  {
214  bool failed;
215  texture = tile_cache_->GetTexture(tiles[i].url_hash, tiles[i].url, failed, priority);
216  }
217 
218  if (texture)
219  {
220  glBindTexture(GL_TEXTURE_2D, texture->id);
221 
222  glBegin(GL_TRIANGLES);
223 
224  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
225 
226  for (int32_t row = 0; row < tiles[i].subdiv_count; row++)
227  {
228  for (int32_t col = 0; col < tiles[i].subdiv_count; col++)
229  {
230  double u_0 = col * tiles[i].subwidth;
231  double v_0 = 1.0 - row * tiles[i].subwidth;
232  double u_1 = (col + 1.0) * tiles[i].subwidth;
233  double v_1 = 1.0 - (row + 1.0) * tiles[i].subwidth;
234 
235  const tf::Vector3& tl = tiles[i].points_t[row * (tiles[i].subdiv_count + 1) + col];
236  const tf::Vector3& tr = tiles[i].points_t[row * (tiles[i].subdiv_count + 1) + col + 1];
237  const tf::Vector3& br = tiles[i].points_t[(row + 1) * (tiles[i].subdiv_count + 1) + col + 1];
238  const tf::Vector3& bl = tiles[i].points_t[(row + 1) * (tiles[i].subdiv_count + 1) + col];
239 
240  // Triangle 1
241  glTexCoord2f(u_0, v_0); glVertex2d(tl.x(), tl.y());
242  glTexCoord2f(u_1, v_0); glVertex2d(tr.x(), tr.y());
243  glTexCoord2f(u_1, v_1); glVertex2d(br.x(), br.y());
244 
245  // Triangle 2
246  glTexCoord2f(u_0, v_0); glVertex2d(tl.x(), tl.y());
247  glTexCoord2f(u_1, v_1); glVertex2d(br.x(), br.y());
248  glTexCoord2f(u_0, v_1); glVertex2d(bl.x(), bl.y());
249  }
250  }
251 
252  glEnd();
253 
254  glBindTexture(GL_TEXTURE_2D, 0);
255  }
256  }
257  }
258 
260  {
261  if (!tile_source_)
262  {
263  return;
264  }
265 
266  glEnable(GL_TEXTURE_2D);
267 
268  DrawTiles( precache_, 0 );
269  DrawTiles( tiles_, 10000 );
270 
271  glDisable(GL_TEXTURE_2D);
272  }
273 
274  void TileMapView::ToLatLon(int32_t level, double x, double y, double& latitude, double& longitude)
275  {
276  double n = std::pow(2, level);
277  longitude = x / n * 360.0 - 180.0;
278 
279  double r = swri_math_util::_pi - swri_math_util::_2pi * y / n;
280  latitude = swri_math_util::_rad_2_deg * std::atan(0.5 * (std::exp(r) - std::exp(-r)));
281  }
282 
283  void TileMapView::InitializeTile(int32_t level, int64_t x, int64_t y, Tile& tile, int priority)
284  {
285  tile.url = tile_source_->GenerateTileUrl(level, x, y);
286 
287  tile.url_hash = tile_source_->GenerateTileHash(level, x, y);
288 
289  tile.level = level;
290 
291  bool failed;
292  tile.texture = tile_cache_->GetTexture(tile.url_hash, tile.url, failed, priority);
293 
294  int32_t subdivs = std::max(0, 4 - level);
295  tile.subwidth = 1.0 / (subdivs + 1.0);
296  tile.subdiv_count = std::pow(2, subdivs);
297  for (int32_t row = 0; row <= tile.subdiv_count; row++)
298  {
299  for (int32_t col = 0; col <= tile.subdiv_count; col++)
300  {
301  double t_lat, t_lon;
302  ToLatLon(level, x + col * tile.subwidth, y + row * tile.subwidth, t_lat, t_lon);
303  tile.points.push_back(tf::Vector3(t_lon, t_lat, 0));
304  }
305  }
306 
307  tile.points_t = tile.points;
308  for (size_t i = 0; i < tile.points_t.size(); i++)
309  {
310  tile.points_t[i] = transform_ * tile.points_t[i];
311  }
312  }
313 }
void SetTileSource(const boost::shared_ptr< TileSource > &tile_source)
int32_t subdiv_count
Definition: tile_map_view.h:52
static const long double _rad_2_deg
std::vector< Tile > precache_
Definition: tile_map_view.h:99
static const double _earth_equator_circumference
void ToLatLon(int32_t level, double x, double y, double &latitude, double &longitude)
f
TexturePtr texture
Definition: tile_map_view.h:55
tf::Quaternion GetOrientation() const
void InitializeTile(int32_t level, int64_t x, int64_t y, Tile &tile, int priority)
tf::Vector3 GetOrigin() const
TFSIMD_FORCE_INLINE const tfScalar & x() const
static const long double _2pi
swri_transform_util::Transform transform_
Definition: tile_map_view.h:86
TFSIMD_FORCE_INLINE const tfScalar & y() const
std::vector< Tile > tiles_
Definition: tile_map_view.h:98
void SetView(double latitude, double longitude, double scale, int32_t width, int32_t height)
void DrawTiles(std::vector< Tile > &tiles, int priority)
static const long double _pi
double ToRadians(double degrees)
TextureCachePtr tile_cache_
void SetTransform(const swri_transform_util::Transform &transform)
std::vector< tf::Vector3 > points
Definition: tile_map_view.h:57
boost::shared_ptr< TileSource > tile_source_
Definition: tile_map_view.h:84
std::vector< tf::Vector3 > points_t
Definition: tile_map_view.h:58
#define ROS_ERROR(...)


tile_map
Author(s): Marc Alban
autogenerated on Thu Jun 6 2019 19:25:35