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

@@ -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);
}
}
}
}