浏览代码

Restructure modules

* Split up map_view module into
  * map_view
  * mercator_view
  * orthografic_view
Johannes Hofmann 7 年前
父节点
当前提交
cf7f21acc3
共有 13 个文件被更改,包括 394 次插入357 次删除
  1. 15
    0
      shader/map_tile_border.frag
  2. 0
    0
      shader/ortho_tile.frag
  3. 0
    0
      shader/ortho_tile.vert
  4. 0
    14
      src/coord.rs
  5. 3
    1
      src/main.rs
  6. 4
    305
      src/map_view.rs
  7. 22
    18
      src/map_view_gl.rs
  8. 3
    2
      src/marker_layer.rs
  9. 151
    0
      src/mercator_view.rs
  10. 15
    14
      src/ortho_tile_layer.rs
  11. 177
    0
      src/orthografic_view.rs
  12. 1
    1
      src/tile_atlas.rs
  13. 3
    2
      src/tile_layer.rs

+ 15
- 0
shader/map_tile_border.frag 查看文件

1
+#version 100
2
+precision mediump float;
3
+
4
+varying vec2 v_tex;
5
+varying vec4 v_tex_minmax;
6
+uniform sampler2D tex_map;
7
+
8
+void main() {
9
+    vec2 mid = 0.5 * (v_tex_minmax.zw + v_tex_minmax.xy);
10
+    vec2 scale = 1.0 / (v_tex_minmax.zw - v_tex_minmax.xy);
11
+    vec2 dist = abs((v_tex - mid) * scale);
12
+    float shade = 1.0 - step(0.49, max(dist.x, dist.y)) * 0.5;
13
+    float add = step(0.4975, max(dist.x, dist.y)) * 0.5;
14
+    gl_FragColor = vec4(texture2D(tex_map, clamp(v_tex.xy, v_tex_minmax.xy, v_tex_minmax.zw)).rgb * shade + vec3(add), 1.0);
15
+}

shader/globe_tile.frag → shader/ortho_tile.frag 查看文件


shader/globe_tile.vert → shader/ortho_tile.vert 查看文件


+ 0
- 14
src/coord.rs 查看文件

357
         }
357
         }
358
     }
358
     }
359
 
359
 
