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  return tile_source_ && tile_source_->IsReady();
62  }
63 
65  {
66  tile_cache_->Clear();
67  }
68 
70  {
71  tile_source_ = tile_source;
72  level_ = -1;
73  }
74 
76  {
77  if (transform.GetOrigin() == transform_.GetOrigin() &&
78  transform.GetOrientation() == transform_.GetOrientation())
79  {
80  return;
81  }
82 
83  transform_ = transform;
84 
85  for (size_t i = 0; i < tiles_.size(); i++)
86  {
87  for (size_t j = 0; j < tiles_[i].points_t.size(); j++)
88  {
89  tiles_[i].points_t[j] = transform_ * tiles_[i].points[j];
90  }
91  }
92 
93  for (size_t i = 0; i < precache_.size(); i++)
94  {
95  for (size_t j = 0; j < precache_[i].points_t.size(); j++)
96  {
97  precache_[i].points_t[j] = transform_ * precache_[i].points[j];
98  }
99  }
100  }
101 
103  double latitude,
104  double longitude,
105  double scale,
106  int32_t width,
107  int32_t height)
108  {
109  latitude = std::max(-90.0, std::min(90.0, latitude));
110  longitude = std::max(-180.0, std::min(180.0, longitude));
111 
112  double lat = swri_math_util::ToRadians(latitude);
113 
114  // Calculate the current zoom level:
115  //
116  // According to http://wiki.openstreetmap.org/wiki/Zoom_levels:
117  // meters_per_pixel = earth_circumference * cos(lat) / 2^(level + 8)
118  //
119  // Therefore,
120  // level = log2(earth_circumference * cos(lat) / meters_per_pixel) - 8
121  //
122  double lat_circumference =
124  int32_t level = std::min(tile_source_->GetMaxZoom(),
125  std::max(tile_source_->GetMinZoom(), static_cast<int32_t>(std::ceil(std::log(lat_circumference) / std::log(2) - 8))));
126  int64_t max_size = std::pow(2, level);
127 
128  int64_t center_x = std::min(max_size - 1, static_cast<int64_t>(
129  std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level))));
130  int64_t center_y = std::min(max_size - 1, static_cast<int64_t>(
131  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))));
132 
133  width_ = width;
134  height_ = height;
135 
136  double max_dimension = std::max(width, height);
137 
138  double meters_per_pixel = swri_transform_util::_earth_equator_circumference * std::cos(lat) / std::pow(2, level + 8);
139  double tile_size = 256.0 * (meters_per_pixel / scale);
140 
141  int64_t size = std::max(static_cast<int64_t>(1L), std::min(max_size, static_cast<int64_t>(
142  std::ceil(0.5 * max_dimension / tile_size) * 2 + 1)));
143 
144  if (size > 50)
145  {
146  ROS_ERROR("Invalid map size: %ld", size);
147  return;
148  }
149 
150  if (size_ != size || level_ != level || center_x_ != center_x || center_y_ != center_y)
151  {
152  size_ = size;
153  level_ = level;
154  center_x_ = center_x;
155  center_y_ = center_y;
156 
157  int64_t top = std::max(static_cast<int64_t>(0L), center_y_ - size_ / 2);
158  int64_t left = std::max(static_cast<int64_t>(0L), center_x_ - size_ / 2);
159 
160  int64_t right = std::min(max_size, left + size_);
161  int64_t bottom = std::min(max_size, top + size_);
162 
163  for (size_t i = 0; i < tiles_.size(); i++)
164  {
165  tile_cache_->AddTexture(tiles_[i].texture);
166  }
167  tiles_.clear();
168 
169  for (int64_t i = top; i < bottom; i++)
170  {
171  for (int64_t j = left; j < right; j++)
172  {
173  Tile tile;
174  InitializeTile(level_, j, i, tile, 10000);
175  tiles_.push_back(tile);
176  }
177  }
178 
179  for (size_t i = 0; i < precache_.size(); i++)
180  {
181  tile_cache_->AddTexture(precache_[i].texture);
182  }
183  precache_.clear();
184 
185  if (level_ > 0)
186  {
187  int64_t precache_x = std::floor(((longitude + 180.0) / 360.0) * std::pow(2.0, level - 1));
188  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));
189 
190  int64_t precache_max_size = std::pow(2, level - 1);
191 
192  int64_t precache_top = std::max(static_cast<int64_t>(0L), precache_y - (size_ - 1) / 2);
193  int64_t precache_left = std::max(static_cast<int64_t>(0L), precache_x - (size_ - 1) / 2);
194 
195  int64_t precache_right = std::min(precache_max_size, precache_left + size_);
196  int64_t precache_bottom = std::min(precache_max_size, precache_top + size_);
197 
198  for (int64_t i = precache_top; i < precache_bottom; i++)
199  {
200  for (int64_t j = precache_left; j < precache_right; j++)
201  {
202  Tile tile;
203  InitializeTile(level_ - 1, j, i, tile, 0);
204  precache_.push_back(tile);
205  }
206  }
207  }
208  }
209  }
210 
211  void TileMapView::DrawTiles(std::vector<Tile>& tiles, int priority)
212  {
213  for (size_t i = 0; i < tiles.size(); i++)
214  {
215  TexturePtr& texture = tiles[i].texture;
216 
217  if (!texture)
218  {
219  bool failed;
220  texture = tile_cache_->GetTexture(tiles[i].url_hash, tiles[i].url, failed, priority);
221  }
222 
223  if (texture)
224  {
225  glBindTexture(GL_TEXTURE_2D, texture->id);
226 
227  glBegin(GL_TRIANGLES);
228 
229  glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
230 
231  for (int32_t row = 0; row < tiles[i].subdiv_count; row++)
232  {
233  for (int32_t col = 0; col < tiles[i].subdiv_count; col++)
234  {
235  double u_0 = col * tiles[i].subwidth;
236  double v_0 = 1.0 - row * tiles[i].subwidth;
237  double u_1 = (col + 1.0) * tiles[i].subwidth;
238  double v_1 = 1.0 - (row + 1.0) * tiles[i].subwidth;
239 
240  const tf::Vector3& tl = tiles[i].points_t[row * (tiles[i].subdiv_count + 1) + col];
241  const tf::Vector3& tr = tiles[i].points_t[row * (tiles[i].subdiv_count + 1) + col + 1];
242  const tf::Vector3& br = tiles[i].points_t[(row + 1) * (tiles[i].subdiv_count + 1) + col + 1];
243  const tf::Vector3& bl = tiles[i].points_t[(row + 1) * (tiles[i].subdiv_count + 1) + col];
244 
245  // Triangle 1
246  glTexCoord2f(u_0, v_0); glVertex2d(tl.x(), tl.y());
247  glTexCoord2f(u_1, v_0); glVertex2d(tr.x(), tr.y());
248  glTexCoord2f(u_1, v_1); glVertex2d(br.x(), br.y());
249 
250  // Triangle 2
251  glTexCoord2f(u_0, v_0); glVertex2d(tl.x(), tl.y());
252  glTexCoord2f(u_1, v_1); glVertex2d(br.x(), br.y());
253  glTexCoord2f(u_0, v_1); glVertex2d(bl.x(), bl.y());
254  }
255  }
256 
257  glEnd();
258 
259  glBindTexture(GL_TEXTURE_2D, 0);
260  }
261  }
262  }
263 
265  {
266  if (!tile_source_)
267  {
268  return;
269  }
270 
271  glEnable(GL_TEXTURE_2D);
272 
273  DrawTiles( precache_, 0 );
274  DrawTiles( tiles_, 10000 );
275 
276  glDisable(GL_TEXTURE_2D);
277  }
278 
279  void TileMapView::ToLatLon(int32_t level, double x, double y, double& latitude, double& longitude)
280  {
281  double n = std::pow(2, level);
282  longitude = x / n * 360.0 - 180.0;
283 
284  double r = swri_math_util::_pi - swri_math_util::_2pi * y / n;
285  latitude = swri_math_util::_rad_2_deg * std::atan(0.5 * (std::exp(r) - std::exp(-r)));
286  }
287 
288  void TileMapView::InitializeTile(int32_t level, int64_t x, int64_t y, Tile& tile, int priority)
289  {
290  tile.url = tile_source_->GenerateTileUrl(level, x, y);
291 
292  tile.url_hash = tile_source_->GenerateTileHash(level, x, y);
293 
294  tile.level = level;
295 
296  bool failed;
297  tile.texture = tile_cache_->GetTexture(tile.url_hash, tile.url, failed, priority);
298 
299  int32_t subdivs = std::max(0, 4 - level);
300  tile.subwidth = 1.0 / (subdivs + 1.0);
301  tile.subdiv_count = std::pow(2, subdivs);
302  for (int32_t row = 0; row <= tile.subdiv_count; row++)
303  {
304  for (int32_t col = 0; col <= tile.subdiv_count; col++)
305  {
306  double t_lat, t_lon;
307  ToLatLon(level, x + col * tile.subwidth, y + row * tile.subwidth, t_lat, t_lon);
308  tile.points.push_back(tf::Vector3(t_lon, t_lat, 0));
309  }
310  }
311 
312  tile.points_t = tile.points;
313  for (size_t i = 0; i < tile.points_t.size(); i++)
314  {
315  tile.points_t[i] = transform_ * tile.points_t[i];
316  }
317  }
318 }
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_
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:88
TFSIMD_FORCE_INLINE const tfScalar & y() const
std::vector< Tile > tiles_
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:86
std::vector< tf::Vector3 > points_t
Definition: tile_map_view.h:58
#define ROS_ERROR(...)


tile_map
Author(s): Marc Alban
autogenerated on Fri Mar 19 2021 02:44:47