update to zoom zone
This commit is contained in:
@@ -222,7 +222,20 @@ async fn fetch_cached(url: &str) -> Option<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_visible_tiles(camera: &Camera) -> Vec<(i32, i32, i32)> {
|
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 n = 2.0f64.powi(z);
|
||||||
|
|
||||||
let half_width = 1.0 * camera.aspect / camera.zoom;
|
let half_width = 1.0 * camera.aspect / camera.zoom;
|
||||||
@@ -360,8 +373,8 @@ pub async fn run() {
|
|||||||
if let Some(btn) = btn_zoom_in {
|
if let Some(btn) = btn_zoom_in {
|
||||||
let closure = wasm_bindgen::closure::Closure::<dyn FnMut()>::new(move || {
|
let closure = wasm_bindgen::closure::Closure::<dyn FnMut()>::new(move || {
|
||||||
let mut cam = camera_clone.lock().unwrap();
|
let mut cam = camera_clone.lock().unwrap();
|
||||||
cam.zoom *= 1.2;
|
cam.zoom *= 1.5;
|
||||||
cam.zoom = cam.zoom.max(100.0).min(50000.0);
|
cam.zoom = cam.zoom.max(20.0).min(50000.0);
|
||||||
window_clone.request_redraw();
|
window_clone.request_redraw();
|
||||||
});
|
});
|
||||||
btn.set_onclick(Some(closure.as_ref().unchecked_ref()));
|
btn.set_onclick(Some(closure.as_ref().unchecked_ref()));
|
||||||
@@ -376,8 +389,8 @@ pub async fn run() {
|
|||||||
if let Some(btn) = btn_zoom_out {
|
if let Some(btn) = btn_zoom_out {
|
||||||
let closure = wasm_bindgen::closure::Closure::<dyn FnMut()>::new(move || {
|
let closure = wasm_bindgen::closure::Closure::<dyn FnMut()>::new(move || {
|
||||||
let mut cam = camera_clone.lock().unwrap();
|
let mut cam = camera_clone.lock().unwrap();
|
||||||
cam.zoom /= 1.2;
|
cam.zoom /= 1.5;
|
||||||
cam.zoom = cam.zoom.max(100.0).min(50000.0);
|
cam.zoom = cam.zoom.max(20.0).min(50000.0);
|
||||||
window_clone.request_redraw();
|
window_clone.request_redraw();
|
||||||
});
|
});
|
||||||
btn.set_onclick(Some(closure.as_ref().unchecked_ref()));
|
btn.set_onclick(Some(closure.as_ref().unchecked_ref()));
|
||||||
@@ -505,7 +518,7 @@ pub async fn run() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut cam = camera.lock().unwrap();
|
let mut cam = camera.lock().unwrap();
|
||||||
let zoom_factor = 1.1f32;
|
let zoom_factor = 1.5f32;
|
||||||
if scroll_y > 0.0 {
|
if scroll_y > 0.0 {
|
||||||
cam.zoom *= zoom_factor;
|
cam.zoom *= zoom_factor;
|
||||||
} else if scroll_y < 0.0 {
|
} else if scroll_y < 0.0 {
|
||||||
@@ -513,7 +526,7 @@ pub async fn run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clamp zoom
|
// 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();
|
window.request_redraw();
|
||||||
}
|
}
|
||||||
@@ -713,7 +726,7 @@ pub async fn run() {
|
|||||||
contents: bytemuck::cast_slice(&landuse_vertex_data),
|
contents: bytemuck::cast_slice(&landuse_vertex_data),
|
||||||
usage: wgpu::BufferUsages::VERTEX,
|
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 {
|
let water_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Tile Water Buffer"),
|
label: Some("Tile Water Buffer"),
|
||||||
@@ -826,23 +839,17 @@ pub async fn run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(landuse) = landuse_data {
|
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);
|
guard.landuse.insert((z, x, y), landuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(water) = water_data {
|
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);
|
guard.water.insert((z, x, y), water);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(railways) = railways_data {
|
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);
|
guard.railways.insert((z, x, y), railways);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,49 @@ use scylla::{Session, SessionBuilder};
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tokio::task::JoinSet;
|
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]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
// Connect to ScyllaDB
|
// Connect to ScyllaDB
|
||||||
@@ -46,8 +89,8 @@ async fn main() -> Result<()> {
|
|||||||
// Channel for backpressure
|
// Channel for backpressure
|
||||||
// Producer (reader) -> Consumer (writer)
|
// Producer (reader) -> Consumer (writer)
|
||||||
enum DbTask {
|
enum DbTask {
|
||||||
Node { id: i64, lat: f64, lon: f64, tags: HashMap<String, String>, x: i32, y: i32 },
|
Node { zoom: i32, 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 },
|
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);
|
let (tx, mut rx) = tokio::sync::mpsc::channel::<DbTask>(10_000);
|
||||||
@@ -72,20 +115,20 @@ async fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match task {
|
match task {
|
||||||
DbTask::Node { id, lat, lon, tags, x, y } => {
|
DbTask::Node { zoom, id, lat, lon, tags, x, y } => {
|
||||||
join_set.spawn(async move {
|
join_set.spawn(async move {
|
||||||
let _ = session.query(
|
let _ = session.query(
|
||||||
"INSERT INTO map_data.nodes (zoom, tile_x, tile_y, id, lat, lon, tags) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
"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;
|
).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);
|
let query = format!("INSERT INTO map_data.{} (zoom, tile_x, tile_y, id, tags, points) VALUES (?, ?, ?, ?, ?, ?)", table);
|
||||||
join_set.spawn(async move {
|
join_set.spawn(async move {
|
||||||
let _ = session.query(
|
let _ = session.query(
|
||||||
query,
|
query,
|
||||||
(10, x, y, id, tags, points),
|
(zoom, x, y, id, tags, points),
|
||||||
).await;
|
).await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -123,12 +166,16 @@ async fn main() -> Result<()> {
|
|||||||
let lat = node.lat();
|
let lat = node.lat();
|
||||||
let lon = node.lon();
|
let lon = node.lon();
|
||||||
let tags: HashMap<String, String> = node.tags().map(|(k, v)| (k.to_string(), v.to_string())).collect();
|
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 };
|
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);
|
let _ = tx.blocking_send(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Element::DenseNode(node) => {
|
Element::DenseNode(node) => {
|
||||||
node_count += 1;
|
node_count += 1;
|
||||||
|
|
||||||
@@ -144,12 +191,16 @@ async fn main() -> Result<()> {
|
|||||||
let lat = node.lat();
|
let lat = node.lat();
|
||||||
let lon = node.lon();
|
let lon = node.lon();
|
||||||
let tags: HashMap<String, String> = node.tags().map(|(k, v)| (k.to_string(), v.to_string())).collect();
|
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 };
|
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);
|
let _ = tx.blocking_send(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Element::Way(way) => {
|
Element::Way(way) => {
|
||||||
way_count += 1;
|
way_count += 1;
|
||||||
let tags: HashMap<String, String> = way.tags().map(|(k, v)| (k.to_string(), v.to_string())).collect();
|
let tags: HashMap<String, String> = way.tags().map(|(k, v)| (k.to_string(), v.to_string())).collect();
|
||||||
@@ -157,12 +208,12 @@ async fn main() -> Result<()> {
|
|||||||
// Filter for highways/roads OR buildings OR landuse OR water OR railways
|
// Filter for highways/roads OR buildings OR landuse OR water OR railways
|
||||||
let is_highway = tags.contains_key("highway");
|
let is_highway = tags.contains_key("highway");
|
||||||
let is_building = tags.contains_key("building");
|
let is_building = tags.contains_key("building");
|
||||||
let is_water = tags.get("natural").map(|v| v == "water").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").unwrap_or(false) ||
|
tags.get("waterway").map(|v| v == "riverbank" || v == "stream" || v == "river").unwrap_or(false) ||
|
||||||
tags.get("landuse").map(|v| v == "basin").unwrap_or(false);
|
tags.get("landuse").map(|v| v == "basin" || v == "reservoir").unwrap_or(false);
|
||||||
let is_landuse = tags.get("leisure").map(|v| v == "park" || v == "garden").unwrap_or(false) ||
|
let is_landuse = tags.contains_key("leisure") ||
|
||||||
tags.get("landuse").map(|v| v == "grass" || v == "forest" || v == "meadow").unwrap_or(false) ||
|
tags.contains_key("landuse") ||
|
||||||
tags.get("natural").map(|v| v == "wood" || v == "scrub").unwrap_or(false);
|
tags.get("natural").map(|v| v == "wood" || v == "scrub" || v == "heath" || v == "wetland").unwrap_or(false);
|
||||||
let is_railway = tags.contains_key("railway");
|
let is_railway = tags.contains_key("railway");
|
||||||
|
|
||||||
if is_highway || is_building || is_water || is_landuse || is_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
|
// Insert into the tile of the first point
|
||||||
let (first_lat, first_lon) = points[0];
|
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
|
// Serialize points to blob (f64, f64) pairs
|
||||||
let mut blob = Vec::with_capacity(points.len() * 16);
|
let mut blob = Vec::with_capacity(points.len() * 16);
|
||||||
@@ -192,33 +242,40 @@ async fn main() -> Result<()> {
|
|||||||
blob.extend_from_slice(&lon.to_be_bytes());
|
blob.extend_from_slice(&lon.to_be_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_highway {
|
if is_highway {
|
||||||
let task = DbTask::Way { table: "ways", id, tags: tags.clone(), points: blob.clone(), x, y };
|
let task = DbTask::Way { zoom: zoom_i32, table: "ways", id, tags: tags.clone(), points: blob.clone(), x, y };
|
||||||
let _ = tx.blocking_send(task);
|
let _ = tx.blocking_send(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_building {
|
if is_building {
|
||||||
let task = DbTask::Way { table: "buildings", id, tags: tags.clone(), points: blob.clone(), x, y };
|
let task = DbTask::Way { zoom: zoom_i32, table: "buildings", id, tags: tags.clone(), points: blob.clone(), x, y };
|
||||||
let _ = tx.blocking_send(task);
|
let _ = tx.blocking_send(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_water {
|
if is_water {
|
||||||
let task = DbTask::Way { table: "water", id, tags: tags.clone(), points: blob.clone(), x, y };
|
let task = DbTask::Way { zoom: zoom_i32, table: "water", id, tags: tags.clone(), points: blob.clone(), x, y };
|
||||||
let _ = tx.blocking_send(task);
|
let _ = tx.blocking_send(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_landuse {
|
if is_landuse {
|
||||||
let task = DbTask::Way { table: "landuse", id, tags: tags.clone(), points: blob.clone(), x, y };
|
let task = DbTask::Way { zoom: zoom_i32, table: "landuse", id, tags: tags.clone(), points: blob.clone(), x, y };
|
||||||
let _ = tx.blocking_send(task);
|
let _ = tx.blocking_send(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_railway {
|
if is_railway {
|
||||||
let task = DbTask::Way { table: "railways", id, tags: tags.clone(), points: blob.clone(), x, y };
|
let task = DbTask::Way { zoom: zoom_i32, table: "railways", id, tags: tags.clone(), points: blob.clone(), x, y };
|
||||||
let _ = tx.blocking_send(task);
|
let _ = tx.blocking_send(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user