360
-    /// Return the coordinate inside the tile that is nearest to the given coordinate.
361
-    /// This function uses spherical topology.
362
-    pub fn nearest_inside_point(&self, other: MapCoord) -> MapCoord {
363
-        //TODO insert real implemenation here
364
-        self.map_coord_north_west()
365
-    }
366
-
367
     pub fn children(&self) -> [(TileCoord, SubTileCoord); 4] {
360
     pub fn children(&self) -> [(TileCoord, SubTileCoord); 4] {
368
         [
361
         [
369
             (
362
             (
649
         assert_eq!(TileCoord::new(2, 0, -1).globe_norm(), TileCoord::new(2, 2, 0));
642
         assert_eq!(TileCoord::new(2, 0, -1).globe_norm(), TileCoord::new(2, 2, 0));
650
         assert_eq!(TileCoord::new(2, 0, -5).globe_norm(), TileCoord::new(2, 0, 3));
643
         assert_eq!(TileCoord::new(2, 0, -5).globe_norm(), TileCoord::new(2, 0, 3));
651
     }
644
     }
652
-
653
-    #[test]
654
-    fn nearest_inside_point() {
655
-        assert_eq!(TileCoord::new(0, 0, 0).nearest_inside_point(MapCoord::new(0.5, 0.25)), MapCoord::new(0.5, 0.25));
656
-        assert_eq!(TileCoord::new(2, 0, 0).nearest_inside_point(MapCoord::new(0.5, 0.5)), MapCoord::new(0.25, 0.25));
657
-        //TODO Add more test cases
658
-    }
659
 }
645
 }

+ 3
- 1
src/main.rs 查看文件

23
 #[macro_use]
23
 #[macro_use]
24
 pub mod context;
24
 pub mod context;
25
 pub mod coord;
25
 pub mod coord;
26
-pub mod globe_tile_layer;
26
+pub mod ortho_tile_layer;
27
 pub mod map_view;
27
 pub mod map_view;
28
 pub mod map_view_gl;
28
 pub mod map_view_gl;
29
 pub mod marker_layer;
29
 pub mod marker_layer;
30
+pub mod mercator_view;
31
+pub mod orthografic_view;
30
 pub mod program;
32
 pub mod program;
31
 pub mod search;
33
 pub mod search;
32
 pub mod session;
34
 pub mod session;

+ 4
- 305
src/map_view.rs 查看文件

1
-use cgmath::{Matrix3, Point3, Transform, vec3};
2
-use coord::{MapCoord, ScreenCoord, ScreenRect, TileCoord};
3
-use std::f32::consts::{PI, FRAC_1_PI};
4
-use std::f64;
1
+use coord::MapCoord;
5
 
2
 
6
 
3
 
7
-/// A view of a tiled map with a rectangular viewport and a zoom.
4
+/// A view of a map with a rectangular viewport and a zoom.
8
 #[derive(Clone, Debug)]
5
 #[derive(Clone, Debug)]
9
 pub struct MapView {
6
 pub struct MapView {
10
     /// Width of the viewport.
7
     /// Width of the viewport.
23
     pub tile_zoom_offset: f64,
20
     pub tile_zoom_offset: f64,
24
 }
21
 }
25
 
22
 
26
-/// The position and size of a specific tile on the screen.
27
-#[derive(Clone, Debug)]
28
-pub struct VisibleTile {
29
-    pub tile: TileCoord,
30
-    pub rect: ScreenRect,
31
-}
32
-
33
 impl MapView {
23
 impl MapView {
34
     /// Constructs a new `MapView`.
24
     /// Constructs a new `MapView`.
35
     pub fn new(width: f64, height: f64, tile_size: u32, center: MapCoord, zoom: f64) -> MapView {
25
     pub fn new(width: f64, height: f64, tile_size: u32, center: MapCoord, zoom: f64) -> MapView {
43
         }
33
         }
44
     }
34
     }
45
 
35
 
46
-    /// Constructs a new `MapView` centered at Null Island with an integer zoom that fills a screen
47
-    /// with the given dimensions.
48
-    pub fn with_filling_zoom(width: f64, height: f64, tile_size: u32) -> MapView {
49
-        let min_dimension = width.min(height);
50
-        let zoom = (min_dimension / f64::from(tile_size)).log2().ceil();
51
-        MapView {
52
-            width,
53
-            height,
54
-            tile_size,
55
-            center: MapCoord::new(0.5, 0.5),
56
-            zoom,
57
-            tile_zoom_offset: 0.0,
58
-        }
59
-    }
60
-
61
-    /// Returns the map coordinate that corresponds to the top-left corner of the viewport.
62
-    pub fn top_left_coord(&self) -> MapCoord {
63
-        let scale = f64::powf(2.0, -self.zoom) / f64::from(self.tile_size);
64
-
65
-        let x = self.center.x + -0.5 * self.width * scale;
66
-        let y = self.center.y + -0.5 * self.height * scale;
67
-
68
-        MapCoord::new(x, y)
69
-    }
70
-
71
-    /// Returns the screen coordinate that corresponds to the given map coordinate.
72
-    pub fn map_to_screen_coord(&self, map_coord: MapCoord) -> ScreenCoord {
73
-        let scale = f64::powf(2.0, self.zoom) * f64::from(self.tile_size);
74
-
75
-        let delta_x = map_coord.x - self.center.x;
76
-        let delta_y = map_coord.y - self.center.y;
77
-
78
-        ScreenCoord {
79
-            x: 0.5 * self.width + delta_x * scale,
80
-            y: 0.5 * self.height + delta_y * scale,
81
-        }
82
-    }
83
-
84
-    /// Returns true if the viewport rectangle is fully inside the map.
85
-    pub fn map_covers_viewport(&self) -> bool {
86
-        let scale = f64::powf(2.0, -self.zoom) / f64::from(self.tile_size);
87
-
88
-        let y_top = self.center.y + -0.5 * self.height * scale;
89
-        let y_bottom = self.center.y + 0.5 * self.height * scale;
90
-
91
-        y_top >= 0.0 && y_bottom <= 1.0
92
-    }
93
-
94
-    /// Returns true if the globe rendering covers the whole viewport.
95
-    pub fn globe_covers_viewport(&self) -> bool {
96
-        //TODO Add a little safety margin since the rendered globe is not a perfect sphere and its
97
-        // screen area is underestimated by the tesselation.
98
-        let globe_diameter = 2.0f64.powf(self.zoom) *
99
-            (f64::consts::FRAC_1_PI * self.tile_size as f64);
100
-
101
-        return (self.width * self.width) + (self.height * self.height) < globe_diameter * globe_diameter;
102
-    }
103
-
104
-    /// Returns the screen coordinate of the top-left corner of a tile.
105
-    pub fn tile_screen_position(&self, tile: &TileCoord) -> ScreenCoord {
106
-        self.map_to_screen_coord(tile.map_coord_north_west())
107
-    }
108
-
109
-    /// Returns a `Vec` of all tiles that are visible in the current viewport.
110
-    pub fn visible_tiles(&self, snap_to_pixel: bool) -> Vec<VisibleTile> {
111
-        let uzoom = self.tile_zoom();
112
-        let top_left_tile = self.top_left_coord().on_tile_at_zoom(uzoom);
113
-        let mut top_left_tile_screen_coord = self.tile_screen_position(&top_left_tile);
114
-        let tile_screen_size = f64::powf(2.0, self.zoom - f64::from(uzoom)) * f64::from(self.tile_size);
115
-
116
-        if snap_to_pixel {
117
-            top_left_tile_screen_coord.snap_to_pixel();
118
-        }
119
-
120
-        let start_tile_x = top_left_tile.x;
121
-        let start_tile_y = top_left_tile.y;
122
-        let num_tiles_x = ((self.width - top_left_tile_screen_coord.x) / tile_screen_size).ceil().max(0.0) as i32;
123
-        let num_tiles_y = ((self.height - top_left_tile_screen_coord.y) / tile_screen_size).ceil().max(0.0) as i32;
124
-
125
-        let mut visible_tiles = Vec::with_capacity(num_tiles_x as usize * num_tiles_y as usize);
126
-
127
-        for y in 0..num_tiles_y {
128
-            for x in 0..num_tiles_x {
129
-                let t = TileCoord::new(uzoom, start_tile_x + x, start_tile_y + y);
130
-                if t.is_on_planet() {
131
-                    visible_tiles.push(
132
-                        VisibleTile {
133
-                            tile: t,
134
-                            rect: ScreenRect {
135
-                                x: top_left_tile_screen_coord.x + tile_screen_size * f64::from(x),
136
-                                y: top_left_tile_screen_coord.y + tile_screen_size * f64::from(y),
137
-                                width: tile_screen_size,
138
-                                height: tile_screen_size,
139
-                            }
140
-                        }
141
-                    );
142
-                }
143
-            }
144
-        }
145
-
146
-        visible_tiles
147
-    }
148
-
149
-    //TODO Put this in a new module with other "sphere things"
150
-    //TODO Return the transformation matrix that is used here to avoid redundant calculation.
151
-    /// Returns a `Vec` of all tiles that are visible in the current viewport.
152
-    pub fn visible_globe_tiles(&self) -> Vec<TileCoord> {
153
-        let uzoom = self.tile_zoom();
154
-
155
-        match uzoom {
156
-            0 => return vec![TileCoord::new(0, 0, 0)],
157
-            1 => {
158
-                // return every tile
159
-                return vec![
160
-                    TileCoord::new(1, 0, 0),
161
-                    TileCoord::new(1, 0, 1),
162
-                    TileCoord::new(1, 1, 0),
163
-                    TileCoord::new(1, 1, 1),
164
-                ]},
165
-            _ => {},
166
-        }
167
-
168
-        let center_tile = self.center.on_tile_at_zoom(uzoom).globe_norm();
169
-
170
-        let transform = self.globe_transformation_matrix();
171
-
172
-        let add_tile_if_visible = |tc: TileCoord, vec: &mut Vec<TileCoord>| -> bool {
173
-            let nearest = tc.nearest_inside_point(self.center).to_latlon_rad().to_sphere_point3();
174
-            let screen_coord = transform.transform_point(nearest);
175
-
176
-            let visible = screen_coord.x >= -1.0 && screen_coord.x <= 1.0 &&
177
-                screen_coord.y >= -1.0 && screen_coord.y <= 1.0;
178
-
179
-            if visible {
180
-                vec.push(tc);
181
-                true
182
-            } else {
183
-                false
184
-            }
185
-        };
186
-
187
-        let mut tiles = vec![];
188
-
189
-        {
190
-            let zoom_level_tiles = TileCoord::get_zoom_level_tiles(uzoom);
191
-
192
-            for dx in 0..(zoom_level_tiles / 2) {
193
-                let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x + dx, center_tile.y), &mut tiles);
194
-                if !v {
195
-                    break;
196
-                }
197
-            }
198
-            for dx in 1..(1 + zoom_level_tiles / 2) {
199
-                let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x - dx, center_tile.y), &mut tiles);
200
-                if !v {
201
-                    break;
202
-                }
203
-            }
204
-
205
-            // move south
206
-            for y in (center_tile.y + 1)..zoom_level_tiles {
207
-                let mut visible = false;
208
-
209
-                for dx in 0..(zoom_level_tiles / 2) {
210
-                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x + dx, y), &mut tiles);
211
-                    visible = visible || v;
212
-                    if !v {
213
-                        break;
214
-                    }
215
-                }
216
-                for dx in 1..(1 + zoom_level_tiles / 2) {
217
-                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x - dx, y), &mut tiles);
218
-                    visible = visible || v;
219
-                    if !v {
220
-                        break;
221
-                    }
222
-                }
223
-
224
-                if !visible {
225
-                    break;
226
-                }
227
-            }
228
-
229
-            // move north
230
-            for y in (0..center_tile.y).rev() {
231
-                let mut visible = false;
232
-
233
-                for dx in 0..(zoom_level_tiles / 2) {
234
-                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x + dx, y), &mut tiles);
235
-                    visible = visible || v;
236
-                    if !v {
237
-                        break;
238
-                    }
239
-                }
240
-                for dx in 1..(1 + zoom_level_tiles / 2) {
241
-                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x - dx, y), &mut tiles);
242
-                    visible = visible || v;
243
-                    if !v {
244
-                        break;
245
-                    }
246
-                }
247
-
248
-                if !visible {
249
-                    break;
250
-                }
251
-            }
252
-        }
253
-
254
-        tiles
255
-    }
256
-
257
-    pub fn globe_transformation_matrix(&self) -> Matrix3<f32> {
258
-        let (scale_x, scale_y) = {
259
-            let factor = 2.0f32.powf(self.zoom as f32) *
260
-                (FRAC_1_PI * self.tile_size as f32);
261
-            (factor / self.width as f32, factor / self.height as f32)
262
-        };
263
-
264
-        let scale_mat: Matrix3<f32> = Matrix3::from_cols(
265
-            vec3(scale_x, 0.0, 0.0),
266
-            vec3(0.0, scale_y, 0.0),
267
-            vec3(0.0, 0.0, 1.0),
268
-        );
269
-
270
-        let rot_mat_x: Matrix3<f32> = {
271
-            let center_latlon = self.center.to_latlon_rad();
272
-            let alpha = center_latlon.lon as f32 + (PI * 0.5);
273
-            let cosa = alpha.cos();
274
-            let sina = alpha.sin();
275
-                Matrix3::from_cols(
276
-                vec3(cosa, 0.0, -sina),
277
-                vec3(0.0, 1.0, 0.0),
278
-                vec3(sina, 0.0, cosa),
279
-            )
280
-        };
281
-
282
-        let rot_mat_y: Matrix3<f32> = {
283
-            let center_latlon = self.center.to_latlon_rad();
284
-            let alpha = (-center_latlon.lat) as f32;
285
-            let cosa = alpha.cos();
286
-            let sina = alpha.sin();
287
-                Matrix3::from_cols(
288
-                vec3(1.0, 0.0, 0.0),
289
-                vec3(0.0, cosa, sina),
290
-                vec3(0.0, -sina, cosa),
291
-            )
292
-        };
293
-
294
-        let transform = Transform::<Point3<f32>>::concat(&rot_mat_y, &rot_mat_x);
295
-        let transform = Transform::<Point3<f32>>::concat(&scale_mat, &transform);
296
-        transform
297
-    }
298
-
299
-    /// Returns the tile zoom value that is used for rendering with the current zoom.
300
-    pub fn tile_zoom(&self) -> u32 {
301
-        (self.zoom + self.tile_zoom_offset).floor().max(0.0) as u32
302
-    }
303
-
304
     /// Returns the tile zoom offset.
