mirror of
https://github.com/maplibre/maplibre-rs.git
synced 2025-12-08 19:05:57 +00:00
Add a few helper functions, fix crash and rename TileAdressingScheme
This commit is contained in:
parent
80fce94c61
commit
24c89dce97
@ -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>,
|
||||
|
||||
188
src/coords.rs
188
src/coords.rs
@ -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,
|
||||
)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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};
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user