update to zoom zone

This commit is contained in:
2025-11-26 15:22:54 +01:00
parent 696d058fed
commit 0d73796900
2 changed files with 121 additions and 57 deletions

View File

@@ -222,7 +222,20 @@ async fn fetch_cached(url: &str) -> Option<String> {
}
fn get_visible_tiles(camera: &Camera) -> Vec<(i32, i32, i32)> {
let z = 10; // Fixed zoom level for data
// Select zoom level based on camera zoom
// Zoom 6: World/Country view
// Zoom 9: Region view
// Zoom 12: City view
// Zoom 14: Street view
let z = if camera.zoom < 500.0 {
6
} else if camera.zoom < 2000.0 {
9
} else if camera.zoom < 8000.0 {
12
} else {
14
};
let n = 2.0f64.powi(z);
let half_width = 1.0 * camera.aspect / camera.zoom;
@@ -360,8 +373,8 @@ pub async fn run() {
if let Some(btn) = btn_zoom_in {
let closure = wasm_bindgen::closure::Closure::<dyn FnMut()>::new(move || {
let mut cam = camera_clone.lock().unwrap();
cam.zoom *= 1.2;
cam.zoom = cam.zoom.max(100.0).min(50000.0);
cam.zoom *= 1.5;
cam.zoom = cam.zoom.max(20.0).min(50000.0);
window_clone.request_redraw();
});
btn.set_onclick(Some(closure.as_ref().unchecked_ref()));
@@ -376,8 +389,8 @@ pub async fn run() {
if let Some(btn) = btn_zoom_out {
let closure = wasm_bindgen::closure::Closure::<dyn FnMut()>::new(move || {
let mut cam = camera_clone.lock().unwrap();
cam.zoom /= 1.2;
cam.zoom = cam.zoom.max(100.0).min(50000.0);
cam.zoom /= 1.5;
cam.zoom = cam.zoom.max(20.0).min(50000.0);
window_clone.request_redraw();
});
btn.set_onclick(Some(closure.as_ref().unchecked_ref()));
@@ -505,7 +518,7 @@ pub async fn run() {
};
let mut cam = camera.lock().unwrap();
let zoom_factor = 1.1f32;
let zoom_factor = 1.5f32;
if scroll_y > 0.0 {
cam.zoom *= zoom_factor;
} else if scroll_y < 0.0 {
@@ -513,7 +526,7 @@ pub async fn run() {
}
// Clamp zoom
cam.zoom = cam.zoom.max(100.0).min(50000.0);
cam.zoom = cam.zoom.max(20.0).min(50000.0);
window.request_redraw();
}
@@ -713,7 +726,7 @@ pub async fn run() {
contents: bytemuck::cast_slice(&landuse_vertex_data),
usage: wgpu::BufferUsages::VERTEX,
});
web_sys::console::log_1(&format!("Created landuse buffer with {} vertices", landuse_vertex_data.len()).into());
let water_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Tile Water Buffer"),
@@ -826,23 +839,17 @@ pub async fn run() {
}
if let Some(landuse) = landuse_data {
if !landuse.is_empty() {
web_sys::console::log_1(&format!("Fetched {} landuse items for tile {}/{}/{}", landuse.len(), z, x, y).into());
}
guard.landuse.insert((z, x, y), landuse);
}
if let Some(water) = water_data {
if !water.is_empty() {
web_sys::console::log_1(&format!("Fetched {} water items for tile {}/{}/{}", water.len(), z, x, y).into());
}
guard.water.insert((z, x, y), water);
}
if let Some(railways) = railways_data {
if !railways.is_empty() {
web_sys::console::log_1(&format!("Fetched {} railway items for tile {}/{}/{}", railways.len(), z, x, y).into());
}
guard.railways.insert((z, x, y), railways);
}

View File

@@ -4,6 +4,49 @@ use scylla::{Session, SessionBuilder};
use std::collections::HashMap;
use tokio::task::JoinSet;
const ZOOM_LEVELS: [u32; 4] = [6, 9, 12, 14];
fn should_include(tags: &HashMap<String, String>, zoom: u32) -> bool {
if zoom >= 14 { return true; }
let highway = tags.get("highway").map(|s| s.as_str());
let place = tags.get("place").map(|s| s.as_str());
let natural = tags.get("natural").map(|s| s.as_str());
let railway = tags.get("railway").map(|s| s.as_str());
let waterway = tags.get("waterway").map(|s| s.as_str());
match zoom {
6 => {
matches!(highway, Some("motorway" | "trunk" | "primary" | "secondary")) ||
matches!(place, Some("city")) ||
matches!(natural, Some("water" | "wood" | "scrub" | "heath" | "wetland")) ||
matches!(tags.get("landuse").map(|s| s.as_str()), Some("forest" | "meadow" | "grass" | "recreation_ground" | "farmland")) ||
tags.contains_key("leisure") || // Parks, nature reserves, golf courses
matches!(waterway, Some("river" | "riverbank"))
},
9 => {
matches!(highway, Some("motorway" | "trunk" | "primary" | "secondary")) ||
matches!(place, Some("city" | "town")) ||
matches!(railway, Some("rail")) ||
matches!(natural, Some("water" | "wood" | "scrub" | "heath" | "wetland")) ||
tags.contains_key("landuse") ||
tags.contains_key("leisure") ||
matches!(waterway, Some("river" | "riverbank"))
},
12 => {
matches!(highway, Some("motorway" | "trunk" | "primary" | "secondary" | "tertiary")) ||
matches!(place, Some("city" | "town" | "village")) ||
matches!(railway, Some("rail")) ||
tags.contains_key("landuse") ||
tags.contains_key("leisure") ||
matches!(natural, Some("water" | "wood" | "scrub" | "wetland" | "heath")) ||
matches!(waterway, Some("river" | "riverbank" | "stream"))
},
_ => false
}
}
#[tokio::main]
async fn main() -> Result<()> {
// Connect to ScyllaDB
@@ -46,8 +89,8 @@ async fn main() -> Result<()> {
// Channel for backpressure
// Producer (reader) -> Consumer (writer)
enum DbTask {
Node { id: i64, lat: f64, lon: f64, tags: HashMap<String, String>, x: i32, y: i32 },
Way { table: &'static str, id: i64, tags: HashMap<String, String>, points: Vec<u8>, x: i32, y: i32 },
Node { zoom: i32, id: i64, lat: f64, lon: f64, tags: HashMap<String, String>, x: i32, y: i32 },
Way { zoom: i32, table: &'static str, id: i64, tags: HashMap<String, String>, points: Vec<u8>, x: i32, y: i32 },
}
let (tx, mut rx) = tokio::sync::mpsc::channel::<DbTask>(10_000);
@@ -72,20 +115,20 @@ async fn main() -> Result<()> {
}
match task {
DbTask::Node { id, lat, lon, tags, x, y } => {
DbTask::Node { zoom, id, lat, lon, tags, x, y } => {
join_set.spawn(async move {
let _ = session.query(
"INSERT INTO map_data.nodes (zoom, tile_x, tile_y, id, lat, lon, tags) VALUES (?, ?, ?, ?, ?, ?, ?)",
(10, x, y, id, lat, lon, tags),
(zoom, x, y, id, lat, lon, tags),
).await;
});
}
DbTask::Way { table, id, tags, points, x, y } => {
DbTask::Way { zoom, table, id, tags, points, x, y } => {
let query = format!("INSERT INTO map_data.{} (zoom, tile_x, tile_y, id, tags, points) VALUES (?, ?, ?, ?, ?, ?)", table);
join_set.spawn(async move {
let _ = session.query(
query,
(10, x, y, id, tags, points),
(zoom, x, y, id, tags, points),
).await;
});
}
@@ -123,10 +166,14 @@ async fn main() -> Result<()> {
let lat = node.lat();
let lon = node.lon();
let tags: HashMap<String, String> = node.tags().map(|(k, v)| (k.to_string(), v.to_string())).collect();
let (x, y) = lat_lon_to_tile(lat, lon, 10);
let task = DbTask::Node { id, lat, lon, tags, x, y };
let _ = tx.blocking_send(task);
for &zoom in &ZOOM_LEVELS {
if should_include(&tags, zoom) {
let (x, y) = lat_lon_to_tile(lat, lon, zoom);
let task = DbTask::Node { zoom: zoom as i32, id, lat, lon, tags: tags.clone(), x, y };
let _ = tx.blocking_send(task);
}
}
}
}
Element::DenseNode(node) => {
@@ -144,10 +191,14 @@ async fn main() -> Result<()> {
let lat = node.lat();
let lon = node.lon();
let tags: HashMap<String, String> = node.tags().map(|(k, v)| (k.to_string(), v.to_string())).collect();
let (x, y) = lat_lon_to_tile(lat, lon, 10);
let task = DbTask::Node { id, lat, lon, tags, x, y };
let _ = tx.blocking_send(task);
for &zoom in &ZOOM_LEVELS {
if should_include(&tags, zoom) {
let (x, y) = lat_lon_to_tile(lat, lon, zoom);
let task = DbTask::Node { zoom: zoom as i32, id, lat, lon, tags: tags.clone(), x, y };
let _ = tx.blocking_send(task);
}
}
}
}
Element::Way(way) => {
@@ -157,12 +208,12 @@ async fn main() -> Result<()> {
// Filter for highways/roads OR buildings OR landuse OR water OR railways
let is_highway = tags.contains_key("highway");
let is_building = tags.contains_key("building");
let is_water = tags.get("natural").map(|v| v == "water").unwrap_or(false) ||
tags.get("waterway").map(|v| v == "riverbank").unwrap_or(false) ||
tags.get("landuse").map(|v| v == "basin").unwrap_or(false);
let is_landuse = tags.get("leisure").map(|v| v == "park" || v == "garden").unwrap_or(false) ||
tags.get("landuse").map(|v| v == "grass" || v == "forest" || v == "meadow").unwrap_or(false) ||
tags.get("natural").map(|v| v == "wood" || v == "scrub").unwrap_or(false);
let is_water = tags.get("natural").map(|v| v == "water" || v == "wetland").unwrap_or(false) ||
tags.get("waterway").map(|v| v == "riverbank" || v == "stream" || v == "river").unwrap_or(false) ||
tags.get("landuse").map(|v| v == "basin" || v == "reservoir").unwrap_or(false);
let is_landuse = tags.contains_key("leisure") ||
tags.contains_key("landuse") ||
tags.get("natural").map(|v| v == "wood" || v == "scrub" || v == "heath" || v == "wetland").unwrap_or(false);
let is_railway = tags.contains_key("railway");
if is_highway || is_building || is_water || is_landuse || is_railway {
@@ -183,7 +234,6 @@ async fn main() -> Result<()> {
// Insert into the tile of the first point
let (first_lat, first_lon) = points[0];
let (x, y) = lat_lon_to_tile(first_lat, first_lon, 10);
// Serialize points to blob (f64, f64) pairs
let mut blob = Vec::with_capacity(points.len() * 16);
@@ -192,29 +242,36 @@ async fn main() -> Result<()> {
blob.extend_from_slice(&lon.to_be_bytes());
}
if is_highway {
let task = DbTask::Way { table: "ways", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
}
for &zoom in &ZOOM_LEVELS {
if !should_include(&tags, zoom) { continue; }
let (x, y) = lat_lon_to_tile(first_lat, first_lon, zoom);
let zoom_i32 = zoom as i32;
if is_building {
let task = DbTask::Way { table: "buildings", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
}
if is_highway {
let task = DbTask::Way { zoom: zoom_i32, table: "ways", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
}
if is_water {
let task = DbTask::Way { table: "water", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
}
if is_building {
let task = DbTask::Way { zoom: zoom_i32, table: "buildings", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
}
if is_landuse {
let task = DbTask::Way { table: "landuse", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
}
if is_water {
let task = DbTask::Way { zoom: zoom_i32, table: "water", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
}
if is_railway {
let task = DbTask::Way { table: "railways", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
if is_landuse {
let task = DbTask::Way { zoom: zoom_i32, table: "landuse", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
}
if is_railway {
let task = DbTask::Way { zoom: zoom_i32, table: "railways", id, tags: tags.clone(), points: blob.clone(), x, y };
let _ = tx.blocking_send(task);
}
}
}
}