36
     /// Returns the tile zoom offset.
305
-    pub fn tile_zoom_offset(&self) -> f64 {
306
-        self.tile_zoom_offset
37
+    pub fn tile_zoom_offset(map_view: &MapView) -> f64 {
38
+        map_view.tile_zoom_offset
307
     }
39
     }
308
 
40
 
309
     /// Set the tile zoom offset.
41
     /// Set the tile zoom offset.
326
     pub fn zoom(&mut self, zoom_delta: f64) {
58
     pub fn zoom(&mut self, zoom_delta: f64) {
327
         self.zoom += zoom_delta;
59
         self.zoom += zoom_delta;
328
     }
60
     }
329
-
330
-    /// Change zoom value by `zoom_delta` and zoom to a position given in screen coordinates.
331
-    pub fn zoom_at(&mut self, pos: ScreenCoord, zoom_delta: f64) {
332
-        let delta_x = pos.x - self.width * 0.5;
333
-        let delta_y = pos.y - self.height * 0.5;
334
-
335
-        let scale =
336
-            (f64::powf(2.0, -self.zoom) - f64::powf(2.0, -self.zoom - zoom_delta))
337
-            / f64::from(self.tile_size);
338
-        self.zoom += zoom_delta;
339
-
340
-        self.center.x += delta_x * scale;
341
-        self.center.y += delta_y * scale;
342
-    }
343
-
344
-    /// Set a zoom value and zoom to a `position` given in screen coordinates.
345
-    pub fn set_zoom_at(&mut self, pos: ScreenCoord, zoom: f64) {
346
-        let delta_x = pos.x - self.width * 0.5;
347
-        let delta_y = pos.y - self.height * 0.5;
348
-
349
-        let scale = (f64::powf(2.0, -self.zoom) - f64::powf(2.0, -zoom)) / f64::from(self.tile_size);
350
-        self.zoom = zoom;
351
-
352
-        self.center.x += delta_x * scale;
353
-        self.center.y += delta_y * scale;
354
-    }
355
-
356
-    /// Move the center of the viewport by (`delta_x`, `delta_y`) in screen coordinates.
357
-    pub fn move_pixel(&mut self, delta_x: f64, delta_y: f64) {
358
-        let scale = f64::powf(2.0, -self.zoom) / f64::from(self.tile_size);
359
-        self.center.x += delta_x * scale;
360
-        self.center.y += delta_y * scale;
361
-    }
362
 }
