A simple map viewer

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. use context::Context;
  2. use coord::{MapCoord, ScreenCoord};
  3. use globe_tile_layer::GlobeTileLayer;
  4. use map_view::MapView;
  5. use marker_layer::MarkerLayer;
  6. use session::Session;
  7. use texture::{Texture, TextureFormat};
  8. use tile_atlas::TileAtlas;
  9. use tile_cache::TileCache;
  10. use tile_layer::TileLayer;
  11. use tile_source::TileSource;
  12. const MIN_ZOOM_LEVEL: f64 = 0.0;
  13. const MAX_ZOOM_LEVEL: f64 = 22.0;
  14. #[derive(Debug)]
  15. pub struct MapViewGl {
  16. map_view: MapView,
  17. viewport_size: (u32, u32),
  18. tile_cache: TileCache,
  19. tile_atlas: TileAtlas,
  20. tile_layer: TileLayer,
  21. marker_layer: MarkerLayer,
  22. globe_tile_layer: GlobeTileLayer,
  23. projection: Projection,
  24. last_draw_type: DrawType,
  25. }
  26. #[derive(Debug, Eq, PartialEq)]
  27. enum Projection {
  28. // EPSG:3857: WGS 84 / Pseudo-Mercator
  29. Mercator,
  30. // Orthographic projection, WGS 84 coordinates mapped to the sphere
  31. Orthografic,
  32. }
  33. #[derive(Debug, Eq, PartialEq)]
  34. enum DrawType {
  35. Null,
  36. Tiles,
  37. Markers,
  38. Globe,
  39. }
  40. impl MapViewGl {
  41. pub fn new<F>(
  42. cx: &mut Context,
  43. initial_size: (u32, u32),
  44. update_func: F,
  45. use_network: bool,
  46. use_async: bool,
  47. ) -> MapViewGl
  48. where F: Fn() + Sync + Send + 'static,
  49. {
  50. let tile_size = 256;
  51. let mut map_view = MapView::with_filling_zoom(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
  52. if map_view.zoom < MIN_ZOOM_LEVEL {
  53. map_view.zoom = MIN_ZOOM_LEVEL;
  54. }
  55. let atlas_size = {
  56. let default_size = 2048;
  57. let max_size = cx.max_texture_size() as u32;
  58. if default_size <= max_size {
  59. default_size
  60. } else {
  61. if tile_size * 3 > max_size {
  62. error!("maximal tile size ({}) is too small", max_size);
  63. }
  64. max_size
  65. }
  66. };
  67. let atlas_tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
  68. check_gl_errors!(cx);
  69. let mut tile_atlas = TileAtlas::new(cx, atlas_tex, tile_size, use_async);
  70. //TODO remove this
  71. tile_atlas.double_texture_size(cx);
  72. tile_atlas.double_texture_size(cx);
  73. tile_atlas.double_texture_size(cx);
  74. let tile_layer = TileLayer::new(cx, &tile_atlas);
  75. MapViewGl {
  76. map_view,
  77. viewport_size: initial_size,
  78. tile_cache: TileCache::new(move |_tile| update_func(), use_network),
  79. tile_atlas,
  80. tile_layer,
  81. marker_layer: MarkerLayer::new(cx),
  82. globe_tile_layer: GlobeTileLayer::new(cx),
  83. projection: Projection::Mercator,
  84. last_draw_type: DrawType::Null,
  85. }
  86. }
  87. pub fn set_viewport_size(&mut self, cx: &mut Context, width: u32, height: u32) {
  88. self.viewport_size = (width, height);
  89. self.map_view.set_size(f64::from(width), f64::from(height));
  90. cx.set_viewport(0, 0, width, height);
  91. }
  92. pub fn add_marker(&mut self, map_coord: MapCoord) {
  93. self.marker_layer.add_marker(map_coord);
  94. }
  95. pub fn map_covers_viewport(&self) -> bool {
  96. match self.projection {
  97. Projection::Mercator => self.map_view.map_covers_viewport(),
  98. //TODO uncomment
  99. //Projection::Orthografic => self.map_view.globe_covers_viewport(),
  100. Projection::Orthografic => false,
  101. }
  102. }
  103. pub fn increase_atlas_size(&mut self, cx: &mut Context) -> Result<(), ()> {
  104. self.tile_atlas.double_texture_size(cx)
  105. }
  106. pub fn toggle_projection(&mut self) {
  107. self.projection = match self.projection {
  108. Projection::Mercator => Projection::Orthografic,
  109. Projection::Orthografic => Projection::Mercator,
  110. };
  111. }
  112. fn draw_flat_tiles(&mut self, cx: &mut Context, source: &TileSource, snap_to_pixel: bool)
  113. -> Result<usize, usize>
  114. {
  115. if self.last_draw_type != DrawType::Tiles {
  116. self.last_draw_type = DrawType::Tiles;
  117. self.tile_layer.prepare_draw(cx, &self.tile_atlas);
  118. }
  119. //TODO remove viewport_size parameter
  120. self.tile_layer.draw(
  121. cx,
  122. &self.map_view,
  123. source,
  124. &mut self.tile_cache,
  125. &mut self.tile_atlas,
  126. self.viewport_size,
  127. snap_to_pixel
  128. )
  129. }
  130. fn draw_marker(&mut self, cx: &mut Context, snap_to_pixel: bool) {
  131. if self.last_draw_type != DrawType::Markers {
  132. self.last_draw_type = DrawType::Markers;
  133. self.marker_layer.prepare_draw(cx);
  134. }
  135. //TODO remove viewport_size parameter
  136. self.marker_layer.draw(cx, &self.map_view, self.viewport_size, snap_to_pixel);
  137. }
  138. fn draw_globe(&mut self, cx: &mut Context, source: &TileSource) {
  139. if self.last_draw_type != DrawType::Globe {
  140. self.last_draw_type = DrawType::Globe;
  141. self.globe_tile_layer.prepare_draw(cx, &self.tile_atlas);
  142. }
  143. self.globe_tile_layer.draw(
  144. cx,
  145. &self.map_view,
  146. source,
  147. &mut self.tile_cache,
  148. &mut self.tile_atlas,
  149. );
  150. }
  151. /// Returns `Err` when tile cache is too small for this view.
  152. /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
  153. /// size of the tile atlas.
  154. pub fn draw(&mut self, cx: &mut Context, source: &TileSource) -> Result<usize, usize> {
  155. // only snap to pixel grid if zoom has integral value
  156. let snap_to_pixel = (self.map_view.zoom - (self.map_view.zoom + 0.5).floor()).abs() < 1e-10;
  157. match self.projection {
  158. Projection::Mercator => {
  159. let ret = self.draw_flat_tiles(cx, source, snap_to_pixel);
  160. if !self.marker_layer.is_empty() {
  161. self.draw_marker(cx, snap_to_pixel);
  162. }
  163. ret
  164. },
  165. Projection::Orthografic => {
  166. self.draw_globe(cx, source);
  167. Ok(1)
  168. },
  169. }
  170. }
  171. pub fn step_zoom(&mut self, steps: i32, step_size: f64) {
  172. let new_zoom = {
  173. let z = (self.map_view.zoom + f64::from(steps) * step_size) / step_size;
  174. if steps > 0 {
  175. z.ceil() * step_size
  176. } else {
  177. z.floor() * step_size
  178. }
  179. }.max(MIN_ZOOM_LEVEL).min(MAX_ZOOM_LEVEL);
  180. self.map_view.set_zoom(new_zoom);
  181. }
  182. pub fn zoom(&mut self, zoom_delta: f64) {
  183. if self.map_view.zoom + zoom_delta < MIN_ZOOM_LEVEL {
  184. self.map_view.set_zoom(MIN_ZOOM_LEVEL);
  185. } else if self.map_view.zoom + zoom_delta > MAX_ZOOM_LEVEL {
  186. self.map_view.set_zoom(MAX_ZOOM_LEVEL);
  187. } else {
  188. self.map_view.zoom(zoom_delta);
  189. }
  190. }
  191. pub fn zoom_at(&mut self, pos: ScreenCoord, zoom_delta: f64) {
  192. if self.map_view.zoom + zoom_delta < MIN_ZOOM_LEVEL {
  193. self.map_view.set_zoom_at(pos, MIN_ZOOM_LEVEL);
  194. } else if self.map_view.zoom + zoom_delta > MAX_ZOOM_LEVEL {
  195. self.map_view.set_zoom_at(pos, MAX_ZOOM_LEVEL);
  196. } else {
  197. self.map_view.zoom_at(pos, zoom_delta);
  198. }
  199. self.map_view.center.normalize_xy();
  200. }
  201. pub fn change_tile_zoom_offset(&mut self, delta_offset: f64) {
  202. let offset = self.map_view.tile_zoom_offset();
  203. self.map_view.set_tile_zoom_offset(offset + delta_offset);
  204. }
  205. pub fn move_pixel(&mut self, delta_x: f64, delta_y: f64) {
  206. self.map_view.move_pixel(delta_x, delta_y);
  207. self.map_view.center.normalize_xy();
  208. }
  209. pub fn restore_session(&mut self, session: &Session) {
  210. self.map_view.center = session.view_center;
  211. self.map_view.center.normalize_xy();
  212. self.map_view.zoom = MIN_ZOOM_LEVEL.max(MAX_ZOOM_LEVEL.min(session.zoom));
  213. }
  214. pub fn to_session(&self) -> Session {
  215. Session {
  216. view_center: self.map_view.center,
  217. zoom: self.map_view.zoom,
  218. tile_source: None,
  219. }
  220. }
  221. }