Add a few helper functions, fix crash and rename TileAdressingScheme

This commit is contained in:
Maximilian Ammann 2022-03-24 12:08:28 +01:00
parent 80fce94c61
commit 24c89dce97
7 changed files with 156 additions and 60 deletions

View File

@ -5,16 +5,16 @@ pub type TileUrl = String;
pub type TileJSONUrl = String;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum TileAdressingScheme {
pub enum TileAddressingScheme {
#[serde(rename = "xyz")]
XYZ,
#[serde(rename = "tms")]
TMS,
}
impl Default for TileAdressingScheme {
impl Default for TileAddressingScheme {
fn default() -> Self {
TileAdressingScheme::XYZ
TileAddressingScheme::XYZ
}
}
@ -35,7 +35,7 @@ pub struct VectorSource {
// TODO: promoteId
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub scheme: Option<TileAdressingScheme>,
pub scheme: Option<TileAddressingScheme>,
/// Array of URLs which can contain place holders like {x}, {y}, {z}.
#[serde(skip_serializing_if = "Option::is_none")]
pub tiles: Option<TileUrl>,

View File

@ -1,11 +1,13 @@
//! File which exposes all kinds of coordinates used throughout mapr
use crate::util::math::{div_floor, Aabb2};
use cgmath::num_traits::Pow;
use cgmath::{Matrix4, Point3, Vector3};
use std::fmt;
use style_spec::source::TileAdressingScheme;
use cgmath::num_traits::Pow;
use cgmath::{Matrix4, Point3, Vector3};
use style_spec::source::TileAddressingScheme;
use crate::util::math::{div_floor, Aabb2};
pub const EXTENT_UINT: u32 = 4096;
pub const EXTENT_SINT: i32 = EXTENT_UINT as i32;
@ -25,27 +27,81 @@ pub struct TileCoords {
}
impl TileCoords {
/// Transforms the tile coordinates as defined by the tile grid addressing scheme into a representation which is
/// used in the 3d-world.
pub fn into_world_tile(self, scheme: TileAdressingScheme) -> WorldTileCoords {
match scheme {
TileAdressingScheme::XYZ => WorldTileCoords {
x: self.x as i32,
y: self.y as i32,
/// Transforms the tile coordinates as defined by the tile grid addressing scheme into a
/// representation which is used in the 3d-world.
/// This is not possible if the coordinates of this [`TileCoords`] exceed their bounds.
///
/// # Example
/// The [`TileCoords`] `T(x=5,y=5,z=0)` exceeds its bounds because there is no tile
/// `x=5,y=5` at zoom level `z=0`.
pub fn into_world_tile(self, scheme: TileAddressingScheme) -> Option<WorldTileCoords> {
let bounds = 2i32.pow(self.z as u32);
let x = self.x as i32;
let y = self.y as i32;
if x >= bounds || y >= bounds {
return None;
}
Some(match scheme {
TileAddressingScheme::XYZ => WorldTileCoords { x, y, z: self.z },
TileAddressingScheme::TMS => WorldTileCoords {
x,
y: bounds - 1 - y,
z: self.z,
},
TileAdressingScheme::TMS => WorldTileCoords {
x: self.x as i32,
y: (2u32.pow(self.z as u32) - 1 - self.y) as i32,
z: self.z,
})
}
/// Get the tile which is one zoom level lower and contains this one
pub fn get_parent(&self) -> [TileCoords; 4] {
[
TileCoords {
x: self.x * 2,
y: self.y * 2,
z: self.z + 1,
},
TileCoords {
x: self.x * 2 + 1,
y: self.y * 2,
z: self.z + 1,
},
TileCoords {
x: self.x * 2 + 1,
y: self.y * 2 + 1,
z: self.z + 1,
},
TileCoords {
x: self.x * 2,
y: self.y * 2 + 1,
z: self.z + 1,
},
]
}
pub fn get_children(&self) -> TileCoords {
TileCoords {
x: self.x >> 1,
y: self.y >> 1,
z: self.z - 1,
}
}
}
impl fmt::Display for TileCoords {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "T({x}, {y}, {z})", x = self.x, y = self.y, z = self.z)
pub fn to_quad_key(&self) -> Vec<u8> {
let mut key = Vec::with_capacity(self.z as usize);
for z in (0..self.z).rev() {
let mut b = 0;
let mask: u32 = 1 << (z - 1);
if self.x & mask != 0 {
b += 1u8;
}
if self.y & mask != 0 {
b += 2u8;
}
key.push(b);
}
return key;
}
}
@ -74,19 +130,30 @@ pub struct WorldTileCoords {
}
impl WorldTileCoords {
pub fn into_tile(self, scheme: TileAdressingScheme) -> TileCoords {
match scheme {
TileAdressingScheme::XYZ => TileCoords {
x: self.x as u32,
y: self.y as u32,
z: self.z,
},
TileAdressingScheme::TMS => TileCoords {
x: self.x as u32,
y: 2u32.pow(self.z as u32) - 1 - self.y as u32,
z: self.z,
},
/// Returns the tile coords according to an addressing scheme. This is not possible if the
/// coordinates of this [`WorldTileCoords`] exceed their bounds.
///
/// # Example
///
/// The [`WorldTileCoords`] `WT(x=5,y=5,z=0)` exceeds its bounds because there is no tile
/// `x=5,y=5` at zoom level `z=0`.
pub fn into_tile(self, scheme: TileAddressingScheme) -> Option<TileCoords> {
let bounds = 2u32.pow(self.z as u32);
let x = self.x as u32;
let y = self.y as u32;
if x >= bounds || y >= bounds {
return None;
}
Some(match scheme {
TileAddressingScheme::XYZ => TileCoords { x, y, z: self.z },
TileAddressingScheme::TMS => TileCoords {
x,
y: bounds - 1 - y,
z: self.z,
},
})
}
pub fn transform_for_zoom(&self, zoom: f64) -> Matrix4<f64> {
@ -122,12 +189,6 @@ impl WorldTileCoords {
}
}
impl fmt::Display for WorldTileCoords {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "WT({x}, {y}, {z})", x = self.x, y = self.y, z = self.z)
}
}
impl From<(i32, i32, u8)> for WorldTileCoords {
fn from(tuple: (i32, i32, u8)) -> Self {
WorldTileCoords {
@ -220,12 +281,6 @@ impl WorldCoords {
}
}
impl fmt::Display for WorldCoords {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "W({x}, {y}, {z})", x = self.x, y = self.y, z = self.z)
}
}
impl From<(f32, f32, f32)> for WorldCoords {
fn from(tuple: (f32, f32, f32)) -> Self {
WorldCoords {
@ -260,10 +315,11 @@ pub struct ViewRegion {
min_tile: WorldTileCoords,
max_tile: WorldTileCoords,
z: u8,
padding: i32,
}
impl ViewRegion {
pub fn new(view_region: Aabb2<f64>, zoom: f64, z: u8) -> Self {
pub fn new(view_region: Aabb2<f64>, padding: i32, zoom: f64, z: u8) -> Self {
let min_world: WorldCoords = WorldCoords::at_ground(view_region.min.x, view_region.min.y);
let min_world_tile: WorldTileCoords = min_world.into_world_tile(z, zoom);
let max_world: WorldCoords = WorldCoords::at_ground(view_region.max.x, view_region.max.y);
@ -273,12 +329,13 @@ impl ViewRegion {
min_tile: min_world_tile,
max_tile: max_world_tile,
z,
padding,
}
}
pub fn iter(&self) -> impl Iterator<Item = WorldTileCoords> + '_ {
(self.min_tile.x..self.max_tile.x + 1).flat_map(move |x| {
(self.min_tile.y..self.max_tile.y + 1).map(move |y| {
(self.min_tile.x..self.max_tile.x + self.padding).flat_map(move |x| {
(self.min_tile.y..self.max_tile.y + self.padding).map(move |y| {
let tile_coord: WorldTileCoords = (x, y, self.z as u8).into();
tile_coord
})
@ -286,11 +343,47 @@ impl ViewRegion {
}
}
impl fmt::Display for TileCoords {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"T(x={x},y={y},z={z})",
x = self.x,
y = self.y,
z = self.z
)
}
}
impl fmt::Display for WorldTileCoords {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"WT(x={x},y={y},z={z})",
x = self.x,
y = self.y,
z = self.z
)
}
}
impl fmt::Display for WorldCoords {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"W(x={x},y={y},z={z})",
x = self.x,
y = self.y,
z = self.z
)
}
}
#[cfg(test)]
mod tests {
use cgmath::{Point2, Vector4};
use crate::coords::{ViewRegion, WorldCoords, WorldTileCoords, EXTENT};
use crate::util::math::Aabb2;
use cgmath::{Point2, Vector4};
const TOP_LEFT: Vector4<f64> = Vector4::new(0.0, 0.0, 0.0, 1.0);
const BOTTOM_RIGHT: Vector4<f64> = Vector4::new(EXTENT, EXTENT, 0.0, 1.0);
@ -318,6 +411,7 @@ mod tests {
fn test_view_region() {
for tile_coords in ViewRegion::new(
Aabb2::new(Point2::new(0.0, 0.0), Point2::new(2000.0, 2000.0)),
1,
0.0,
0,
)

View File

@ -4,7 +4,7 @@ use log::{error, info};
use std::sync::mpsc::{channel, Receiver, SendError, Sender};
use std::sync::{Arc, Mutex};
use style_spec::source::TileAdressingScheme;
use style_spec::source::TileAddressingScheme;
use vector_tile::parse_tile_bytes;
/// Describes through which channels work-requests travel. It describes the flow of work.
@ -233,9 +233,10 @@ impl IOScheduler {
if let Some(id) = tile_request_state.start_tile_request(tile_request) {
info!("new tile request: {}", &tile_coords);
let tile_coords = tile_coords.into_tile(TileAdressingScheme::TMS);
self.schedule_method
.schedule_tile_request(self, id, tile_coords)
if let Some(tile_coords) = tile_coords.into_tile(TileAddressingScheme::TMS) {
self.schedule_method
.schedule_tile_request(self, id, tile_coords);
}
}
}

View File

@ -44,7 +44,7 @@ impl StaticTileFetcher {
#[cfg(test)]
mod tests {
use style_spec::source::TileAdressingScheme;
use style_spec::source::TileAddressingScheme;
use crate::coords::WorldTileCoords;
@ -60,7 +60,7 @@ mod tests {
assert!(fetcher.fetch_tile(&(0, 0, 0).into()).await.is_err()); // World overview
let world_tile: WorldTileCoords = (MUNICH_X, MUNICH_Y, MUNICH_Z).into();
assert!(fetcher
.fetch_tile(&world_tile.into_tile(TileAdressingScheme::XYZ))
.fetch_tile(&world_tile.into_tile(TileAddressingScheme::XYZ))
.await
.is_ok()); // Maxvorstadt Munich
}

View File

@ -18,7 +18,7 @@ use console_error_panic_hook;
pub use instant::Instant;
use scheduler::WebWorkerPoolScheduleMethod;
use scheduler::WebWorkerScheduleMethod;
use style_spec::source::TileAdressingScheme;
use style_spec::source::TileAddressingScheme;
use wasm_bindgen::prelude::*;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;

View File

@ -1,5 +1,6 @@
//! A small module that's intended to provide an example of creating a pool of
//! web workers which can be used to execute `rayon`-style work.
//! web workers which can be used to execute work.
//! Adopted from [wasm-bindgen example](https://github.com/rustwasm/wasm-bindgen/blob/0eba2efe45801b71f8873bc368c58a8ed8e894ff/examples/raytrace-parallel/src/pool.rs)
use js_sys::Promise;
use log::{info, warn};

View File

@ -357,7 +357,7 @@ impl RenderState {
let view_region = self
.camera
.view_region_bounding_box(&self.perspective)
.map(|bounding_box| ViewRegion::new(bounding_box, self.zoom, visible_z));
.map(|bounding_box| ViewRegion::new(bounding_box, 2, self.zoom, visible_z));
// Fetch tiles which are currently in view
if let Some(view_region) = &view_region {