61
 }

+ 22
- 18
src/map_view_gl.rs 查看文件

1
 use context::Context;
1
 use context::Context;
2
 use coord::{MapCoord, ScreenCoord};
2
 use coord::{MapCoord, ScreenCoord};
3
-use globe_tile_layer::GlobeTileLayer;
3
+use ortho_tile_layer::OrthoTileLayer;
4
 use map_view::MapView;
4
 use map_view::MapView;
5
 use marker_layer::MarkerLayer;
5
 use marker_layer::MarkerLayer;
6
+use mercator_view::MercatorView;
7
+use orthografic_view::OrthograficView;
6
 use session::Session;
8
 use session::Session;
7
 use texture::{Texture, TextureFormat};
9
 use texture::{Texture, TextureFormat};
8
 use tile_atlas::TileAtlas;
10
 use tile_atlas::TileAtlas;
22
     tile_atlas: TileAtlas,
24
     tile_atlas: TileAtlas,
23
     tile_layer: TileLayer,
25
     tile_layer: TileLayer,
24
     marker_layer: MarkerLayer,
26
     marker_layer: MarkerLayer,
25
-    globe_tile_layer: GlobeTileLayer,
27
+    ortho_tile_layer: OrthoTileLayer,
26
     projection: Projection,
28
     projection: Projection,
27
     last_draw_type: DrawType,
29
     last_draw_type: DrawType,
28
 }
30
 }
40
     Null,
42
     Null,
41
     Tiles,
43
     Tiles,
42
     Markers,
44
     Markers,
43
-    Globe,
45
+    OrthoTiles,
44
 }
46
 }
45
 
47
 
