Pārlūkot izejas kodu

Spherical tile visibility, part III

Still a partial solution. Uses region growing starting from the central
tile and checks if at least one of the vertices is visible.
Johannes Hofmann 7 gadus atpakaļ
vecāks
revīzija
cf5a195488
1 mainītis faili ar 49 papildinājumiem un 75 dzēšanām
  1. 49
    75
      src/orthografic_view.rs

+ 49
- 75
src/orthografic_view.rs Parādīt failu

@@ -1,11 +1,12 @@
1 1
 use cgmath::{Matrix3, Point3, Transform, vec3};
2
-use coord::TileCoord;
2
+use coord::{LatLonRad, TileCoord};
3 3
 use map_view::MapView;
4
+use std::collections::HashSet;
4 5
 use std::f32::consts::{PI, FRAC_1_PI};
5 6
 use std::f64;
6 7
 
7 8
 
8
-#[derive(Copy, Clone, Debug, PartialEq)]
9
+#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
9 10
 pub enum TileNeighbor {
10 11
     Coord(TileCoord),
11 12
     NorthPole,
@@ -137,85 +138,58 @@ impl OrthograficView {
137 138
 
138 139
         let transform = Self::transformation_matrix(map_view);
139 140
 
140
-        let add_tile_if_visible = |tc: TileCoord, vec: &mut Vec<TileCoord>| -> bool {
141
-            let test_point = tc.latlon_rad_north_west().to_sphere_point3();
142
-            let test_point = transform.transform_point(test_point);
143
-
144
-            let visible = test_point.x >= -1.0 && test_point.x <= 1.0 &&
145
-                test_point.y >= -1.0 && test_point.y <= 1.0;
141
+        let point_on_screen = |p: &Point3<f32>| {
142
+            p.x >= -1.0 && p.x <= 1.0 && p.y >= -1.0 && p.y <= 1.0
143
+        };
146 144
 
147
-            if visible {
148
-                vec.push(tc);
149
-                true
145
+        let tile_is_visible = |tc: TileCoord| -> bool {
146
+            let nw = tc.latlon_rad_north_west();
147
+            let se = tc.latlon_rad_south_east();
148
+            let vertices = [
149
+                transform.transform_point(nw.to_sphere_point3()),
150
+                transform.transform_point(se.to_sphere_point3()),
151
+                transform.transform_point(LatLonRad::new(nw.lat, se.lon).to_sphere_point3()),
152
+                transform.transform_point(LatLonRad::new(se.lat, nw.lon).to_sphere_point3()),
153
+            ];
154
+
155
+            if vertices.iter().all(|v| v.z > 0.0) {
156
+                // Tile is on the backside of the sphere
157
+                return false;
150 158
             } else {
151
-                false
159
+                return vertices.iter().any(&point_on_screen);
152 160
             }
153 161
         };
154 162
 
155
-        let mut tiles = vec![];
156
-
157
-        {
158
-            let zoom_level_tiles = TileCoord::get_zoom_level_tiles(uzoom);
159
-
160
-            for dx in 0..(zoom_level_tiles / 2) {
161
-                let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x + dx, center_tile.y), &mut tiles);
162
-                if !v {
163
-                    break;
164
-                }
165
-            }
166
-            for dx in 1..(1 + zoom_level_tiles / 2) {
167
-                let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x - dx, center_tile.y), &mut tiles);
168
-                if !v {
169
-                    break;
170
-                }
171
-            }
172
-
173
-            // move south
174
-            for y in (center_tile.y + 1)..zoom_level_tiles {
175
-                let mut visible = false;
176
-
177
-                for dx in 0..(zoom_level_tiles / 2) {
178
-                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x + dx, y), &mut tiles);
179
-                    visible = visible || v;
180
-                    if !v {
181
-                        break;
182
-                    }
183
-                }
184
-                for dx in 1..(1 + zoom_level_tiles / 2) {
185
-                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x - dx, y), &mut tiles);
186
-                    visible = visible || v;
187
-                    if !v {
188
-                        break;
189
-                    }
190
-                }
191
-
192
-                if !visible {
193
-                    break;
194
-                }
195
-            }
196
-
197
-            // move north
198
-            for y in (0..center_tile.y).rev() {
199
-                let mut visible = false;
200
-
201
-                for dx in 0..(zoom_level_tiles / 2) {
202
-                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x + dx, y), &mut tiles);
203
-                    visible = visible || v;
204
-                    if !v {
205
-                        break;
206
-                    }
207
-                }
208
-                for dx in 1..(1 + zoom_level_tiles / 2) {
209
-                    let v = add_tile_if_visible(TileCoord::new(uzoom, center_tile.x - dx, y), &mut tiles);
210
-                    visible = visible || v;
211
-                    if !v {
212
-                        break;
213
-                    }
214
-                }
215
-
216
-                if !visible {
217
-                    break;
163
+        let mut tiles = vec![center_tile];
164
+
165
+        let mut stack: Vec<TileNeighbor> = vec![];
166
+        tile_neighbors(center_tile, &mut stack);
167
+
168
+        let mut visited: HashSet<TileNeighbor> = HashSet::new();
169
+        visited.insert(TileNeighbor::Coord(center_tile));
170
+        visited.extend(stack.iter());
171
+
172
+        let mut neighbors = vec![];
173
+
174
+        loop {
175
+            if let Some(tn) = stack.pop() {
176
+                match tn {
177
+                    TileNeighbor::Coord(tc) => {
178
+                        if tile_is_visible(tc) {
179
+                            tiles.push(tc);
180
+                            tile_neighbors(tc, &mut neighbors);
181
+                            for tn in &neighbors {
182
+                                if !visited.contains(tn) {
183
+                                    visited.insert(*tn);
184
+                                    stack.push(*tn);
185
+                                }
186
+                            }
187
+                        }
188
+                    },
189
+                    _ => {},
218 190
                 }
191
+            } else {
192
+                break;
219 193
             }
220 194
         }
221 195