pub const QUANTIZED_MAX: u16 = 32767;
#[derive(Debug, Clone, Default)]
pub struct QuantizedVertices {
pub u: Vec<u16>,
pub v: Vec<u16>,
pub height: Vec<u16>,
}
impl QuantizedVertices {
pub fn new() -> Self {
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
u: Vec::with_capacity(capacity),
v: Vec::with_capacity(capacity),
height: Vec::with_capacity(capacity),
}
}
pub fn len(&self) -> usize {
self.u.len()
}
pub fn is_empty(&self) -> bool {
self.u.is_empty()
}
pub fn push(&mut self, u: u16, v: u16, height: u16) {
self.u.push(u);
self.v.push(v);
self.height.push(height);
}
}
#[derive(Debug, Clone, Default)]
pub struct EdgeIndices {
pub west: Vec<u32>,
pub south: Vec<u32>,
pub east: Vec<u32>,
pub north: Vec<u32>,
}
impl EdgeIndices {
pub fn new() -> Self {
Self::default()
}
pub fn from_vertices(vertices: &QuantizedVertices) -> Self {
let mut west = Vec::new();
let mut south = Vec::new();
let mut east = Vec::new();
let mut north = Vec::new();
for (i, (&u, &v)) in vertices.u.iter().zip(vertices.v.iter()).enumerate() {
let idx = i as u32;
if u == 0 {
west.push((idx, v));
}
if u == QUANTIZED_MAX {
east.push((idx, v));
}
if v == 0 {
south.push((idx, u));
}
if v == QUANTIZED_MAX {
north.push((idx, u));
}
}
west.sort_by_key(|&(_, v)| v);
east.sort_by_key(|&(_, v)| v);
south.sort_by_key(|&(_, u)| u);
north.sort_by_key(|&(_, u)| u);
Self {
west: west.into_iter().map(|(idx, _)| idx).collect(),
south: south.into_iter().map(|(idx, _)| idx).collect(),
east: east.into_iter().map(|(idx, _)| idx).collect(),
north: north.into_iter().map(|(idx, _)| idx).collect(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ExtensionId {
OctEncodedVertexNormals = 1,
WaterMask = 2,
Metadata = 4,
}
#[derive(Debug, Clone)]
pub enum WaterMask {
Uniform(u8),
Grid(Box<[u8; 256 * 256]>),
}
impl Default for WaterMask {
fn default() -> Self {
Self::Uniform(0) }
}
impl WaterMask {
pub fn from_data(data: &[u8]) -> Self {
if data.len() < 256 * 256 {
return Self::Uniform(0); }
if let Some(&first) = data.first()
&& data[..256 * 256].iter().all(|&v| v == first)
{
return Self::Uniform(first);
}
let mut grid = Box::new([0u8; 256 * 256]);
grid.copy_from_slice(&data[..256 * 256]);
Self::Grid(grid)
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AvailableRange {
pub start_x: u32,
pub end_x: u32,
pub start_y: u32,
pub end_y: u32,
}
impl AvailableRange {
pub fn new(start_x: u32, end_x: u32, start_y: u32, end_y: u32) -> Self {
Self {
start_x,
end_x,
start_y,
end_y,
}
}
pub fn full_level_geodetic(zoom: u8) -> Self {
let max_x = (1u32 << (zoom + 1)) - 1;
let max_y = (1u32 << zoom) - 1;
Self {
start_x: 0,
end_x: max_x,
start_y: 0,
end_y: max_y,
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct TileMetadata {
pub available: Vec<Vec<AvailableRange>>,
}
impl TileMetadata {
pub fn new() -> Self {
Self {
available: Vec::new(),
}
}
#[deprecated(note = "Use for_tile instead, which computes correct child tile ranges")]
pub fn all_available(current_zoom: u8, max_zoom: u8) -> Self {
let mut available = Vec::new();
for child_zoom in (current_zoom + 1)..=max_zoom {
available.push(vec![AvailableRange::full_level_geodetic(child_zoom)]);
}
Self { available }
}
pub fn for_tile(tile_x: u32, tile_y: u32, current_zoom: u8, max_zoom: u8) -> Self {
let mut available = Vec::new();
for child_zoom in (current_zoom + 1)..=max_zoom {
let levels_deep = child_zoom - current_zoom;
let scale = 1u32 << levels_deep;
let start_x = tile_x * scale;
let start_y = tile_y * scale;
let end_x = start_x + scale - 1;
let end_y = start_y + scale - 1;
available.push(vec![AvailableRange::new(start_x, end_x, start_y, end_y)]);
}
Self { available }
}
}
impl Default for TileMetadata {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy)]
pub struct TileBounds {
pub west: f64,
pub south: f64,
pub east: f64,
pub north: f64,
}
impl TileBounds {
pub fn new(west: f64, south: f64, east: f64, north: f64) -> Self {
Self {
west,
south,
east,
north,
}
}
pub fn width(&self) -> f64 {
self.east - self.west
}
pub fn height(&self) -> f64 {
self.north - self.south
}
pub fn center_lon(&self) -> f64 {
(self.west + self.east) / 2.0
}
pub fn center_lat(&self) -> f64 {
(self.south + self.north) / 2.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_quantized_vertices() {
let mut vertices = QuantizedVertices::new();
assert!(vertices.is_empty());
vertices.push(0, 0, 100);
vertices.push(QUANTIZED_MAX, QUANTIZED_MAX, 200);
assert_eq!(vertices.len(), 2);
assert_eq!(vertices.u, vec![0, QUANTIZED_MAX]);
assert_eq!(vertices.v, vec![0, QUANTIZED_MAX]);
assert_eq!(vertices.height, vec![100, 200]);
}
#[test]
fn test_edge_indices_extraction() {
let vertices = QuantizedVertices {
u: vec![0, QUANTIZED_MAX, 0, QUANTIZED_MAX],
v: vec![0, 0, QUANTIZED_MAX, QUANTIZED_MAX],
height: vec![0, 0, 0, 0],
};
let edges = EdgeIndices::from_vertices(&vertices);
assert_eq!(edges.west, vec![0, 2]);
assert_eq!(edges.east, vec![1, 3]);
assert_eq!(edges.south, vec![0, 1]);
assert_eq!(edges.north, vec![2, 3]);
}
#[test]
fn test_tile_bounds() {
let bounds = TileBounds::new(-180.0, -90.0, 180.0, 90.0);
assert_eq!(bounds.width(), 360.0);
assert_eq!(bounds.height(), 180.0);
assert_eq!(bounds.center_lon(), 0.0);
assert_eq!(bounds.center_lat(), 0.0);
}
}