46
 impl MapViewGl {
48
 impl MapViewGl {
55
     {
57
     {
56
         let tile_size = 256;
58
         let tile_size = 256;
57
 
59
 
58
-        let mut map_view = MapView::with_filling_zoom(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
60
+        let mut map_view = MercatorView::initial_map_view(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
59
 
61
 
60
         if map_view.zoom < MIN_ZOOM_LEVEL {
62
         if map_view.zoom < MIN_ZOOM_LEVEL {
61
             map_view.zoom = MIN_ZOOM_LEVEL;
63
             map_view.zoom = MIN_ZOOM_LEVEL;
93
             tile_atlas,
95
             tile_atlas,
94
             tile_layer,
96
             tile_layer,
95
             marker_layer: MarkerLayer::new(cx),
97
             marker_layer: MarkerLayer::new(cx),
96
-            globe_tile_layer: GlobeTileLayer::new(cx),
98
+            ortho_tile_layer: OrthoTileLayer::new(cx),
97
             projection: Projection::Mercator,
99
             projection: Projection::Mercator,
98
             last_draw_type: DrawType::Null,
100
             last_draw_type: DrawType::Null,
99
         }
101
         }
111
 
113
 
112
     pub fn map_covers_viewport(&self) -> bool {
114
     pub fn map_covers_viewport(&self) -> bool {
113
         match self.projection {
115
         match self.projection {
114
-            Projection::Mercator => self.map_view.map_covers_viewport(),
116
+            Projection::Mercator => MercatorView::covers_viewport(&self.map_view),
115
             //TODO uncomment
117
             //TODO uncomment
116
-            //Projection::Orthografic => self.map_view.globe_covers_viewport(),
118
+            //Projection::Orthografic => OrthograficView::covers_viewport(&self.map_view),
117
             Projection::Orthografic => false,
119
             Projection::Orthografic => false,
118
         }
120
         }
119
     }
121
     }
159
         self.marker_layer.draw(cx, &self.map_view, self.viewport_size, snap_to_pixel);
161
         self.marker_layer.draw(cx, &self.map_view, self.viewport_size, snap_to_pixel);
160
     }
162
     }
161
 
163
 
162
-    fn draw_globe(&mut self, cx: &mut Context, source: &TileSource) {
163
-        if self.last_draw_type != DrawType::Globe {
164
-            self.last_draw_type = DrawType::Globe;
165
-            self.globe_tile_layer.prepare_draw(cx, &self.tile_atlas);
164
+    fn draw_ortho_tiles(&mut self, cx: &mut Context, source: &TileSource) {
165
+        if self.last_draw_type != DrawType::OrthoTiles {
166
+            self.last_draw_type = DrawType::OrthoTiles;
167
+            self.ortho_tile_layer.prepare_draw(cx, &self.tile_atlas);
166
         }
168
         }
167
 
169
 
168
-        self.globe_tile_layer.draw(
170
+        self.ortho_tile_layer.draw(
169
             cx,
171
             cx,
170
             &self.map_view,
172
             &self.map_view,
171
             source,
173
             source,
190
                 ret
192
                 ret
191
             },
193
             },
192
             Projection::Orthografic => {
194
             Projection::Orthografic => {
193
-                self.draw_globe(cx, source);
195
+                self.draw_ortho_tiles(cx, source);
194
                 Ok(1)
196
                 Ok(1)
195
             },
197
             },
196
         }
198
         }
220
     }
222
     }
221
 
223
 
222
     pub fn zoom_at(&mut self, pos: ScreenCoord, zoom_delta: f64) {
224
     pub fn zoom_at(&mut self, pos: ScreenCoord, zoom_delta: f64) {
225
+        //TODO implement for OrthograficView
223
         if self.map_view.zoom + zoom_delta < MIN_ZOOM_LEVEL {
226
         if self.map_view.zoom + zoom_delta < MIN_ZOOM_LEVEL {
224
-            self.map_view.set_zoom_at(pos, MIN_ZOOM_LEVEL);
227
+            MercatorView::set_zoom_at(&mut self.map_view, pos, MIN_ZOOM_LEVEL);
225
         } else if self.map_view.zoom + zoom_delta > MAX_ZOOM_LEVEL {
228
         } else if self.map_view.zoom + zoom_delta > MAX_ZOOM_LEVEL {
226
-            self.map_view.set_zoom_at(pos, MAX_ZOOM_LEVEL);
229
+            MercatorView::set_zoom_at(&mut self.map_view, pos, MAX_ZOOM_LEVEL);
227
         } else {
230
         } else {
228
-            self.map_view.zoom_at(pos, zoom_delta);
231
+            MercatorView::zoom_at(&mut self.map_view, pos, zoom_delta);
229
         }
232
         }
230
         self.map_view.center.normalize_xy();
233
         self.map_view.center.normalize_xy();
231
     }
234
     }
232
 
235
 
233
     pub fn change_tile_zoom_offset(&mut self, delta_offset: f64) {
236
     pub fn change_tile_zoom_offset(&mut self, delta_offset: f64) {
234
-        let offset = self.map_view.tile_zoom_offset();
237
+        let offset = self.map_view.tile_zoom_offset;
235
         self.map_view.set_tile_zoom_offset(offset + delta_offset);
238
         self.map_view.set_tile_zoom_offset(offset + delta_offset);
236
     }
239
     }
237
 
240
 
238
     pub fn move_pixel(&mut self, delta_x: f64, delta_y: f64) {
241
     pub fn move_pixel(&mut self, delta_x: f64, delta_y: f64) {
239
-        self.map_view.move_pixel(delta_x, delta_y);
242
+        //TODO implement for OrthograficView
243
+        MercatorView::move_pixel(&mut self.map_view, delta_x, delta_y);
240
         self.map_view.center.normalize_xy();
244
         self.map_view.center.normalize_xy();
241
     }
245
     }
242
 
246
 

+ 3
- 2
src/marker_layer.rs 查看文件

5
 use coord::{MapCoord, ScreenRect};
5
 use coord::{MapCoord, ScreenRect};
6
 use image;
6
 use image;
7
 use map_view::MapView;
7
 use map_view::MapView;
8
+use mercator_view::MercatorView;
8
 use program::Program;
9
 use program::Program;
9
 use texture::Texture;
10
 use texture::Texture;
10
 use vertex_attrib::VertexAttribParams;
11
 use vertex_attrib::VertexAttribParams;
115
 
116
 
116
         for map_pos in &self.positions {
117
         for map_pos in &self.positions {
117
             let screen_pos = {
118
             let screen_pos = {
118
-                let mut sp = map_view.map_to_screen_coord(*map_pos);
119
+                let mut sp = MercatorView::map_to_screen_coord(map_view, *map_pos);
119
                 if snap_to_pixel {
120
                 if snap_to_pixel {
120
-                    let topleft = map_view.map_to_screen_coord(MapCoord::new(0.0, 0.0));
121
+                    let topleft = MercatorView::map_to_screen_coord(map_view, MapCoord::new(0.0, 0.0));
121
                     let mut snapped = topleft;
122
                     let mut snapped = topleft;
122
                     snapped.snap_to_pixel();
123
                     snapped.snap_to_pixel();
123
 
124
 

+ 151
- 0
src/mercator_view.rs 查看文件

1
+use coord::{MapCoord, ScreenCoord, ScreenRect, TileCoord};
2
+use map_view::MapView;
3
+
4
+
5
+/// A view of a tiled map with a rectangular viewport and a zoom.
6
+#[derive(Clone, Debug)]
7
+pub struct MercatorView {
8
+}
9
+
10
+/// The position and size of a specific tile on the screen.
11
+#[derive(Clone, Debug)]
12
+pub struct VisibleTile {
13
+    pub tile: TileCoord,
14
+    pub rect: ScreenRect,
15
+}
16
+
17
+impl MercatorView {
18
+    /// Constructs a `MapView` centered at Null Island with an integer zoom that fills a screen
19
+    /// with the given dimensions.
20
+    pub fn initial_map_view(width: f64, height: f64, tile_size: u32) -> MapView {
21
+        let min_dimension = width.min(height);
22
+        let zoom = (min_dimension / f64::from(tile_size)).log2().ceil();
23
+        MapView {
24
+            width,
25
+            height,
26
+            tile_size,
27
+            center: MapCoord::new(0.5, 0.5),
28
+            zoom,
29
+            tile_zoom_offset: 0.0,
30
+        }
31
+    }
32
+
33
+    /// Returns the map coordinate that corresponds to the top-left corner of the viewport.
34
+    pub fn top_left_coord(map_view: &MapView) -> MapCoord {
35
+        let scale = f64::powf(2.0, -map_view.zoom) / f64::from(map_view.tile_size);
36
+
37
+        let x = map_view.center.x + -0.5 * map_view.width * scale;
38
+        let y = map_view.center.y + -0.5 * map_view.height * scale;
39
+
40
+        MapCoord::new(x, y)
41
+    }
42
+
43
+    /// Returns the screen coordinate that corresponds to the given map coordinate.
44
+    pub fn map_to_screen_coord(map_view: &MapView, map_coord: MapCoord) -> ScreenCoord {
45
+        let scale = f64::powf(2.0, map_view.zoom) * f64::from(map_view.tile_size);
46
+
47
+        let delta_x = map_coord.x - map_view.center.x;
48
+        let delta_y = map_coord.y - map_view.center.y;
49
+
50
+        ScreenCoord {
51
+            x: 0.5 * map_view.width + delta_x * scale,
52
+            y: 0.5 * map_view.height + delta_y * scale,
53
+        }
54
+    }
55
+
56
+    /// Returns true if the viewport rectangle is fully inside the map.
57
+    pub fn covers_viewport(map_view: &MapView) -> bool {
58
+        let scale = f64::powf(2.0, -map_view.zoom) / f64::from(map_view.tile_size);
59
+
60
+        let y_top = map_view.center.y + -0.5 * map_view.height * scale;
61
+        let y_bottom = map_view.center.y + 0.5 * map_view.height * scale;
62
+
63
+        y_top >= 0.0 && y_bottom <= 1.0
64
+    }
65
+
66
+    /// Returns the screen coordinate of the top-left corner of a tile.
67
+    pub fn tile_screen_position(map_view: &MapView, tile: &TileCoord) -> ScreenCoord {
68
+        Self::map_to_screen_coord(map_view, tile.map_coord_north_west())
69
+    }
70
+
71
+    /// Returns a `Vec` of all tiles that are visible in the current viewport.
72
+    pub fn visible_tiles(map_view: &MapView, snap_to_pixel: bool) -> Vec<VisibleTile> {
73
+        let uzoom = Self::tile_zoom(map_view);
74
+        let top_left_tile = Self::top_left_coord(map_view).on_tile_at_zoom(uzoom);
75
+        let mut top_left_tile_screen_coord = Self::tile_screen_position(map_view, &top_left_tile);
76
+        let tile_screen_size = f64::powf(2.0, map_view.zoom - f64::from(uzoom)) *
77
+            f64::from(map_view.tile_size);
78
+
79
+        if snap_to_pixel {
80
+            top_left_tile_screen_coord.snap_to_pixel();
81
+        }
82
+
83
+        let start_tile_x = top_left_tile.x;
84
+        let start_tile_y = top_left_tile.y;
85
+        let num_tiles_x = ((map_view.width - top_left_tile_screen_coord.x) /
86
+                           tile_screen_size).ceil().max(0.0) as i32;
87
+        let num_tiles_y = ((map_view.height - top_left_tile_screen_coord.y) /
88
+                           tile_screen_size).ceil().max(0.0) as i32;
89
+
90
+        let mut visible_tiles = Vec::with_capacity(num_tiles_x as usize * num_tiles_y as usize);
91
+
92
+        for y in 0..num_tiles_y {
93
+            for x in 0..num_tiles_x {
94
+                let t = TileCoord::new(uzoom, start_tile_x + x, start_tile_y + y);
95
+                if t.is_on_planet() {
96
+                    visible_tiles.push(
97
+                        VisibleTile {
98
+                            tile: t,
99
+                            rect: ScreenRect {
100
+                                x: top_left_tile_screen_coord.x + tile_screen_size * f64::from(x),
101
+                                y: top_left_tile_screen_coord.y + tile_screen_size * f64::from(y),
102
+                                width: tile_screen_size,
103
+                                height: tile_screen_size,
104
+                            }
105
+                        }
106
+                    );
107
+                }
108
+            }
109
+        }
110
+
111
+        visible_tiles
112
+    }
113
+
114
+    /// Returns the tile zoom value that is used for rendering with the current zoom.
115
+    pub fn tile_zoom(map_view: &MapView) -> u32 {
116
+        (map_view.zoom + map_view.tile_zoom_offset).floor().max(0.0) as u32
117
+    }
118
+
119
+    /// Change zoom value by `zoom_delta` and zoom to a position given in screen coordinates.
120
+    pub fn zoom_at(map_view: &mut MapView, pos: ScreenCoord, zoom_delta: f64) {
121
+        let delta_x = pos.x - map_view.width * 0.5;
122
+        let delta_y = pos.y - map_view.height * 0.5;
123
+
124
+        let scale = (f64::powf(2.0, -map_view.zoom) - f64::powf(2.0, -map_view.zoom - zoom_delta))
125
+            / f64::from(map_view.tile_size);
126
+
127
+        map_view.zoom += zoom_delta;
128
+        map_view.center.x += delta_x * scale;
129
+        map_view.center.y += delta_y * scale;
130
+    }
131
+
132
+    /// Set a zoom value and zoom to a `position` given in screen coordinates.
133
+    pub fn set_zoom_at(map_view: &mut MapView, pos: ScreenCoord, zoom: f64) {
134
+        let delta_x = pos.x - map_view.width * 0.5;
135
+        let delta_y = pos.y - map_view.height * 0.5;
136
+
137
+        let scale = (f64::powf(2.0, -map_view.zoom) - f64::powf(2.0, -zoom)) /
138
+            f64::from(map_view.tile_size);
139
+
140
+        map_view.zoom = zoom;
141
+        map_view.center.x += delta_x * scale;
142
+        map_view.center.y += delta_y * scale;
143
+    }
144
+
145
+    /// Move the center of the viewport by (`delta_x`, `delta_y`) in screen coordinates.
146
+    pub fn move_pixel(map_view: &mut MapView, delta_x: f64, delta_y: f64) {
147
+        let scale = f64::powf(2.0, -map_view.zoom) / f64::from(map_view.tile_size);
148
+        map_view.center.x += delta_x * scale;
149
+        map_view.center.y += delta_y * scale;
150
+    }
151
+}

src/globe_tile_layer.rs → src/ortho_tile_layer.rs 查看文件

1
-use std::ffi::CStr;
2
 use buffer::{Buffer, DrawMode};
1
 use buffer::{Buffer, DrawMode};
3
 use cgmath::Transform;
2
 use cgmath::Transform;
4
 use context::Context;
3
 use context::Context;
5
 use coord::{LatLonRad, ScreenCoord, TileCoord, View};
4
 use coord::{LatLonRad, ScreenCoord, TileCoord, View};
6
 use map_view::MapView;
5
 use map_view::MapView;
6
+use orthografic_view::OrthograficView;
7
 use program::Program;
7
 use program::Program;
8
+use std::ffi::CStr;
8
 use tile_atlas::TileAtlas;
9
 use tile_atlas::TileAtlas;
9
 use tile_cache::TileCache;
10
 use tile_cache::TileCache;
10
 use tile_source::TileSource;
11
 use tile_source::TileSource;
12
 
13
 
13
 
14
 
14
 #[derive(Debug)]
15
 #[derive(Debug)]
15
-pub struct GlobeTileLayer {
16
+pub struct OrthoTileLayer {
16
     program: Program,
17
     program: Program,
17
     buffer: Buffer,
18
     buffer: Buffer,
18
 }
19
 }
27
 }
28
 }
28
 
29
 
29
 impl LatScreenEllipse {
30
 impl LatScreenEllipse {
30
-    fn new(view_center: LatLonRad, viewport_size: (u32, u32), globe_radius: f64, lat: f64) -> Self {
31
+    fn new(view_center: LatLonRad, viewport_size: (u32, u32), sphere_radius: f64, lat: f64) -> Self {
31
         LatScreenEllipse {
32
         LatScreenEllipse {
32
             center: ScreenCoord {
33
             center: ScreenCoord {
33
                 x: viewport_size.0 as f64 * 0.5,
34
                 x: viewport_size.0 as f64 * 0.5,
34
-                y: viewport_size.1 as f64 * 0.5 * (lat - view_center.lat).sin() * globe_radius,
35
+                y: viewport_size.1 as f64 * 0.5 * (lat - view_center.lat).sin() * sphere_radius,
35
             },
36
             },
36
-            radius_x: lat.cos() * globe_radius,
37
-            radius_y: lat.cos() * -view_center.lat.sin() * globe_radius,
37
+            radius_x: lat.cos() * sphere_radius,
38
+            radius_y: lat.cos() * -view_center.lat.sin() * sphere_radius,
38
             ref_angle: view_center.lon,
39
             ref_angle: view_center.lon,
39
         }
40
         }
40
     }
41
     }
41
 }
42
 }
42
 
43
 
43
 
44
 
44
-impl GlobeTileLayer {
45
+impl OrthoTileLayer {
45
     pub fn new(
46
     pub fn new(
46
         cx: &mut Context,
47
         cx: &mut Context,
47
-    ) -> GlobeTileLayer
48
+    ) -> OrthoTileLayer
48
     {
49
     {
49
         let buffer = Buffer::new(cx, &[], 0);
50
         let buffer = Buffer::new(cx, &[], 0);
50
         check_gl_errors!(cx);
51
         check_gl_errors!(cx);
52
 
53
 
53
         let mut program = Program::new(
54
         let mut program = Program::new(
54
             cx,
55
             cx,
55
-            include_bytes!("../shader/globe_tile.vert"),
56
-            include_bytes!("../shader/globe_tile.frag"),
56
+            include_bytes!("../shader/ortho_tile.vert"),
57
+            include_bytes!("../shader/ortho_tile.frag"),
57
         ).unwrap();
58
         ).unwrap();
58
         check_gl_errors!(cx);
59
         check_gl_errors!(cx);
59
 
60
 
74
         );
75
         );
75
         check_gl_errors!(cx);
76
         check_gl_errors!(cx);
76
 
77
 
77
-        GlobeTileLayer {
78
+        OrthoTileLayer {
78
             program,
79
             program,
79
             buffer,
80
             buffer,
80
         }
81
         }
98
         //TODO Add distance function to TileCache that takes topology of the sphere into account.
99
         //TODO Add distance function to TileCache that takes topology of the sphere into account.
99
         cache.set_view_location(View {
100
         cache.set_view_location(View {
100
             source_id: source.id(),
101
             source_id: source.id(),
101
-            zoom: map_view.tile_zoom(),
102
+            zoom: OrthograficView::tile_zoom(map_view),
102
             center: map_view.center,
103
             center: map_view.center,
103
         });
104
         });
104
 
105
 
105
         let mut vertex_data = vec![];
106
         let mut vertex_data = vec![];
106
 
107
 
107
-        let transform = map_view.globe_transformation_matrix();
108
+        let transform = OrthograficView::transformation_matrix(map_view);
108
 
109
 
109
         let (inset_x, inset_y) = tile_atlas.texture_margins();
110
         let (inset_x, inset_y) = tile_atlas.texture_margins();
110
 
111
 
111
-        for tile_coord in map_view.visible_globe_tiles().into_iter() {
112
+        for tile_coord in OrthograficView::visible_tiles(map_view).into_iter() {
112
             let slot = tile_atlas.store(cx, tile_coord, source, cache, true)
113
             let slot = tile_atlas.store(cx, tile_coord, source, cache, true)
113
                 .unwrap_or_else(TileAtlas::default_slot);
114
                 .unwrap_or_else(TileAtlas::default_slot);
114
             let texrect = tile_atlas.slot_to_texture_rect(slot);
115
             let texrect = tile_atlas.slot_to_texture_rect(slot);

+ 177
- 0
src/orthografic_view.rs 查看文件

1
+use cgmath::{Matrix3, Point3, Transform, vec3};
2
+use coord::TileCoord;
3
+use map_view::MapView;
4
+use std::f32::consts::{PI, FRAC_1_PI};
5
+use std::f64;
6
+
7
+
8
+#[derive(Clone, Debug)]
9
+pub struct OrthograficView {
10
+}
11
+
12
+impl OrthograficView {
13
+    /// Returns true if the rendering covers the whole viewport.
14
+    pub fn covers_viewport(map_view: &MapView) -> bool {
15
+        //TODO Add a little safety margin since the rendered globe is not a perfect sphere and its
16
+        // screen area is underestimated by the tesselation.
17
+        let sphere_diameter = 2.0f64.powf(map_view.zoom) *
18
+            (f64::consts::FRAC_1_PI * map_view.tile_size as f64);
19
+
20
+        return map_view.width.hypot(map_view.height) < sphere_diameter;
21
+    }
22
+
23
+    /// Returns the tile zoom value that is used for rendering with the current zoom.
24
+    //TODO Insert real implementation. Add TileCoord parameter -> lower resolution at the poles
25
+    pub fn tile_zoom(map_view: &MapView) -> u32 {
26
+        (map_view.zoom + map_view.tile_zoom_offset).floor().max(0.0) as u32
27
+    }
28
+
29
+    //TODO Return the transformation matrix that is used here to avoid redundant calculation.
30
+    /// Returns a `Vec` of all tiles that are visible in the current viewport.
31
+    pub fn visible_tiles(map_view: &MapView) -> Vec<TileCoord> {
32
+        let uzoom = Self::tile_zoom(map_view);
33
+
34
+        match uzoom {
35
+            0 => return vec![TileCoord::new(0, 0, 0)],
36
+            1 => {
37
+                // return every tile
38
+                return vec![
39
+                    TileCoord::new(1, 0, 0),
40
+                    TileCoord::new(1, 0, 1),
41
+                    TileCoord::new(1, 1, 0),
42
+                    TileCoord::new(1, 1, 1),
43
+                ]},
44
+            _ => {},
45
+        }
46
+
47
+        let center_tile = map_view.center.on_tile_at_zoom(uzoom).globe_norm();
48
+
49
+        let transform = Self::transformation_matrix(map_view);
50
+
51
+        let add_tile_if_visible = |tc: TileCoord, vec: &mut Vec<TileCoord>| -> bool {
52
+            let test_point = tc.latlon_rad_north_west().to_sphere_point3();
53
+            let test_point = transform.transform_point(test_point);
54
+
55
+            let visible = test_point.x >= -1.0 && test_point.x <= 1.0 &&
56
+                test_point.y >= -1.0 && test_point.y <= 1.0;
57
+
58
+            if visible {
59
+                vec.push(tc);
60
+                true
61
+            } else {
62
+                false
63
+            }
64
+        };
65
+
66
+        let mut tiles = vec![];
67
+
68
+        {
69
+            let zoom_level_tiles = TileCoord::get_zoom_level_tiles(uzoom);
70
+
71
+            for dx in 0..(zoom_level_tiles / 2) {
72
+                let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x + dx, center_tile.y), &mut tiles);
73
+                if !v {
74
+                    break;
75
+                }
76
+            }
77
+            for dx in 1..(1 + zoom_level_tiles / 2) {
78
+                let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x - dx, center_tile.y), &mut tiles);
79
+                if !v {
80
+                    break;
81
+                }
82
+            }
83
+
84
+            // move south
85
+            for y in (center_tile.y + 1)..zoom_level_tiles {
86
+                let mut visible = false;
87
+
88
+                for dx in 0..(zoom_level_tiles / 2) {
89
+                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x + dx, y), &mut tiles);
90
+                    visible = visible || v;
91
+                    if !v {
92
+                        break;
93
+                    }
94
+                }
95
+                for dx in 1..(1 + zoom_level_tiles / 2) {
96
+                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x - dx, y), &mut tiles);
97
+                    visible = visible || v;
98
+                    if !v {
99
+                        break;
100
+                    }
101
+                }
102
+
103
+                if !visible {
104
+                    break;
105
+                }
106
+            }
107
+
108
+            // move north
109
+            for y in (0..center_tile.y).rev() {
110
+                let mut visible = false;
111
+
112
+                for dx in 0..(zoom_level_tiles / 2) {
113
+                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x + dx, y), &mut tiles);
114
+                    visible = visible || v;
115
+                    if !v {
116
+                        break;
117
+                    }
118
+                }
119
+                for dx in 1..(1 + zoom_level_tiles / 2) {
120
+                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x - dx, y), &mut tiles);
121
+                    visible = visible || v;
122
+                    if !v {
123
+                        break;
124
+                    }
125
+                }
126
+
127
+                if !visible {
128
+                    break;
129
+                }
130
+            }
131
+        }
132
+
133
+        tiles
134
+    }
135
+
136
+    pub fn transformation_matrix(map_view: &MapView) -> Matrix3<f32> {
137
+        let (scale_x, scale_y) = {
138
+            let factor = 2.0f32.powf(map_view.zoom as f32) *
139
+                (FRAC_1_PI * map_view.tile_size as f32);
140
+            (factor / map_view.width as f32, factor / map_view.height as f32)
141
+        };
142
+
143
+        let scale_mat: Matrix3<f32> = Matrix3::from_cols(
144
+            vec3(scale_x, 0.0, 0.0),
145
+            vec3(0.0, scale_y, 0.0),
146
+            vec3(0.0, 0.0, 1.0),
147
+        );
148
+
149
+        let rot_mat_x: Matrix3<f32> = {
150
+            let center_latlon = map_view.center.to_latlon_rad();
151
+            let alpha = center_latlon.lon as f32 + (PI * 0.5);
152
+            let cosa = alpha.cos();
153
+            let sina = alpha.sin();
154
+                Matrix3::from_cols(
155
+                vec3(cosa, 0.0, -sina),
156
+                vec3(0.0, 1.0, 0.0),
157
+                vec3(sina, 0.0, cosa),
158
+            )
159
+        };
160
+
161
+        let rot_mat_y: Matrix3<f32> = {
162
+            let center_latlon = map_view.center.to_latlon_rad();
163
+            let alpha = (-center_latlon.lat) as f32;
164
+            let cosa = alpha.cos();
165
+            let sina = alpha.sin();
166
+                Matrix3::from_cols(
167
+                vec3(1.0, 0.0, 0.0),
168
+                vec3(0.0, cosa, sina),
169
+                vec3(0.0, -sina, cosa),
170
+            )
171
+        };
172
+
173
+        let transform = Transform::<Point3<f32>>::concat(&rot_mat_y, &rot_mat_x);
174
+        let transform = Transform::<Point3<f32>>::concat(&scale_mat, &transform);
175
+        transform
176
+    }
177
+}

