浏览代码

Remove map_view

Move functionality to orthografic_view and mercator_view.
Johannes Hofmann 7 年前
父节点
当前提交
f484a3193d
共有 11 个文件被更改,包括 507 次插入345 次删除
  1. 3
    4
      src/atmos_layer.rs
  2. 4
    4
      src/main.rs
  3. 0
    79
      src/map_view.rs
  4. 106
    75
      src/map_view_gl.rs
  5. 15
    16
      src/marker_layer.rs
  6. 6
    7
      src/mercator_tile_layer.rs
  7. 150
    59
      src/mercator_view.rs
  8. 5
    6
      src/ortho_tile_layer.rs
  9. 156
    37
      src/orthografic_view.rs
  10. 27
    0
      src/projection_view.rs
  11. 35
    58
      src/session.rs

+ 3
- 4
src/atmos_layer.rs 查看文件

@@ -1,7 +1,6 @@
1 1
 use ::std::ffi::CStr;
2 2
 use buffer::{Buffer, DrawMode};
3 3
 use context::Context;
4
-use map_view::MapView;
5 4
 use orthografic_view::OrthograficView;
6 5
 use program::{Program, UniformId};
7 6
 use std::f32::consts::PI;
@@ -67,11 +66,11 @@ impl AtmosLayer {
67 66
     pub fn draw(
68 67
         &mut self,
69 68
         cx: &mut Context,
70
-        map_view: &MapView,
69
+        ortho: &OrthograficView,
71 70
     ) {
72 71
         let (scale_x, scale_y) = {
73
-            let diam = OrthograficView::diameter_physical_pixels(map_view);
74
-            ((diam / map_view.width) as f32, (diam / map_view.height) as f32)
72
+            let diam = ortho.diameter_physical_pixels();
73
+            ((diam / ortho.viewport_size.x) as f32, (diam / ortho.viewport_size.y) as f32)
75 74
         };
76 75
 
77 76
         self.program.set_uniform_2f(cx, self.scale_uniform, scale_x, scale_y);

+ 4
- 4
src/main.rs 查看文件

@@ -27,7 +27,6 @@ pub mod atmos_layer;
27 27
 pub mod buffer;
28 28
 pub mod config;
29 29
 pub mod coord;
30
-pub mod map_view;
31 30
 pub mod map_view_gl;
32 31
 pub mod marker_layer;
33 32
 pub mod mercator_tile_layer;
@@ -36,6 +35,7 @@ pub mod ortho_tile_layer;
36 35
 pub mod orthografic_view;
37 36
 pub mod program;
38 37
 pub mod projection;
38
+pub mod projection_view;
39 39
 pub mod query;
40 40
 pub mod search;
41 41
 pub mod session;
@@ -283,7 +283,7 @@ fn run() -> Result<(), Box<Error>> {
283 283
         None
284 284
     };
285 285
 
286
-    if let Some(tile_source) = last_session.as_ref().and_then(|s| s.tile_source.as_ref()) {
286
+    if let Some(tile_source) = last_session.as_ref().and_then(|s| s.tile_source()) {
287 287
         sources.switch_to_name(tile_source);
288 288
     }
289 289
 
@@ -319,7 +319,7 @@ fn run() -> Result<(), Box<Error>> {
319 319
     };
320 320
 
321 321
     if let Some(ref session) = last_session {
322
-        map.restore_session(session);
322
+        map.restore_session(session)?;
323 323
     }
324 324
 
325 325
     let (marker_tx, marker_rx) = mpsc::channel();
@@ -463,7 +463,7 @@ fn run() -> Result<(), Box<Error>> {
463 463
 
464 464
     if config.open_last_session() {
465 465
         let mut session = map.to_session();
466
-        session.tile_source = Some(sources.current_name().to_string());
466
+        session.set_tile_source(Some(sources.current_name()));
467 467
         config::save_session(&session)?;
468 468
     }
469 469
 

+ 0
- 79
src/map_view.rs 查看文件

@@ -1,79 +0,0 @@
1
-use coord::MapCoord;
2
-
3
-
4
-pub const MIN_ZOOM_LEVEL: f64 = 0.0;
5
-pub const MAX_ZOOM_LEVEL: f64 = 22.0;
6
-
7
-/// A view of a map with a rectangular viewport and a zoom.
8
-#[derive(Clone, Debug)]
9
-pub struct MapView {
10
-    /// Width of the viewport.
11
-    pub width: f64,
12
-    /// Height of the viewport.
13
-    pub height: f64,
14
-    /// Size of each square tile in the same unit as the viewport dimensions (usually pixels).
15
-    pub tile_size: u32,
16
-    /// The `MapCoord` that corresponds to the center of the viewport.
17
-    pub center: MapCoord,
18
-    /// The zoom value. The zoom factor is given by 2.0.powf(zoom);
19
-    pub zoom: f64,
20
-    /// Tiles only exist for integer zoom values. The tile zoom value that is used for rendering
21
-    /// is computed by the `tile_zoom` method. Increasing `tile_zoom_offset` increases the number
22
-    /// of visible tiles for a given zoom value.
23
-    pub tile_zoom_offset: f64,
24
-}
25
-
26
-impl MapView {
27
-    /// Constructs a new `MapView`.
28
-    pub fn new(width: f64, height: f64, tile_size: u32, center: MapCoord, zoom: f64) -> MapView {
29
-        MapView {
30
-            width,
31
-            height,
32
-            tile_size,
33
-            center,
34
-            zoom,
35
-            tile_zoom_offset: 0.0,
36
-        }
37
-    }
38
-
39
-    /// Returns the tile zoom offset.
40
-    pub fn tile_zoom_offset(map_view: &MapView) -> f64 {
41
-        map_view.tile_zoom_offset
42
-    }
43
-
44
-    /// Set the tile zoom offset.
45
-    pub fn set_tile_zoom_offset(&mut self, offset: f64) {
46
-        self.tile_zoom_offset = offset;
47
-    }
48
-
49
-    /// Set the viewport size.
50
-    pub fn set_size(&mut self, width: f64, height: f64) {
51
-        self.width = width;
52
-        self.height = height;
53
-    }
54
-
55
-    /// Set the zoom value.
56
-    pub fn set_zoom(&mut self, zoom: f64) {
57
-        self.zoom = zoom
58
-            .max(MIN_ZOOM_LEVEL)
59
-            .min(MAX_ZOOM_LEVEL);
60
-    }
61
-
62
-    /// Change zoom value by `zoom_delta`.
63
-    pub fn zoom(&mut self, zoom_delta: f64) {
64
-        self.zoom = (self.zoom + zoom_delta)
65
-            .max(MIN_ZOOM_LEVEL)
66
-            .min(MAX_ZOOM_LEVEL);
67
-    }
68
-
69
-    pub fn step_zoom(&mut self, steps: i32, step_size: f64) {
70
-        self.zoom = {
71
-            let z = (self.zoom + f64::from(steps) * step_size) / step_size;
72
-            if steps > 0 {
73
-                z.ceil() * step_size
74
-            } else {
75
-                z.floor() * step_size
76
-            }
77
-        }.max(MIN_ZOOM_LEVEL).min(MAX_ZOOM_LEVEL);
78
-    }
79
-}

+ 106
- 75
src/map_view_gl.rs 查看文件

@@ -1,13 +1,14 @@
1 1
 use atmos_layer::AtmosLayer;
2
+use cgmath::vec2;
2 3
 use context::Context;
3 4
 use coord::{MapCoord, ScreenCoord};
4
-use map_view::{MapView, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL};
5 5
 use marker_layer::MarkerLayer;
6 6
 use mercator_tile_layer::MercatorTileLayer;
7 7
 use mercator_view::MercatorView;
8 8
 use ortho_tile_layer::OrthoTileLayer;
9 9
 use orthografic_view::OrthograficView;
10 10
 use projection::Projection;
11
+use projection_view::ProjectionView;
11 12
 use session::Session;
12 13
 use texture::{Texture, TextureFormat};
13 14
 use tile_atlas::TileAtlas;
@@ -15,9 +16,12 @@ use tile_cache::TileCache;
15 16
 use tile_source::TileSource;
16 17
 
17 18
 
19
+pub const MIN_TILE_ZOOM_OFFSET: f64 = -4.0;
20
+pub const MAX_TILE_ZOOM_OFFSET: f64 = 4.0;
21
+
18 22
 #[derive(Debug)]
19 23
 pub struct MapViewGl {
20
-    map_view: MapView,
24
+    proj_view: ProjectionView,
21 25
     /// Size in physical pixels
22 26
     viewport_size: (u32, u32),
23 27
     dpi_factor: f64,
@@ -27,7 +31,6 @@ pub struct MapViewGl {
27 31
     marker_layer: MarkerLayer,
28 32
     ortho_tile_layer: OrthoTileLayer,
29 33
     atmos_layer: AtmosLayer,
30
-    projection: Projection,
31 34
     show_marker: bool,
32 35
     show_atmos: bool,
33 36
     last_draw_type: DrawType,
@@ -55,10 +58,12 @@ impl MapViewGl {
55 58
     {
56 59
         let tile_size = 256;
57 60
 
58
-        let map_view = MercatorView::initial_map_view(
59
-            f64::from(initial_size.0),
60
-            f64::from(initial_size.1),
61
-            tile_size,
61
+        let proj_view = ProjectionView::Mercator(
62
+            MercatorView::initial_view(
63
+                f64::from(initial_size.0),
64
+                f64::from(initial_size.1),
65
+                tile_size,
66
+            )
62 67
         );
63 68
 
64 69
         let atlas_size = {
@@ -85,7 +90,7 @@ impl MapViewGl {
85 90
         let atmos_layer = AtmosLayer::new(cx);
86 91
 
87 92
         MapViewGl {
88
-            map_view,
93
+            proj_view,
89 94
             viewport_size: initial_size,
90 95
             dpi_factor,
91 96
             tile_cache: TileCache::new(move |_tile| update_func(), use_network),
@@ -94,7 +99,6 @@ impl MapViewGl {
94 99
             marker_layer: MarkerLayer::new(cx),
95 100
             ortho_tile_layer,
96 101
             atmos_layer,
97
-            projection: Projection::Mercator,
98 102
             show_marker: true,
99 103
             show_atmos: false,
100 104
             last_draw_type: DrawType::Null,
@@ -103,7 +107,11 @@ impl MapViewGl {
103 107
 
104 108
     pub fn set_viewport_size(&mut self, cx: &mut Context, width: u32, height: u32) {
105 109
         self.viewport_size = (width, height);
106
-        self.map_view.set_size(f64::from(width), f64::from(height));
110
+        let vec_size = vec2(f64::from(width), f64::from(height));
111
+        match &mut self.proj_view {
112
+            ProjectionView::Mercator(merc) => merc.viewport_size = vec_size,
113
+            ProjectionView::Orthografic(ortho) => ortho.viewport_size = vec_size,
114
+        }
107 115
         cx.set_viewport(0, 0, width, height);
108 116
     }
109 117
 
@@ -116,9 +124,9 @@ impl MapViewGl {
116 124
     }
117 125
 
118 126
     pub fn map_covers_viewport(&self) -> bool {
119
-        match self.projection {
120
-            Projection::Mercator => MercatorView::covers_viewport(&self.map_view),
121
-            Projection::Orthografic => OrthograficView::covers_viewport(&self.map_view),
127
+        match &self.proj_view {
128
+            ProjectionView::Mercator(ref merc) => merc.covers_viewport(),
129
+            ProjectionView::Orthografic(ref ortho) => ortho.covers_viewport(),
122 130
         }
123 131
     }
124 132
 
@@ -127,9 +135,11 @@ impl MapViewGl {
127 135
     }
128 136
 
129 137
     pub fn toggle_projection(&mut self) {
130
-        self.projection = match self.projection {
131
-            Projection::Mercator => Projection::Orthografic,
132
-            Projection::Orthografic => Projection::Mercator,
138
+        self.proj_view = match &self.proj_view {
139
+            ProjectionView::Orthografic(ortho) =>
140
+                ProjectionView::Mercator(MercatorView::from_orthografic_view(ortho)),
141
+            ProjectionView::Mercator(merc) =>
142
+                ProjectionView::Orthografic(OrthograficView::from_mercator_view(merc)),
133 143
         };
134 144
     }
135 145
 
@@ -141,7 +151,7 @@ impl MapViewGl {
141 151
         self.show_atmos = !self.show_atmos;
142 152
     }
143 153
 
144
-    fn draw_mercator_tiles(&mut self, cx: &mut Context, source: &TileSource, snap_to_pixel: bool)
154
+    fn draw_mercator_tiles(&mut self, cx: &mut Context, merc: &MercatorView, source: &TileSource, snap_to_pixel: bool)
145 155
         -> Result<usize, usize>
146 156
     {
147 157
         if self.last_draw_type != DrawType::Tiles {
@@ -151,7 +161,7 @@ impl MapViewGl {
151 161
 
152 162
         self.mercator_tile_layer.draw(
153 163
             cx,
154
-            &self.map_view,
164
+            merc,
155 165
             source,
156 166
             &mut self.tile_cache,
157 167
             &mut self.tile_atlas,
@@ -159,7 +169,7 @@ impl MapViewGl {
159 169
         )
160 170
     }
161 171
 
162
-    fn draw_mercator_marker(&mut self, cx: &mut Context, snap_to_pixel: bool) {
172
+    fn draw_mercator_marker(&mut self, cx: &mut Context, merc: &MercatorView, snap_to_pixel: bool) {
163 173
         if self.last_draw_type != DrawType::Markers {
164 174
             self.last_draw_type = DrawType::Markers;
165 175
             self.marker_layer.prepare_draw(cx);
@@ -167,13 +177,13 @@ impl MapViewGl {
167 177
 
168 178
         self.marker_layer.draw_mercator(
169 179
             cx,
170
-            &self.map_view,
180
+            merc,
171 181
             self.dpi_factor,
172 182
             snap_to_pixel,
173 183
         );
174 184
     }
175 185
 
176
-    fn draw_ortho_marker(&mut self, cx: &mut Context) {
186
+    fn draw_ortho_marker(&mut self, cx: &mut Context, ortho: &OrthograficView) {
177 187
         if self.last_draw_type != DrawType::Markers {
178 188
             self.last_draw_type = DrawType::Markers;
179 189
             self.marker_layer.prepare_draw(cx);
@@ -181,12 +191,12 @@ impl MapViewGl {
181 191
 
182 192
         self.marker_layer.draw_ortho(
183 193
             cx,
184
-            &self.map_view,
194
+            ortho,
185 195
             self.dpi_factor,
186 196
         );
187 197
     }
188 198
 
189
-    fn draw_ortho_tiles(&mut self, cx: &mut Context, source: &TileSource) -> Result<usize, usize> {
199
+    fn draw_ortho_tiles(&mut self, cx: &mut Context, ortho: &OrthograficView, source: &TileSource) -> Result<usize, usize> {
190 200
         if self.last_draw_type != DrawType::OrthoTiles {
191 201
             self.last_draw_type = DrawType::OrthoTiles;
192 202
             self.ortho_tile_layer.prepare_draw(cx, &self.tile_atlas);
@@ -194,14 +204,14 @@ impl MapViewGl {
194 204
 
195 205
         self.ortho_tile_layer.draw(
196 206
             cx,
197
-            &self.map_view,
207
+            ortho,
198 208
             source,
199 209
             &mut self.tile_cache,
200 210
             &mut self.tile_atlas,
201 211
         )
202 212
     }
203 213
 
204
-    fn draw_atmos(&mut self, cx: &mut Context) {
214
+    fn draw_atmos(&mut self, cx: &mut Context, ortho: &OrthograficView) {
205 215
         if self.last_draw_type != DrawType::Atmos {
206 216
             self.last_draw_type = DrawType::Atmos;
207 217
             self.atmos_layer.prepare_draw(cx);
@@ -209,7 +219,7 @@ impl MapViewGl {
209 219
 
210 220
         self.atmos_layer.draw(
211 221
             cx,
212
-            &self.map_view,
222
+            ortho,
213 223
         )
214 224
     }
215 225
 
@@ -217,89 +227,110 @@ impl MapViewGl {
217 227
     /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
218 228
     /// size of the tile atlas.
219 229
     pub fn draw(&mut self, cx: &mut Context, source: &TileSource) -> Result<usize, usize> {
220
-        // only snap to pixel grid if zoom has integral value
221
-        let snap_to_pixel = (self.map_view.zoom - (self.map_view.zoom + 0.5).floor()).abs() < 1e-10;
230
+        match self.proj_view.clone() {
231
+            ProjectionView::Mercator(ref merc) => {
232
+                // only snap to pixel grid if zoom has integral value
233
+                let snap_to_pixel = (merc.zoom - (merc.zoom + 0.5).floor()).abs() < 1e-10;
222 234
 
223
-        match self.projection {
224
-            Projection::Mercator => {
225
-                let ret = self.draw_mercator_tiles(cx, source, snap_to_pixel);
235
+                let ret = self.draw_mercator_tiles(cx, merc, source, snap_to_pixel);
226 236
                 if self.show_marker && !self.marker_layer.is_empty() {
227
-                    self.draw_mercator_marker(cx, snap_to_pixel);
237
+                    self.draw_mercator_marker(cx, merc, snap_to_pixel);
228 238
                 }
229 239
                 ret
230 240
             },
231
-            Projection::Orthografic => {
232
-                let ret = self.draw_ortho_tiles(cx, source);
241
+            ProjectionView::Orthografic(ref ortho) => {
242
+                let ret = self.draw_ortho_tiles(cx, ortho, source);
233 243
                 if self.show_marker && !self.marker_layer.is_empty() {
234
-                    self.draw_ortho_marker(cx);
244
+                    self.draw_ortho_marker(cx, ortho);
235 245
                 }
236 246
                 if self.show_atmos {
237
-                    self.draw_atmos(cx);
247
+                    self.draw_atmos(cx, ortho);
238 248
                 }
239 249
                 ret
240 250
             },
241 251
         }
242 252
     }
243 253
 
244
-    pub fn zoom(&mut self, zoom_delta: f64) {
245
-        self.map_view.zoom(zoom_delta);
246
-    }
247
-
248 254
     pub fn step_zoom(&mut self, steps: i32, step_size: f64) {
249
-        self.map_view.step_zoom(steps, step_size);
255
+        match &mut self.proj_view {
256
+            ProjectionView::Mercator(merc) => {
257
+                merc.step_zoom(steps, step_size);
258
+            },
259
+            ProjectionView::Orthografic(ortho) => {
260
+                ortho.step_zoom(steps, step_size);
261
+            },
262
+        }
250 263
     }
251 264
 
252 265
     pub fn zoom_at(&mut self, pos: ScreenCoord, zoom_delta: f64) {
253
-        match self.projection {
254
-            Projection::Mercator => {
255
-                if self.map_view.zoom + zoom_delta < MIN_ZOOM_LEVEL {
256
-                    MercatorView::set_zoom_at(&mut self.map_view, pos, MIN_ZOOM_LEVEL);
257
-                } else if self.map_view.zoom + zoom_delta > MAX_ZOOM_LEVEL {
258
-                    MercatorView::set_zoom_at(&mut self.map_view, pos, MAX_ZOOM_LEVEL);
259
-                } else {
260
-                    MercatorView::zoom_at(&mut self.map_view, pos, zoom_delta);
261
-                }
262
-                self.map_view.center.normalize_xy();
266
+        match &mut self.proj_view {
267
+            ProjectionView::Mercator(merc) => {
268
+                merc.zoom_at(pos, zoom_delta)
263 269
             },
264
-            Projection::Orthografic => {
265
-                if self.map_view.zoom + zoom_delta < MIN_ZOOM_LEVEL {
266
-                    OrthograficView::set_zoom_at(&mut self.map_view, pos, MIN_ZOOM_LEVEL);
267
-                } else if self.map_view.zoom + zoom_delta > MAX_ZOOM_LEVEL {
268
-                    OrthograficView::set_zoom_at(&mut self.map_view, pos, MAX_ZOOM_LEVEL);
269
-                } else {
270
-                    OrthograficView::zoom_at(&mut self.map_view, pos, zoom_delta);
271
-                }
270
+            ProjectionView::Orthografic(ortho) => {
271
+                ortho.zoom_at(pos, zoom_delta)
272 272
             },
273 273
         }
274 274
     }
275 275
 
276 276
     pub fn change_tile_zoom_offset(&mut self, delta_offset: f64) {
277
-        let offset = self.map_view.tile_zoom_offset;
278
-        self.map_view.set_tile_zoom_offset(offset + delta_offset);
277
+        match &mut self.proj_view {
278
+            ProjectionView::Mercator(merc) => {
279
+                merc.tile_zoom_offset = (merc.tile_zoom_offset + delta_offset)
280
+                    .max(MIN_TILE_ZOOM_OFFSET)
281
+                    .min(MAX_TILE_ZOOM_OFFSET);
282
+            },
283
+            ProjectionView::Orthografic(ortho) => {
284
+                ortho.tile_zoom_offset = (ortho.tile_zoom_offset + delta_offset)
285
+                    .max(MIN_TILE_ZOOM_OFFSET)
286
+                    .min(MAX_TILE_ZOOM_OFFSET);
287
+            },
288
+        }
279 289
     }
280 290
 
281 291
     //TODO Make sure to use physical pixel deltas
282 292
     pub fn move_pixel(&mut self, delta_x: f64, delta_y: f64) {
283
-        //TODO implement for OrthograficView
284
-        MercatorView::move_pixel(&mut self.map_view, delta_x, delta_y);
285
-        self.map_view.center.normalize_xy();
293
+        match &mut self.proj_view {
294
+            ProjectionView::Mercator(merc) => {
295
+                merc.move_pixel(delta_x, delta_y);
296
+            },
297
+            ProjectionView::Orthografic(ortho) => {
298
+                ortho.move_pixel(delta_x, delta_y);
299
+            },
300
+        }
286 301
     }
287 302
 
288
-    pub fn restore_session(&mut self, session: &Session) {
289
-        self.map_view.center = session.view_center;
290
-        self.map_view.center.normalize_xy();
291
-        self.map_view.zoom = session.zoom
292
-            .max(MIN_ZOOM_LEVEL)
293
-            .min(MAX_ZOOM_LEVEL);
294
-        self.projection = session.projection;
303
+    pub fn restore_session(&mut self, session: &Session) -> Result<(), String> {
304
+        let viewport_size = self.proj_view.viewport_size();
305
+        let tile_size = self.proj_view.tile_size();
306
+        match session.projection() {
307
+            Some(Projection::Mercator) => {
308
+                self.proj_view = ProjectionView::Mercator(
309
+                    MercatorView::from_toml_table(&session.view, viewport_size, tile_size)?
310
+                )
311
+            },
312
+            Some(Projection::Orthografic) => {
313
+                self.proj_view = ProjectionView::Orthografic(
314
+                    OrthograficView::from_toml_table(&session.view, viewport_size, tile_size)?
315
+                )
316
+            },
317
+            None => {},
318
+        }
319
+        Ok(())
295 320
     }
296 321
 
297 322
     pub fn to_session(&self) -> Session {
323
+        let view = match &self.proj_view {
324
+            ProjectionView::Mercator(merc) => {
325
+                merc.toml_table()
326
+            },
327
+            ProjectionView::Orthografic(ortho) => {
328
+                ortho.toml_table()
329
+            },
330
+        };
331
+
298 332
         Session {
299
-            view_center: self.map_view.center,
300
-            zoom: self.map_view.zoom,
301
-            tile_source: None,
302
-            projection: self.projection,
333
+            view,
303 334
         }
304 335
     }
305 336
 }

+ 15
- 16
src/marker_layer.rs 查看文件

@@ -4,7 +4,6 @@ use cgmath::{Matrix3, Point2, Transform, vec2, vec3};
4 4
 use context::Context;
5 5
 use coord::{MapCoord, ScreenCoord, ScreenRect};
6 6
 use image;
7
-use map_view::MapView;
8 7
 use mercator_view::MercatorView;
9 8
 use orthografic_view::OrthograficView;
10 9
 use program::Program;
@@ -79,7 +78,7 @@ impl MarkerLayer {
79 78
     pub fn draw_mercator(
80 79
         &mut self,
81 80
         cx: &mut Context,
82
-        map_view: &MapView,
81
+        merc: &MercatorView,
83 82
         dpi_factor: f64,
84 83
         snap_to_pixel: bool
85 84
     ) {
@@ -88,8 +87,8 @@ impl MarkerLayer {
88 87
         let marker_size = vec2::<f64>(40.0, 50.0) * dpi_factor;
89 88
         let marker_offset = vec2::<f64>(-20.0, -50.0) * dpi_factor;
90 89
 
91
-        let scale_x = 2.0 / map_view.width as f32;
92
-        let scale_y = -2.0 / map_view.height as f32;
90
+        let scale_x = 2.0 / merc.viewport_size.x as f32;
91
+        let scale_y = -2.0 / merc.viewport_size.y as f32;
93 92
 
94 93
         let tex_mat: Matrix3<f32> = Matrix3::from_cols(
95 94
             vec3(marker_size.x as f32, 0.0, 0.0),
@@ -111,15 +110,15 @@ impl MarkerLayer {
111 110
         let visible_rect = ScreenRect {
112 111
             x: -(marker_offset.x + marker_size.x),
113 112
             y: -(marker_offset.y + marker_size.y),
114
-            width: map_view.width + marker_size.x,
115
-            height: map_view.height + marker_size.y,
113
+            width: merc.viewport_size.x + marker_size.x,
114
+            height: merc.viewport_size.y + marker_size.y,
116 115
         };
117 116
 
118 117
         for map_pos in &self.positions {
119 118
             let screen_pos = {
120
-                let mut sp = MercatorView::map_to_screen_coord(map_view, *map_pos);
119
+                let mut sp = merc.map_to_screen_coord(*map_pos);
121 120
                 if snap_to_pixel {
122
-                    let topleft = MercatorView::map_to_screen_coord(map_view, MapCoord::new(0.0, 0.0));
121
+                    let topleft = merc.map_to_screen_coord(MapCoord::new(0.0, 0.0));
123 122
                     let mut snapped = topleft;
124 123
                     snapped.snap_to_pixel();
125 124
 
@@ -166,7 +165,7 @@ impl MarkerLayer {
166 165
     pub fn draw_ortho(
167 166
         &mut self,
168 167
         cx: &mut Context,
169
-        map_view: &MapView,
168
+        ortho: &OrthograficView,
170 169
         dpi_factor: f64,
171 170
     ) {
172 171
         let mut vertex_data: Vec<f32> = vec![];
@@ -174,8 +173,8 @@ impl MarkerLayer {
174 173
         let marker_size = vec2::<f64>(40.0, 50.0) * dpi_factor;
175 174
         let marker_offset = vec2::<f64>(-20.0, -50.0) * dpi_factor;
176 175
 
177
-        let scale_x = 2.0 / map_view.width as f32;
178
-        let scale_y = -2.0 / map_view.height as f32;
176
+        let scale_x = 2.0 / ortho.viewport_size.x as f32;
177
+        let scale_y = -2.0 / ortho.viewport_size.y as f32;
179 178
 
180 179
         let tex_mat: Matrix3<f32> = Matrix3::from_cols(
181 180
             vec3(marker_size.x as f32, 0.0, 0.0),
@@ -197,11 +196,11 @@ impl MarkerLayer {
197 196
         let visible_rect = ScreenRect {
198 197
             x: -(marker_offset.x + marker_size.x),
199 198
             y: -(marker_offset.y + marker_size.y),
200
-            width: map_view.width + marker_size.x,
201
-            height: map_view.height + marker_size.y,
199
+            width: ortho.viewport_size.x + marker_size.x,
200
+            height: ortho.viewport_size.y + marker_size.y,
202 201
         };
203 202
 
204
-        let transform = OrthograficView::transformation_matrix(map_view);
203
+        let transform = ortho.transformation_matrix();
205 204
 
206 205
         for map_pos in &self.positions {
207 206
             let screen_pos = {
@@ -212,8 +211,8 @@ impl MarkerLayer {
212 211
                 }
213 212
 
214 213
                 ScreenCoord::new(
215
-                    (norm_pos.x + 1.0) * (0.5 * map_view.width),
216
-                    (-norm_pos.y + 1.0) * (0.5 * map_view.height),
214
+                    (norm_pos.x + 1.0) * (0.5 * ortho.viewport_size.x),
215
+                    (-norm_pos.y + 1.0) * (0.5 * ortho.viewport_size.y),
217 216
                 )
218 217
             };
219 218
 

+ 6
- 7
src/mercator_tile_layer.rs 查看文件

@@ -2,7 +2,6 @@ use ::std::ffi::CStr;
2 2
 use buffer::{Buffer, DrawMode};
3 3
 use context::Context;
4 4
 use coord::View;
5
-use map_view::MapView;
6 5
 use mercator_view::MercatorView;
7 6
 use program::Program;
8 7
 use tile_atlas::{TileAtlas, VisibleTilesProvider};
@@ -68,7 +67,7 @@ impl MercatorTileLayer {
68 67
     pub fn draw(
69 68
         &mut self,
70 69
         cx: &mut Context,
71
-        map_view: &MapView,
70
+        merc: &MercatorView,
72 71
         source: &TileSource,
73 72
         cache: &mut TileCache,
74 73
         atlas: &mut TileAtlas,
@@ -76,11 +75,11 @@ impl MercatorTileLayer {
76 75
     ) -> Result<usize, usize> {
77 76
         cache.set_view_location(View {
78 77
             source_id: source.id(),
79
-            zoom: MercatorView::tile_zoom(map_view),
80
-            center: map_view.center,
78
+            zoom: merc.tile_zoom(),
79
+            center: merc.center,
81 80
         });
82 81
 
83
-        let visible_tiles = MercatorView::visible_tiles(map_view, snap_to_pixel);
82
+        let visible_tiles = merc.visible_tiles(snap_to_pixel);
84 83
         let mut remainder = visible_tiles.as_slice();
85 84
         let mut num_draws = 0;
86 85
         let mut max_tiles_to_use = cache.max_tiles();
@@ -99,8 +98,8 @@ impl MercatorTileLayer {
99 98
             max_tiles_to_use = max_tiles_to_use.saturating_sub(used_tiles);
100 99
 
101 100
             let mut vertex_data: Vec<f32> = Vec::with_capacity(textured_visible_tiles.len() * (6 * 8));
102
-            let scale_x = 2.0 / map_view.width;
103
-            let scale_y = -2.0 / map_view.height;
101
+            let scale_x = 2.0 / merc.viewport_size.x;
102
+            let scale_y = -2.0 / merc.viewport_size.y;
104 103
             for tvt in &textured_visible_tiles {
105 104
                 let minmax = [
106 105
                     tvt.tex_minmax.x1 as f32,

+ 150
- 59
src/mercator_view.rs 查看文件

@@ -1,10 +1,30 @@
1
+use cgmath::{vec2, Vector2};
1 2
 use coord::{MapCoord, ScreenCoord, ScreenRect, TextureRect, TileCoord};
2
-use map_view::{MapView, MIN_ZOOM_LEVEL, MAX_ZOOM_LEVEL};
3
+use orthografic_view::OrthograficView;
4
+use projection::Projection;
5
+use toml::Value;
6
+use toml::value::Table;
3 7
 
4 8
 
9
+pub const MIN_ZOOM_LEVEL: f64 = 0.0;
10
+pub const MAX_ZOOM_LEVEL: f64 = 22.0;
11
+
5 12
 /// A view of a tiled map with a rectangular viewport and a zoom.
13
+/// Projection: EPSG:3857: WGS 84 / Pseudo-Mercator
6 14
 #[derive(Clone, Debug)]
7 15
 pub struct MercatorView {
16
+    /// Size of the viewport in physical pixels.
17
+    pub viewport_size: Vector2<f64>,
18
+    /// Size of each square tile in the same unit as the viewport dimensions.
19
+    pub tile_size: u32,
20
+    /// The `MapCoord` that corresponds to the center of the viewport.
21
+    pub center: MapCoord,
22
+    /// The zoom value. The zoom factor is given by 2.0.powf(zoom);
23
+    pub zoom: f64,
24
+    /// Tiles only exist for integer zoom values. The tile zoom value that is used for rendering
25
+    /// is computed by the `tile_zoom` method. Increasing `tile_zoom_offset` increases the number
26
+    /// of visible tiles for a given zoom value.
27
+    pub tile_zoom_offset: f64,
8 28
 }
9 29
 
10 30
 /// The position and size of a specific tile on the screen.
@@ -25,14 +45,13 @@ pub struct TexturedVisibleTile {
25 45
 impl MercatorView {
26 46
     /// Constructs a `MapView` centered at Null Island with an integer zoom that fills a screen
27 47
     /// with the given dimensions.
28
-    pub fn initial_map_view(width: f64, height: f64, tile_size: u32) -> MapView {
48
+    pub fn initial_view(width: f64, height: f64, tile_size: u32) -> MercatorView {
29 49
         let min_dimension = width.min(height);
30 50
         let zoom = (min_dimension / f64::from(tile_size)).log2().ceil()
31 51
             .max(MIN_ZOOM_LEVEL)
32 52
             .min(MAX_ZOOM_LEVEL);
33
-        MapView {
34
-            width,
35
-            height,
53
+        MercatorView {
54
+            viewport_size: vec2(width, height),
36 55
             tile_size,
37 56
             center: MapCoord::new(0.5, 0.5),
38 57
             zoom,
@@ -40,39 +59,103 @@ impl MercatorView {
40 59
         }
41 60
     }
42 61
 
62
+    pub fn from_orthografic_view(ortho: &OrthograficView) -> Self {
63
+        MercatorView {
64
+            viewport_size: ortho.viewport_size,
65
+            tile_size: ortho.tile_size,
66
+            center: ortho.center,
67
+            zoom: ortho.zoom,
68
+            tile_zoom_offset: ortho.tile_zoom_offset,
69
+        }
70
+    }
71
+
72
+    pub fn from_toml_table(
73
+        table: &Table,
74
+        viewport_size: Vector2<f64>,
75
+        tile_size: u32,
76
+    ) -> Result<Self, String> {
77
+        let x = match table.get("x") {
78
+            Some(&Value::Float(x)) => x,
79
+            Some(&Value::Integer(x)) => x as f64,
80
+            Some(_) => return Err("x has to be a number.".to_string()),
81
+            None => return Err("x position is missing.".to_string()),
82
+        };
83
+
84
+        let y = match table.get("y") {
85
+            Some(&Value::Float(y)) => y,
86
+            Some(&Value::Integer(y)) => y as f64,
87
+            Some(_) => return Err("y has to be a number.".to_string()),
88
+            None => return Err("y position is missing.".to_string()),
89
+        };
90
+
91
+        let zoom = match table.get("zoom") {
92
+            Some(&Value::Float(z)) => z,
93
+            Some(&Value::Integer(z)) => z as f64,
94
+            Some(_) => return Err("zoom has to be a number.".to_string()),
95
+            None => return Err("zoom value is missing.".to_string()),
96
+        }.min(MAX_ZOOM_LEVEL).max(MIN_ZOOM_LEVEL);
97
+
98
+        if let Some(&Value::String(ref s)) = table.get("projection") {
99
+            if s != "mercator" {
100
+                return Err("try to deserialize wrong projection".to_string());
101
+            }
102
+        }
103
+
104
+        Ok(MercatorView {
105
+            viewport_size,
106
+            tile_size,
107
+            center: MapCoord::new(x, y),
108
+            zoom,
109
+            tile_zoom_offset: 0.0,
110
+        })
111
+    }
112
+
113
+    pub fn toml_table(&self) -> Table {
114
+        let mut table = Table::new();
115
+        table.insert("projection".to_string(), Value::String(Self::projection().to_str().to_string()));
116
+        table.insert("x".to_string(), Value::Float(self.center.x));
117
+        table.insert("y".to_string(), Value::Float(self.center.y));
118
+        table.insert("zoom".to_string(), Value::Float(self.zoom));
119
+        table
120
+    }
121
+
122
+    pub fn projection() -> Projection {
123
+        Projection::Mercator
124
+    }
125
+
43 126
     /// Returns the map coordinate that corresponds to the top-left corner of the viewport.
44
-    pub fn top_left_coord(map_view: &MapView) -> MapCoord {
45
-        let scale = f64::powf(2.0, -map_view.zoom) / f64::from(map_view.tile_size);
127
+    pub fn top_left_coord(&self) -> MapCoord {
128
+        let scale = f64::powf(2.0, -self.zoom) / f64::from(self.tile_size);
46 129
 
47
-        let x = map_view.center.x + -0.5 * map_view.width * scale;
48
-        let y = map_view.center.y + -0.5 * map_view.height * scale;
130
+        let x = self.center.x + -0.5 * self.viewport_size.x * scale;
131
+        let y = self.center.y + -0.5 * self.viewport_size.y * scale;
49 132
 
50 133
         MapCoord::new(x, y)
51 134
     }
52 135
 
53 136
     /// Returns the screen coordinate that corresponds to the given map coordinate.
54
-    pub fn map_to_screen_coord(map_view: &MapView, map_coord: MapCoord) -> ScreenCoord {
55
-        let scale = f64::powf(2.0, map_view.zoom) * f64::from(map_view.tile_size);
137
+    pub fn map_to_screen_coord(&self, map_coord: MapCoord) -> ScreenCoord {
138
+        let scale = f64::powf(2.0, self.zoom) * f64::from(self.tile_size);
56 139
 
57
-        let delta_x = map_coord.x - map_view.center.x;
58
-        let delta_y = map_coord.y - map_view.center.y;
140
+        let delta_x = map_coord.x - self.center.x;
141
+        let delta_y = map_coord.y - self.center.y;
59 142
 
60 143
         ScreenCoord {
61
-            x: 0.5 * map_view.width + delta_x * scale,
62
-            y: 0.5 * map_view.height + delta_y * scale,
144
+            x: 0.5 * self.viewport_size.x + delta_x * scale,
145
+            y: 0.5 * self.viewport_size.y + delta_y * scale,
63 146
         }
64 147
     }
65 148
 
66 149
     /// Returns the map coordinate that corresponds to the given screen coordinate.
67
-    pub fn screen_to_map_coord(map_view: &MapView, screen_coord: ScreenCoord) -> MapCoord {
68
-        let scale = f64::powf(2.0, -map_view.zoom) / f64::from(map_view.tile_size);
150
+    pub fn screen_to_map_coord(&self, screen_coord: ScreenCoord) -> MapCoord {
151
+        let scale = f64::powf(2.0, -self.zoom) / f64::from(self.tile_size);
69 152
 
70
-        let delta_x = screen_coord.x - map_view.width * 0.5;
71
-        let delta_y = screen_coord.y - map_view.height * 0.5;
153
+        let delta_x = screen_coord.x - self.viewport_size.x * 0.5;
154
+        let delta_y = screen_coord.y - self.viewport_size.y * 0.5;
72 155
 
73 156
         let mut m = MapCoord {
74
-            x: map_view.center.x + delta_x * scale,
75
-            y: map_view.center.y + delta_y * scale,
157
+            x: self.center.x + delta_x * scale,
158
+            y: self.center.y + delta_y * scale,
76 159
         };
77 160
 
78 161
         m.normalize_x();
@@ -80,27 +163,27 @@ impl MercatorView {
80 163
     }
81 164
 
82 165
     /// Returns true if the viewport rectangle is fully inside the map.
83
-    pub fn covers_viewport(map_view: &MapView) -> bool {
84
-        let scale = f64::powf(2.0, -map_view.zoom) / f64::from(map_view.tile_size);
166
+    pub fn covers_viewport(&self) -> bool {
167
+        let scale = f64::powf(2.0, -self.zoom) / f64::from(self.tile_size);
85 168
 
86
-        let y_top = map_view.center.y + -0.5 * map_view.height * scale;
87
-        let y_bottom = map_view.center.y + 0.5 * map_view.height * scale;
169
+        let y_top = self.center.y + -0.5 * self.viewport_size.x * scale;
170
+        let y_bottom = self.center.y + 0.5 * self.viewport_size.y * scale;
88 171
 
89 172
         y_top >= 0.0 && y_bottom <= 1.0
90 173
     }
91 174
 
92 175
     /// Returns the screen coordinate of the top-left corner of a tile.
93
-    pub fn tile_screen_position(map_view: &MapView, tile: &TileCoord) -> ScreenCoord {
94
-        Self::map_to_screen_coord(map_view, tile.map_coord_north_west())
176
+    pub fn tile_screen_position(&self, tile: &TileCoord) -> ScreenCoord {
177
+        self.map_to_screen_coord(tile.map_coord_north_west())
95 178
     }
96 179
 
97 180
     /// Returns a `Vec` of all tiles that are visible in the current viewport.
98
-    pub fn visible_tiles(map_view: &MapView, snap_to_pixel: bool) -> Vec<VisibleTile> {
99
-        let uzoom = Self::tile_zoom(map_view);
100
-        let top_left_tile = Self::top_left_coord(map_view).on_tile_at_zoom(uzoom);
101
-        let mut top_left_tile_screen_coord = Self::tile_screen_position(map_view, &top_left_tile);
102
-        let tile_screen_size = f64::powf(2.0, map_view.zoom - f64::from(uzoom)) *
103
-            f64::from(map_view.tile_size);
181
+    pub fn visible_tiles(&self, snap_to_pixel: bool) -> Vec<VisibleTile> {
182
+        let uzoom = self.tile_zoom();
183
+        let top_left_tile = self.top_left_coord().on_tile_at_zoom(uzoom);
184
+        let mut top_left_tile_screen_coord = self.tile_screen_position(&top_left_tile);
185
+        let tile_screen_size = f64::powf(2.0, self.zoom - f64::from(uzoom)) *
186
+            f64::from(self.tile_size);
104 187
 
105 188
         if snap_to_pixel {
106 189
             top_left_tile_screen_coord.snap_to_pixel();
@@ -108,9 +191,9 @@ impl MercatorView {
108 191
 
109 192
         let start_tile_x = top_left_tile.x;
110 193
         let start_tile_y = top_left_tile.y;
111
-        let num_tiles_x = ((map_view.width - top_left_tile_screen_coord.x) /
194
+        let num_tiles_x = ((self.viewport_size.x - top_left_tile_screen_coord.x) /
112 195
                            tile_screen_size).ceil().max(0.0) as i32;
113
-        let num_tiles_y = ((map_view.height - top_left_tile_screen_coord.y) /
196
+        let num_tiles_y = ((self.viewport_size.y - top_left_tile_screen_coord.y) /
114 197
                            tile_screen_size).ceil().max(0.0) as i32;
115 198
 
116 199
         let mut visible_tiles = Vec::with_capacity(num_tiles_x as usize * num_tiles_y as usize);
@@ -138,40 +221,48 @@ impl MercatorView {
138 221
     }
139 222
 
140 223
     /// Returns the tile zoom value that is used for rendering with the current zoom.
141
-    pub fn tile_zoom(map_view: &MapView) -> u32 {
142
-        (map_view.zoom + map_view.tile_zoom_offset).floor().max(0.0) as u32
224
+    pub fn tile_zoom(&self) -> u32 {
225
+        (self.zoom + self.tile_zoom_offset).floor().max(0.0) as u32
143 226
     }
144 227
 
145 228
     /// Change zoom value by `zoom_delta` and zoom to a position given in screen coordinates.
146
-    pub fn zoom_at(map_view: &mut MapView, pos: ScreenCoord, zoom_delta: f64) {
147
-        let delta_x = pos.x - map_view.width * 0.5;
148
-        let delta_y = pos.y - map_view.height * 0.5;
149
-
150
-        let scale = (f64::powf(2.0, -map_view.zoom) - f64::powf(2.0, -map_view.zoom - zoom_delta))
151
-            / f64::from(map_view.tile_size);
152
-
153
-        map_view.zoom += zoom_delta;
154
-        map_view.center.x += delta_x * scale;
155
-        map_view.center.y += delta_y * scale;
229
+    pub fn zoom_at(&mut self, pos: ScreenCoord, zoom_delta: f64) {
230
+        let new_zoom = self.zoom + zoom_delta;
231
+        self.set_zoom_at(pos, new_zoom);
156 232
     }
157 233
 
158 234
     /// Set a zoom value and zoom to a `position` given in screen coordinates.
159
-    pub fn set_zoom_at(map_view: &mut MapView, pos: ScreenCoord, zoom: f64) {
160
-        let delta_x = pos.x - map_view.width * 0.5;
161
-        let delta_y = pos.y - map_view.height * 0.5;
235
+    pub fn set_zoom_at(&mut self, pos: ScreenCoord, new_zoom: f64) {
236
+        let new_zoom = new_zoom.min(MAX_ZOOM_LEVEL).max(MIN_ZOOM_LEVEL);
237
+
238
+        let delta_x = pos.x - self.viewport_size.x * 0.5;
239
+        let delta_y = pos.y - self.viewport_size.y * 0.5;
162 240
 
163
-        let scale = (f64::powf(2.0, -map_view.zoom) - f64::powf(2.0, -zoom)) /
164
-            f64::from(map_view.tile_size);
241
+        let scale = (f64::powf(2.0, -self.zoom) - f64::powf(2.0, -new_zoom)) /
242
+            f64::from(self.tile_size);
165 243
 
166
-        map_view.zoom = zoom;
167
-        map_view.center.x += delta_x * scale;
168
-        map_view.center.y += delta_y * scale;
244
+        self.zoom = new_zoom;
245
+        self.center.x += delta_x * scale;
246
+        self.center.y += delta_y * scale;
247
+        self.center.normalize_xy();
248
+    }
249
+
250
+    pub fn step_zoom(&mut self, steps: i32, step_size: f64) {
251
+        self.zoom = {
252
+            let z = (self.zoom + f64::from(steps) * step_size) / step_size;
253
+            if steps > 0 {
254
+                z.ceil() * step_size
255
+            } else {
256
+                z.floor() * step_size
257
+            }
258
+        }.max(MIN_ZOOM_LEVEL).min(MAX_ZOOM_LEVEL);
169 259
     }
170 260
 
171 261
     /// Move the center of the viewport by (`delta_x`, `delta_y`) in screen coordinates.
172
-    pub fn move_pixel(map_view: &mut MapView, delta_x: f64, delta_y: f64) {
173
-        let scale = f64::powf(2.0, -map_view.zoom) / f64::from(map_view.tile_size);
174
-        map_view.center.x += delta_x * scale;
175
-        map_view.center.y += delta_y * scale;
262
+    pub fn move_pixel(&mut self, delta_x: f64, delta_y: f64) {
263
+        let scale = f64::powf(2.0, -self.zoom) / f64::from(self.tile_size);
264
+        self.center.x += delta_x * scale;
265
+        self.center.y += delta_y * scale;
266
+        self.center.normalize_xy();
176 267
     }
177 268
 }

+ 5
- 6
src/ortho_tile_layer.rs 查看文件

@@ -2,7 +2,6 @@ use buffer::{Buffer, DrawMode};
2 2
 use cgmath::Transform;
3 3
 use context::Context;
4 4
 use coord::{LatLonRad, ScreenCoord, View};
5
-use map_view::MapView;
6 5
 use orthografic_view::OrthograficView;
7 6
 use program::Program;
8 7
 use std::ffi::CStr;
@@ -91,7 +90,7 @@ impl OrthoTileLayer {
91 90
     pub fn draw(
92 91
         &mut self,
93 92
         cx: &mut Context,
94
-        map_view: &MapView,
93
+        ortho: &OrthograficView,
95 94
         source: &TileSource,
96 95
         cache: &mut TileCache,
97 96
         tile_atlas: &mut TileAtlas,
@@ -99,13 +98,13 @@ impl OrthoTileLayer {
99 98
         //TODO Add distance function to TileCache that takes topology of the sphere into account.
100 99
         cache.set_view_location(View {
101 100
             source_id: source.id(),
102
-            zoom: OrthograficView::tile_zoom(map_view),
103
-            center: map_view.center,
101
+            zoom: ortho.tile_zoom(),
102
+            center: ortho.center,
104 103
         });
105 104
 
106
-        let transform = OrthograficView::transformation_matrix(map_view);
105
+        let transform = ortho.transformation_matrix();
107 106
 
108
-        let visible_tiles = OrthograficView::visible_tiles(map_view);
107
+        let visible_tiles = ortho.visible_tiles();
109 108
         let mut remainder = visible_tiles.as_slice();
110 109
         let mut num_draws = 0;
111 110
         let mut max_tiles_to_use = cache.max_tiles();

+ 156
- 37
src/orthografic_view.rs 查看文件

@@ -1,11 +1,17 @@
1
-use cgmath::{Matrix3, Point3, Transform, vec3};
2
-use coord::{LatLonRad, ScreenCoord, TextureRect, TileCoord};
3
-use map_view::MapView;
1
+use cgmath::{Matrix3, Point3, Transform, vec3, Vector2};
2
+use coord::{LatLonRad, MapCoord, ScreenCoord, TextureRect, TileCoord};
3
+use mercator_view::MercatorView;
4
+use projection::Projection;
4 5
 use std::collections::HashSet;
5 6
 use std::f64::consts::{PI, FRAC_1_PI};
6 7
 use std::f64;
8
+use toml::Value;
9
+use toml::value::Table;
7 10
 
8 11
 
12
+pub const MIN_ZOOM_LEVEL: f64 = 0.0;
13
+pub const MAX_ZOOM_LEVEL: f64 = 22.0;
14
+
9 15
 #[derive(Clone, Debug)]
10 16
 pub struct VisibleTile {
11 17
     pub tile: TileCoord,
@@ -136,31 +142,124 @@ pub fn tile_neighbors(origin: TileCoord, result: &mut Vec<TileNeighbor>) {
136 142
 }
137 143
 
138 144
 
145
+/// Orthographic projection, WGS 84 coordinates mapped to the sphere
139 146
 #[derive(Clone, Debug)]
140 147
 pub struct OrthograficView {
148
+    /// Size of the viewport in physical pixels.
149
+    pub viewport_size: Vector2<f64>,
150
+    /// Size of each square tile in the same unit as the viewport dimensions.
151
+    pub tile_size: u32,
152
+    /// The `MapCoord` that corresponds to the center of the viewport.
153
+    pub center: MapCoord,
154
+    /// The zoom value. The zoom factor is given by 2.0.powf(zoom);
155
+    pub zoom: f64,
156
+    /// Tiles only exist for integer zoom values. The tile zoom value that is used for rendering
157
+    /// is computed by the `tile_zoom` method. Increasing `tile_zoom_offset` increases the number
158
+    /// of visible tiles for a given zoom value.
159
+    pub tile_zoom_offset: f64,
141 160
 }
142 161
 
143 162
 impl OrthograficView {
163
+    /// Constructs a new `OrthograficView`.
164
+    pub fn new(
165
+        viewport_size: Vector2<f64>,
166
+        tile_size: u32,
167
+        center: MapCoord,
168
+        zoom: f64
169
+    ) -> OrthograficView {
170
+        OrthograficView {
171
+            viewport_size,
172
+            tile_size,
173
+            center,
174
+            zoom,
175
+            tile_zoom_offset: 0.0,
176
+        }
177
+    }
178
+
179
+    pub fn from_mercator_view(merc: &MercatorView) -> Self {
180
+        OrthograficView {
181
+            viewport_size: merc.viewport_size,
182
+            tile_size: merc.tile_size,
183
+            center: merc.center,
184
+            zoom: merc.zoom,
185
+            tile_zoom_offset: merc.tile_zoom_offset,
186
+        }
187
+    }
188
+
189
+    pub fn from_toml_table(
190
+        table: &Table,
191
+        viewport_size: Vector2<f64>,
192
+        tile_size: u32,
193
+    ) -> Result<Self, String> {
194
+        let x = match table.get("x") {
195
+            Some(&Value::Float(x)) => x,
196
+            Some(&Value::Integer(x)) => x as f64,
197
+            Some(_) => return Err("x has to be a number.".to_string()),
198
+            None => return Err("x position is missing.".to_string()),
199
+        };
200
+
201
+        let y = match table.get("y") {
202
+            Some(&Value::Float(y)) => y,
203
+            Some(&Value::Integer(y)) => y as f64,
204
+            Some(_) => return Err("y has to be a number.".to_string()),
205
+            None => return Err("y position is missing.".to_string()),
206
+        };
207
+
208
+        let zoom = match table.get("zoom") {
209
+            Some(&Value::Float(z)) => z,
210
+            Some(&Value::Integer(z)) => z as f64,
211
+            Some(_) => return Err("zoom has to be a number.".to_string()),
212
+            None => return Err("zoom value is missing.".to_string()),
213
+        }.min(MAX_ZOOM_LEVEL).max(MIN_ZOOM_LEVEL);
214
+
215
+        if let Some(&Value::String(ref s)) = table.get("projection") {
216
+            if s != "orthografic" {
217
+                return Err("try to deserialize wrong projection".to_string());
218
+            }
219
+        }
220
+
221
+        Ok(OrthograficView {
222
+            viewport_size,
223
+            tile_size,
224
+            center: MapCoord::new(x, y),
225
+            zoom,
226
+            tile_zoom_offset: 0.0,
227
+        })
228
+    }
229
+
230
+    pub fn toml_table(&self) -> Table {
231
+        let mut table = Table::new();
232
+        table.insert("projection".to_string(), Value::String(Self::projection().to_str().to_string()));
233
+        table.insert("x".to_string(), Value::Float(self.center.x));
234
+        table.insert("y".to_string(), Value::Float(self.center.y));
235
+        table.insert("zoom".to_string(), Value::Float(self.zoom));
236
+        table
237
+    }
238
+
239
+    pub fn projection() -> Projection {
240
+        Projection::Orthografic
241
+    }
242
+
144 243
     /// Returns true if the rendering covers the whole viewport.
145
-    pub fn covers_viewport(map_view: &MapView) -> bool {
146
-        let sphere_diameter = 2.0f64.powf(map_view.zoom) *
147
-            (f64::consts::FRAC_1_PI * f64::from(map_view.tile_size));
244
+    pub fn covers_viewport(&self) -> bool {
245
+        let sphere_diameter = 2.0f64.powf(self.zoom) *
246
+            (f64::consts::FRAC_1_PI * f64::from(self.tile_size));
148 247
 
149 248
         // Add a little safety margin (the constant factor) since the rendered globe is not a
150 249
         // perfect sphere and its screen area is underestimated by the tesselation.
151
-        map_view.width.hypot(map_view.height) < sphere_diameter * 0.9
250
+        self.viewport_size.x.hypot(self.viewport_size.y) < sphere_diameter * 0.9
152 251
     }
153 252
 
154 253
     /// Returns the tile zoom value that is used for rendering with the current zoom.
155 254
     //TODO Insert real implementation. Add TileCoord parameter -> lower resolution at the poles
156
-    pub fn tile_zoom(map_view: &MapView) -> u32 {
157
-        (map_view.zoom + map_view.tile_zoom_offset).floor().max(0.0) as u32
255
+    pub fn tile_zoom(&self) -> u32 {
256
+        (self.zoom + self.tile_zoom_offset).floor().max(0.0) as u32
158 257
     }
159 258
 
160 259
     //TODO Return the transformation matrix that is used here to avoid redundant calculation.
161 260
     /// Returns a `Vec` of all tiles that are visible in the current viewport.
162
-    pub fn visible_tiles(map_view: &MapView) -> Vec<VisibleTile> {
163
-        let uzoom = Self::tile_zoom(map_view);
261
+    pub fn visible_tiles(&self) -> Vec<VisibleTile> {
262
+        let uzoom = self.tile_zoom();
164 263
 
165 264
         match uzoom {
166 265
             0 => return vec![TileCoord::new(0, 0, 0).into()],
@@ -175,9 +274,9 @@ impl OrthograficView {
175 274
             _ => {},
176 275
         }
177 276
 
178
-        let center_tile = map_view.center.on_tile_at_zoom(uzoom).nearest_valid();
277
+        let center_tile = self.center.on_tile_at_zoom(uzoom).nearest_valid();
179 278
 
180
-        let transform = Self::transformation_matrix(map_view);
279
+        let transform = self.transformation_matrix();
181 280
 
182 281
         let tile_is_visible = |tc: TileCoord| -> bool {
183 282
             let nw = tc.latlon_rad_north_west();
@@ -231,14 +330,14 @@ impl OrthograficView {
231 330
         tiles
232 331
     }
233 332
 
234
-    pub fn diameter_physical_pixels(map_view: &MapView) -> f64 {
235
-        2.0f64.powf(map_view.zoom) * (FRAC_1_PI * f64::from(map_view.tile_size))
333
+    pub fn diameter_physical_pixels(&self) -> f64 {
334
+        2.0f64.powf(self.zoom) * (FRAC_1_PI * f64::from(self.tile_size))
236 335
     }
237 336
 
238
-    pub fn transformation_matrix(map_view: &MapView) -> Matrix3<f64> {
337
+    pub fn transformation_matrix(&self) -> Matrix3<f64> {
239 338
         let (scale_x, scale_y) = {
240
-            let diam = Self::diameter_physical_pixels(map_view);
241
-            (diam / map_view.width, diam / map_view.height)
339
+            let diam = self.diameter_physical_pixels();
340
+            (diam / self.viewport_size.x, diam / self.viewport_size.y)
242 341
         };
243 342
 
244 343
         let scale_mat: Matrix3<f64> = Matrix3::from_cols(
@@ -247,7 +346,7 @@ impl OrthograficView {
247 346
             vec3(0.0, 0.0, 1.0),
248 347
         );
249 348
 
250
-        let center_latlon = map_view.center.to_latlon_rad();
349
+        let center_latlon = self.center.to_latlon_rad();
251 350
 
252 351
         let rot_mat_x: Matrix3<f64> = {
253 352
             let alpha = center_latlon.lon + (PI * 0.5);
@@ -278,8 +377,8 @@ impl OrthograficView {
278 377
     }
279 378
 
280 379
     // Returns the inverse rotation matrix of the given view.
281
-    pub fn inv_rotation_matrix(map_view: &MapView) -> Matrix3<f64> {
282
-        let center_latlon = map_view.center.to_latlon_rad();
380
+    pub fn inv_rotation_matrix(&self) -> Matrix3<f64> {
381
+        let center_latlon = self.center.to_latlon_rad();
283 382
 
284 383
         let rot_mat_x: Matrix3<f64> = {
285 384
             let alpha = -center_latlon.lon - (PI * 0.5);
@@ -307,12 +406,12 @@ impl OrthograficView {
307 406
     }
308 407
 
309 408
     // Returns the coordinates of the location that is nearest to the given `ScreenCoord`.
310
-    pub fn screen_coord_to_sphere_point(map_view: &MapView, screen_coord: ScreenCoord) -> Point3<f64> {
409
+    pub fn screen_coord_to_sphere_point(&self, screen_coord: ScreenCoord) -> Point3<f64> {
311 410
         // Point on unit sphere
312 411
         let sphere_point = {
313
-            let recip_radius = 2.0 * Self::diameter_physical_pixels(map_view).recip();
314
-            let sx = (screen_coord.x - map_view.width * 0.5) * recip_radius;
315
-            let sy = (screen_coord.y - map_view.height * 0.5) * -recip_radius;
412
+            let recip_radius = 2.0 * self.diameter_physical_pixels().recip();
413
+            let sx = (screen_coord.x - self.viewport_size.x * 0.5) * recip_radius;
414
+            let sy = (screen_coord.y - self.viewport_size.y * 0.5) * -recip_radius;
316 415
             let t = 1.0 - sx * sx - sy * sy;
317 416
             if t >= 0.0 {
318 417
                 // screen_coord is on the sphere
@@ -333,38 +432,58 @@ impl OrthograficView {
333 432
         };
334 433
 
335 434
         // Rotate
336
-        let inv_trans = Self::inv_rotation_matrix(map_view);
435
+        let inv_trans = self.inv_rotation_matrix();
337 436
         inv_trans.transform_point(sphere_point)
338 437
     }
339 438
 
340 439
     // Returns the coordinates of the location that is nearest to the given `ScreenCoord`.
341
-    pub fn screen_coord_to_latlonrad(map_view: &MapView, screen_coord: ScreenCoord) -> LatLonRad {
342
-        let p = Self::screen_coord_to_sphere_point(map_view, screen_coord);
440
+    pub fn screen_coord_to_latlonrad(&self, screen_coord: ScreenCoord) -> LatLonRad {
441
+        let p = self.screen_coord_to_sphere_point(screen_coord);
343 442
 
344 443
         // Transform to latitude, longitude
345 444
         LatLonRad::new(p.y.asin(), p.z.atan2(p.x))
346 445
     }
347 446
 
348 447
     /// Change zoom value by `zoom_delta` and zoom to a position given in screen coordinates.
349
-    pub fn zoom_at(map_view: &mut MapView, pos: ScreenCoord, zoom_delta: f64) {
448
+    pub fn zoom_at(&mut self, pos: ScreenCoord, zoom_delta: f64) {
350 449
         //TODO Do something sophisticated: Increase zoom and rotate slightly so that the given
351 450
         // ScreenCoord points to the same geographical location.
352 451
         /*
353
-        let latlon = Self::screen_coord_to_latlonrad(map_view, pos);
452
+        let latlon = self.screen_coord_to_latlonrad(pos);
354 453
 
355
-        let delta_x = pos.x - map_view.width * 0.5;
356
-        let delta_y = pos.y - map_view.height * 0.5;
454
+        let delta_x = pos.x - self.viewport_size.x * 0.5;
455
+        let delta_y = pos.y - self.viewport_size.y * 0.5;
357 456
 
358
-        map_view.center = latlon.into();
457
+        self.center = latlon.into();
359 458
         */
360 459
 
361
-        map_view.zoom += zoom_delta;
460
+        self.zoom = (self.zoom + zoom_delta).min(MAX_ZOOM_LEVEL).max(MIN_ZOOM_LEVEL);
362 461
     }
363 462
 
364 463
     /// Change zoom value by `zoom_delta` and zoom to a position given in screen coordinates.
365
-    pub fn set_zoom_at(map_view: &mut MapView, pos: ScreenCoord, zoom: f64) {
366
-        //TODO Do something sophisticated, just like with Self::zoom_at
367
-        map_view.zoom = zoom;
464
+    pub fn set_zoom_at(&mut self, pos: ScreenCoord, zoom: f64) {
465
+        //TODO Do something sophisticated
466
+        self.zoom = zoom.min(MAX_ZOOM_LEVEL).max(MIN_ZOOM_LEVEL);
467
+    }
468
+
469
+    pub fn step_zoom(&mut self, steps: i32, step_size: f64) {
470
+        self.zoom = {
471
+            let z = (self.zoom + f64::from(steps) * step_size) / step_size;
472
+            if steps > 0 {
473
+                z.ceil() * step_size
474
+            } else {
475
+                z.floor() * step_size
476
+            }
477
+        }.max(MIN_ZOOM_LEVEL).min(MAX_ZOOM_LEVEL);
478
+    }
479
+
480
+    /// Move the center of the viewport by approx. (`delta_x`, `delta_y`) in screen coordinates.
481
+    pub fn move_pixel(&mut self, delta_x: f64, delta_y: f64) {
482
+        //TODO Do something more sophisticated
483
+        let scale = f64::powf(2.0, -self.zoom) / f64::from(self.tile_size);
484
+        self.center.x += delta_x * scale;
485
+        self.center.y += delta_y * scale;
486
+        self.center.normalize_xy();
368 487
     }
369 488
 }
370 489
 

+ 27
- 0
src/projection_view.rs 查看文件

@@ -0,0 +1,27 @@
1
+use cgmath::Vector2;
2
+use mercator_view::MercatorView;
3
+use orthografic_view::OrthograficView;
4
+
5
+
6
+/// A view of the map with a specific projection.
7
+#[derive(Clone, Debug)]
8
+pub enum ProjectionView {
9
+    Mercator(MercatorView),
10
+    Orthografic(OrthograficView),
11
+}
12
+
13
+impl ProjectionView {
14
+    pub fn viewport_size(&self) -> Vector2<f64> {
15
+        match *self {
16
+            ProjectionView::Mercator(ref merc) => merc.viewport_size,
17
+            ProjectionView::Orthografic(ref ortho) => ortho.viewport_size,
18
+        }
19
+    }
20
+
21
+    pub fn tile_size(&self) -> u32 {
22
+        match *self {
23
+            ProjectionView::Mercator(ref merc) => merc.tile_size,
24
+            ProjectionView::Orthografic(ref ortho) => ortho.tile_size,
25
+        }
26
+    }
27
+}

+ 35
- 58
src/session.rs 查看文件

@@ -1,4 +1,3 @@
1
-use coord::MapCoord;
2 1
 use projection::Projection;
3 2
 use std::fs::File;
4 3
 use std::io::Read;
@@ -11,10 +10,7 @@ use toml;
11 10
 
12 11
 #[derive(Debug)]
13 12
 pub struct Session {
14
-    pub view_center: MapCoord,
15
-    pub zoom: f64,
16
-    pub tile_source: Option<String>,
17
-    pub projection: Projection,
13
+    pub view: Table,
18 14
 }
19 15
 
20 16
 impl Session {
@@ -29,55 +25,16 @@ impl Session {
29 25
 
30 26
     pub fn from_toml_str(toml_str: &str) -> Result<Session, String> {
31 27
         match toml_str.parse::<Value>() {
32
-            Ok(Value::Table(ref table)) => {
33
-
34
-                let view = match table.get("view") {
35
-                    Some(&Value::Table(ref table)) => table,
28
+            Ok(Value::Table(mut table)) => {
29
+                let view = match table.remove("view") {
30
+                    Some(Value::Table(table)) => table,
36 31
                     Some(_) => return Err("view has to be a table.".to_string()),
37 32
                     None => return Err("view table is missing.".to_string()),
38 33
                 };
39 34
 
40
-                let x = match view.get("x") {
41
-                    Some(&Value::Float(x)) => x,
42
-                    Some(&Value::Integer(x)) => x as f64,
43
-                    Some(_) => return Err("x has to be a number.".to_string()),
44
-                    None => return Err("x position is missing.".to_string()),
45
-                };
46
-
47
-                let y = match view.get("y") {
48
-                    Some(&Value::Float(y)) => y,
49
-                    Some(&Value::Integer(y)) => y as f64,
50
-                    Some(_) => return Err("y has to be a number.".to_string()),
51
-                    None => return Err("y position is missing.".to_string()),
52
-                };
53
-
54
-                let zoom = match view.get("zoom") {
55
-                    Some(&Value::Float(z)) => z,
56
-                    Some(&Value::Integer(z)) => z as f64,
57
-                    Some(_) => return Err("zoom has to be a number.".to_string()),
58
-                    None => return Err("zoom value is missing.".to_string()),
59
-                };
60
-
61
-                let tile_source = match view.get("tile_source") {
62
-                    Some(&Value::String(ref s)) => Some(s.clone()),
63
-                    Some(_) => return Err("tile_source has to be a string.".to_string()),
64
-                    None => None,
65
-                };
66
-
67
-                let projection = match view.get("projection") {
68
-                    Some(&Value::String(ref s)) => {
69
-                        Projection::from_str(s).unwrap_or_else(|_| Projection::Mercator)
70
-                    },
71
-                    Some(_) => return Err("projection has to be a string.".to_string()),
72
-                    None => Projection::Mercator,
73
-                };
74
-
75 35
                 Ok(
76 36
                     Session {
77
-                        view_center: MapCoord::new(x, y),
78
-                        zoom,
79
-                        tile_source,
80
-                        projection,
37
+                        view,
81 38
                     }
82 39
                 )
83 40
             },
@@ -87,18 +44,38 @@ impl Session {
87 44
     }
88 45
 
89 46
     pub fn to_toml_string(&self) -> String {
90
-        let mut view = Table::new();
91
-        view.insert("x".to_string(), Value::Float(self.view_center.x));
92
-        view.insert("y".to_string(), Value::Float(self.view_center.y));
93
-        view.insert("zoom".to_string(), Value::Float(self.zoom));
94
-        if let Some(ref tile_source) = self.tile_source {
95
-            view.insert("tile_source".to_string(), Value::String(tile_source.clone()));
96
-        }
97
-        view.insert("projection".to_string(), Value::String(self.projection.to_str().to_string()));
98
-
99 47
         let mut root = Table::new();
100
-        root.insert("view".to_string(), Value::Table(view));
48
+        root.insert("view".to_string(), Value::Table(self.view.clone()));
101 49
 
102 50
         toml::ser::to_string_pretty(&Value::Table(root)).unwrap()
103 51
     }
52
+
53
+    pub fn set_tile_source(&mut self, tile_source: Option<&str>) {
54
+        match tile_source {
55
+            None => {
56
+                self.view.remove("tile_source");
57
+            },
58
+            Some(tile_source) => {
59
+                self.view.insert(
60
+                    "tile_source".to_string(),
61
+                    Value::String(tile_source.to_string())
62
+                );
63
+            },
64
+        }
65
+    }
66
+
67
+    pub fn tile_source(&self) -> Option<&str> {
68
+        if let Some(Value::String(s)) = self.view.get("tile_source") {
69
+            Some(s.as_str())
70
+        } else {
71
+            None
72
+        }
73
+    }
74
+
75
+    pub fn projection(&self) -> Option<Projection> {
76
+        match self.view.get("projection") {
77
+            Some(Value::String(s)) => Projection::from_str(s.as_str()).ok(),
78
+            _ => None,
79
+        }
80
+    }
104 81
 }