+ 1
- 1
src/tile_atlas.rs 查看文件

2
 use coord::{ScreenRect, SubTileCoord, TileCoord, TextureRect};
2
 use coord::{ScreenRect, SubTileCoord, TileCoord, TextureRect};
3
 use image;
3
 use image;
4
 use linked_hash_map::LinkedHashMap;
4
 use linked_hash_map::LinkedHashMap;
5
-use map_view::VisibleTile;
5
+use mercator_view::VisibleTile;
6
 use std::collections::HashMap;
6
 use std::collections::HashMap;
7
 use std::collections::hash_map::Entry;
7
 use std::collections::hash_map::Entry;
8
 use texture::Texture;
8
 use texture::Texture;

+ 3
- 2
src/tile_layer.rs 查看文件

3
 use context::Context;
3
 use context::Context;
4
 use coord::View;
4
 use coord::View;
5
 use map_view::MapView;
5
 use map_view::MapView;
6
+use mercator_view::MercatorView;
6
 use program::Program;
7
 use program::Program;
7
 use tile_atlas::TileAtlas;
8
 use tile_atlas::TileAtlas;
8
 use tile_cache::TileCache;
9
 use tile_cache::TileCache;
79
     ) -> Result<usize, usize> {
80
     ) -> Result<usize, usize> {
80
         cache.set_view_location(View {
81
         cache.set_view_location(View {
81
             source_id: source.id(),
82
             source_id: source.id(),
82
-            zoom: map_view.tile_zoom(),
83
+            zoom: MercatorView::tile_zoom(map_view),
83
             center: map_view.center,
84
             center: map_view.center,
84
         });
85
         });
85
 
86
 
86
-        let visible_tiles = map_view.visible_tiles(snap_to_pixel);
87
+        let visible_tiles = MercatorView::visible_tiles(map_view, snap_to_pixel);
87
         let mut remainder = visible_tiles.as_slice();
88
         let mut remainder = visible_tiles.as_slice();
88
         let mut num_draws = 0;
89
         let mut num_draws = 0;
89
         let mut max_tiles_to_use = cache.max_tiles();
90
         let mut max_tiles_to_use = cache.max_tiles();