update
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1 +1,6 @@
|
|||||||
/target
|
/target
|
||||||
|
scylla_data/
|
||||||
|
*.wasm
|
||||||
|
pkg/
|
||||||
|
node_modules/
|
||||||
|
.DS_Store
|
||||||
|
|||||||
@@ -59,6 +59,36 @@ pub async fn initialize_schema(session: &Session) -> Result<(), Box<dyn std::err
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
session
|
||||||
|
.query(
|
||||||
|
"CREATE TABLE IF NOT EXISTS map_data.landuse (
|
||||||
|
zoom int,
|
||||||
|
tile_x int,
|
||||||
|
tile_y int,
|
||||||
|
id bigint,
|
||||||
|
tags map<text, text>,
|
||||||
|
points blob,
|
||||||
|
PRIMARY KEY ((zoom, tile_x, tile_y), id)
|
||||||
|
)",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
session
|
||||||
|
.query(
|
||||||
|
"CREATE TABLE IF NOT EXISTS map_data.water (
|
||||||
|
zoom int,
|
||||||
|
tile_x int,
|
||||||
|
tile_y int,
|
||||||
|
id bigint,
|
||||||
|
tags map<text, text>,
|
||||||
|
points blob,
|
||||||
|
PRIMARY KEY ((zoom, tile_x, tile_y), id)
|
||||||
|
)",
|
||||||
|
&[],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
println!("Schema initialized.");
|
println!("Schema initialized.");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
println!("Connecting to ScyllaDB...");
|
println!("Connecting to ScyllaDB...");
|
||||||
|
println!("Starting backend with landuse support...");
|
||||||
let uri = std::env::var("SCYLLA_URI").unwrap_or_else(|_| "127.0.0.1:9042".to_string());
|
let uri = std::env::var("SCYLLA_URI").unwrap_or_else(|_| "127.0.0.1:9042".to_string());
|
||||||
|
|
||||||
let session = SessionBuilder::new()
|
let session = SessionBuilder::new()
|
||||||
@@ -45,6 +46,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
.route("/api/tiles/:z/:x/:y", get(get_tile))
|
.route("/api/tiles/:z/:x/:y", get(get_tile))
|
||||||
.route("/api/tiles/:z/:x/:y/ways", get(get_tile_ways))
|
.route("/api/tiles/:z/:x/:y/ways", get(get_tile_ways))
|
||||||
.route("/api/tiles/:z/:x/:y/buildings", get(get_tile_buildings))
|
.route("/api/tiles/:z/:x/:y/buildings", get(get_tile_buildings))
|
||||||
|
.route("/api/tiles/:z/:x/:y/landuse", get(get_tile_landuse))
|
||||||
|
.route("/api/tiles/:z/:x/:y/water", get(get_tile_water))
|
||||||
.nest_service("/", ServeDir::new("static"))
|
.nest_service("/", ServeDir::new("static"))
|
||||||
.layer(CorsLayer::permissive())
|
.layer(CorsLayer::permissive())
|
||||||
.with_state(state);
|
.with_state(state);
|
||||||
@@ -144,3 +147,55 @@ async fn get_tile_buildings(
|
|||||||
|
|
||||||
Json(buildings)
|
Json(buildings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_tile_landuse(
|
||||||
|
Path((z, x, y)): Path<(i32, i32, i32)>,
|
||||||
|
State(state): State<Arc<AppState>>,
|
||||||
|
) -> Json<Vec<MapWay>> {
|
||||||
|
let query = "SELECT id, tags, points FROM map_data.landuse WHERE zoom = ? AND tile_x = ? AND tile_y = ?";
|
||||||
|
let rows = state.scylla_session.query(query, (z, x, y)).await.unwrap().rows.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut landuse = Vec::new();
|
||||||
|
for row in rows {
|
||||||
|
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>().unwrap();
|
||||||
|
|
||||||
|
let mut points = Vec::new();
|
||||||
|
for chunk in points_blob.chunks(16) {
|
||||||
|
if chunk.len() == 16 {
|
||||||
|
let lat = f64::from_be_bytes(chunk[0..8].try_into().unwrap());
|
||||||
|
let lon = f64::from_be_bytes(chunk[8..16].try_into().unwrap());
|
||||||
|
points.push(vec![lat, lon]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
landuse.push(MapWay { id, tags, points });
|
||||||
|
}
|
||||||
|
|
||||||
|
Json(landuse)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_tile_water(
|
||||||
|
Path((z, x, y)): Path<(i32, i32, i32)>,
|
||||||
|
State(state): State<Arc<AppState>>,
|
||||||
|
) -> Json<Vec<MapWay>> {
|
||||||
|
let query = "SELECT id, tags, points FROM map_data.water WHERE zoom = ? AND tile_x = ? AND tile_y = ?";
|
||||||
|
let rows = state.scylla_session.query(query, (z, x, y)).await.unwrap().rows.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut water = Vec::new();
|
||||||
|
for row in rows {
|
||||||
|
let (id, tags, points_blob) = row.into_typed::<(i64, std::collections::HashMap<String, String>, Vec<u8>)>().unwrap();
|
||||||
|
|
||||||
|
let mut points = Vec::new();
|
||||||
|
for chunk in points_blob.chunks(16) {
|
||||||
|
if chunk.len() == 16 {
|
||||||
|
let lat = f64::from_be_bytes(chunk[0..8].try_into().unwrap());
|
||||||
|
let lon = f64::from_be_bytes(chunk[8..16].try_into().unwrap());
|
||||||
|
points.push(vec![lat, lon]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
water.push(MapWay { id, tags, points });
|
||||||
|
}
|
||||||
|
|
||||||
|
Json(water)
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ services:
|
|||||||
- "9042:9042"
|
- "9042:9042"
|
||||||
- "9160:9160"
|
- "9160:9160"
|
||||||
- "10000:10000"
|
- "10000:10000"
|
||||||
command: --smp 1 --memory 750M --overprovisioned 1 --api-address 0.0.0.0 --max-memory-for-unlimited-query-soft-limit 10485760 --tombstone-warn-threshold 100000
|
command: --smp 1 --memory 2G --overprovisioned 1 --api-address 0.0.0.0 --max-memory-for-unlimited-query-soft-limit 1073741824 --tombstone-warn-threshold 10000000
|
||||||
volumes:
|
volumes:
|
||||||
- scylla_data:/var/lib/scylla
|
- scylla_data:/var/lib/scylla
|
||||||
|
|
||||||
|
|||||||
@@ -129,12 +129,18 @@ struct TileBuffers {
|
|||||||
road_vertex_count: u32,
|
road_vertex_count: u32,
|
||||||
building_vertex_buffer: wgpu::Buffer,
|
building_vertex_buffer: wgpu::Buffer,
|
||||||
building_index_count: u32,
|
building_index_count: u32,
|
||||||
|
landuse_vertex_buffer: wgpu::Buffer,
|
||||||
|
landuse_index_count: u32,
|
||||||
|
water_vertex_buffer: wgpu::Buffer,
|
||||||
|
water_index_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AppState {
|
struct AppState {
|
||||||
nodes: HashMap<(i32, i32, i32), Vec<MapNode>>,
|
nodes: HashMap<(i32, i32, i32), Vec<MapNode>>,
|
||||||
ways: HashMap<(i32, i32, i32), Vec<MapWay>>,
|
ways: HashMap<(i32, i32, i32), Vec<MapWay>>,
|
||||||
buildings: HashMap<(i32, i32, i32), Vec<MapWay>>,
|
buildings: HashMap<(i32, i32, i32), Vec<MapWay>>,
|
||||||
|
landuse: HashMap<(i32, i32, i32), Vec<MapWay>>,
|
||||||
|
water: HashMap<(i32, i32, i32), Vec<MapWay>>,
|
||||||
buffers: HashMap<(i32, i32, i32), std::sync::Arc<TileBuffers>>,
|
buffers: HashMap<(i32, i32, i32), std::sync::Arc<TileBuffers>>,
|
||||||
loaded_tiles: HashSet<(i32, i32, i32)>,
|
loaded_tiles: HashSet<(i32, i32, i32)>,
|
||||||
pending_tiles: HashSet<(i32, i32, i32)>,
|
pending_tiles: HashSet<(i32, i32, i32)>,
|
||||||
@@ -240,7 +246,8 @@ fn get_visible_tiles(camera: &Camera) -> Vec<(i32, i32, i32)> {
|
|||||||
|
|
||||||
#[wasm_bindgen(start)]
|
#[wasm_bindgen(start)]
|
||||||
pub async fn run() {
|
pub async fn run() {
|
||||||
console_log::init_with_level(log::Level::Warn).expect("Could not initialize logger");
|
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||||
|
console_log::init_with_level(log::Level::Warn).expect("Couldn't initialize logger");
|
||||||
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||||
|
|
||||||
let event_loop = EventLoop::new().unwrap();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
@@ -331,6 +338,8 @@ pub async fn run() {
|
|||||||
nodes: HashMap::new(),
|
nodes: HashMap::new(),
|
||||||
ways: HashMap::new(),
|
ways: HashMap::new(),
|
||||||
buildings: HashMap::new(),
|
buildings: HashMap::new(),
|
||||||
|
landuse: HashMap::new(),
|
||||||
|
water: HashMap::new(),
|
||||||
buffers: HashMap::new(),
|
buffers: HashMap::new(),
|
||||||
loaded_tiles: HashSet::new(),
|
loaded_tiles: HashSet::new(),
|
||||||
pending_tiles: HashSet::new(),
|
pending_tiles: HashSet::new(),
|
||||||
@@ -440,6 +449,8 @@ pub async fn run() {
|
|||||||
let pipeline = create_pipeline(&device, &config.format, &camera_bind_group_layout);
|
let pipeline = create_pipeline(&device, &config.format, &camera_bind_group_layout);
|
||||||
let road_pipeline = create_road_pipeline(&device, &config.format, &camera_bind_group_layout);
|
let road_pipeline = create_road_pipeline(&device, &config.format, &camera_bind_group_layout);
|
||||||
let building_pipeline = create_building_pipeline(&device, &config.format, &camera_bind_group_layout);
|
let building_pipeline = create_building_pipeline(&device, &config.format, &camera_bind_group_layout);
|
||||||
|
let landuse_pipeline = create_landuse_pipeline(&device, &config.format, &camera_bind_group_layout);
|
||||||
|
let water_pipeline = create_water_pipeline(&device, &config.format, &camera_bind_group_layout);
|
||||||
|
|
||||||
|
|
||||||
let window_clone = window.clone();
|
let window_clone = window.clone();
|
||||||
@@ -547,6 +558,8 @@ pub async fn run() {
|
|||||||
let mut point_instance_data = Vec::new();
|
let mut point_instance_data = Vec::new();
|
||||||
let mut road_vertex_data = Vec::new();
|
let mut road_vertex_data = Vec::new();
|
||||||
let mut building_vertex_data = Vec::new();
|
let mut building_vertex_data = Vec::new();
|
||||||
|
let mut landuse_vertex_data = Vec::new();
|
||||||
|
let mut water_vertex_data = Vec::new();
|
||||||
|
|
||||||
// Process nodes
|
// Process nodes
|
||||||
if let Some(nodes) = state_guard.nodes.get(tile) {
|
if let Some(nodes) = state_guard.nodes.get(tile) {
|
||||||
@@ -589,7 +602,10 @@ pub async fn run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Earcut triangulation
|
// Earcut triangulation
|
||||||
let indices = earcut(&flat_points, &[], 2).unwrap();
|
let indices = match earcut(&flat_points, &[], 2) {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
for i in indices {
|
for i in indices {
|
||||||
let p = projected_points[i];
|
let p = projected_points[i];
|
||||||
@@ -597,9 +613,61 @@ pub async fn run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process landuse
|
||||||
|
if let Some(landuse) = state_guard.landuse.get(tile) {
|
||||||
|
for area in landuse {
|
||||||
|
if area.points.len() < 3 { continue; }
|
||||||
|
|
||||||
|
let mut flat_points = Vec::new();
|
||||||
|
let mut projected_points = Vec::new();
|
||||||
|
|
||||||
|
for p in &area.points {
|
||||||
|
let (x, y) = project(p[0], p[1]);
|
||||||
|
flat_points.push(x as f64);
|
||||||
|
flat_points.push(y as f64);
|
||||||
|
projected_points.push([x, y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let indices = match earcut(&flat_points, &[], 2) {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
for i in indices {
|
||||||
|
let p = projected_points[i];
|
||||||
|
landuse_vertex_data.push(Vertex { position: p });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process water
|
||||||
|
if let Some(water) = state_guard.water.get(tile) {
|
||||||
|
for area in water {
|
||||||
|
if area.points.len() < 3 { continue; }
|
||||||
|
|
||||||
|
let mut flat_points = Vec::new();
|
||||||
|
let mut projected_points = Vec::new();
|
||||||
|
|
||||||
|
for p in &area.points {
|
||||||
|
let (x, y) = project(p[0], p[1]);
|
||||||
|
flat_points.push(x as f64);
|
||||||
|
flat_points.push(y as f64);
|
||||||
|
projected_points.push([x, y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let indices = match earcut(&flat_points, &[], 2) {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
for i in indices {
|
||||||
|
let p = projected_points[i];
|
||||||
|
water_vertex_data.push(Vertex { position: p });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only create buffers if we have data
|
// Only create buffers if we have data
|
||||||
if !point_instance_data.is_empty() || !road_vertex_data.is_empty() || !building_vertex_data.is_empty() {
|
if !point_instance_data.is_empty() || !road_vertex_data.is_empty() || !building_vertex_data.is_empty() || !landuse_vertex_data.is_empty() || !water_vertex_data.is_empty() {
|
||||||
let point_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let point_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
label: Some("Tile Instance Buffer"),
|
label: Some("Tile Instance Buffer"),
|
||||||
contents: bytemuck::cast_slice(&point_instance_data),
|
contents: bytemuck::cast_slice(&point_instance_data),
|
||||||
@@ -618,6 +686,19 @@ pub async fn run() {
|
|||||||
usage: wgpu::BufferUsages::VERTEX,
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let landuse_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: Some("Tile Landuse Buffer"),
|
||||||
|
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"),
|
||||||
|
contents: bytemuck::cast_slice(&water_vertex_data),
|
||||||
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
|
});
|
||||||
|
|
||||||
state_guard.buffers.insert(*tile, std::sync::Arc::new(TileBuffers {
|
state_guard.buffers.insert(*tile, std::sync::Arc::new(TileBuffers {
|
||||||
point_instance_buffer: point_buffer,
|
point_instance_buffer: point_buffer,
|
||||||
point_count: point_instance_data.len() as u32,
|
point_count: point_instance_data.len() as u32,
|
||||||
@@ -625,6 +706,10 @@ pub async fn run() {
|
|||||||
road_vertex_count: road_vertex_data.len() as u32,
|
road_vertex_count: road_vertex_data.len() as u32,
|
||||||
building_vertex_buffer: building_buffer,
|
building_vertex_buffer: building_buffer,
|
||||||
building_index_count: building_vertex_data.len() as u32,
|
building_index_count: building_vertex_data.len() as u32,
|
||||||
|
landuse_vertex_buffer: landuse_buffer,
|
||||||
|
landuse_index_count: landuse_vertex_data.len() as u32,
|
||||||
|
water_vertex_buffer: water_buffer,
|
||||||
|
water_index_count: water_vertex_data.len() as u32,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -670,6 +755,22 @@ pub async fn run() {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Fetch landuse
|
||||||
|
let url_landuse = format!("http://localhost:3000/api/tiles/{}/{}/{}/landuse", z, x, y);
|
||||||
|
let landuse_data = if let Some(json) = fetch_cached(&url_landuse).await {
|
||||||
|
serde_json::from_str::<Vec<MapWay>>(&json).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fetch water
|
||||||
|
let url_water = format!("http://localhost:3000/api/tiles/{}/{}/{}/water", z, x, y);
|
||||||
|
let water_data = if let Some(json) = fetch_cached(&url_water).await {
|
||||||
|
serde_json::from_str::<Vec<MapWay>>(&json).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut guard = state_clone.lock().unwrap();
|
let mut guard = state_clone.lock().unwrap();
|
||||||
|
|
||||||
if let Some(nodes) = nodes_data {
|
if let Some(nodes) = nodes_data {
|
||||||
@@ -684,6 +785,20 @@ pub async fn run() {
|
|||||||
guard.buildings.insert((z, x, y), buildings);
|
guard.buildings.insert((z, x, y), buildings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
guard.loaded_tiles.insert((z, x, y));
|
guard.loaded_tiles.insert((z, x, y));
|
||||||
guard.pending_tiles.remove(&(z, x, y));
|
guard.pending_tiles.remove(&(z, x, y));
|
||||||
|
|
||||||
@@ -696,7 +811,13 @@ pub async fn run() {
|
|||||||
camera_uniform = camera_uniform_data;
|
camera_uniform = camera_uniform_data;
|
||||||
queue.write_buffer(&camera_buffer, 0, bytemuck::cast_slice(&[camera_uniform]));
|
queue.write_buffer(&camera_buffer, 0, bytemuck::cast_slice(&[camera_uniform]));
|
||||||
|
|
||||||
let frame = surface.get_current_texture().unwrap();
|
let frame = match surface.get_current_texture() {
|
||||||
|
Ok(frame) => frame,
|
||||||
|
Err(e) => {
|
||||||
|
web_sys::console::log_1(&format!("Surface error: {:?}", e).into());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
let view = frame.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
let view = frame.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
|
|
||||||
@@ -736,7 +857,23 @@ pub async fn run() {
|
|||||||
|
|
||||||
// Draw each tile - order: Roads -> Buildings -> Points (back to front)
|
// Draw each tile - order: Roads -> Buildings -> Points (back to front)
|
||||||
for buffers in &tiles_to_render {
|
for buffers in &tiles_to_render {
|
||||||
// Draw Roads (bottom layer)
|
// Draw Water (bottom layer)
|
||||||
|
if buffers.water_index_count > 0 {
|
||||||
|
rpass.set_pipeline(&water_pipeline);
|
||||||
|
rpass.set_bind_group(0, &camera_bind_group, &[]);
|
||||||
|
rpass.set_vertex_buffer(0, buffers.water_vertex_buffer.slice(..));
|
||||||
|
rpass.draw(0..buffers.water_index_count, 0..1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw Landuse (second layer)
|
||||||
|
if buffers.landuse_index_count > 0 {
|
||||||
|
rpass.set_pipeline(&landuse_pipeline);
|
||||||
|
rpass.set_bind_group(0, &camera_bind_group, &[]);
|
||||||
|
rpass.set_vertex_buffer(0, buffers.landuse_vertex_buffer.slice(..));
|
||||||
|
rpass.draw(0..buffers.landuse_index_count, 0..1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw Roads (third layer)
|
||||||
if buffers.road_vertex_count > 0 {
|
if buffers.road_vertex_count > 0 {
|
||||||
rpass.set_pipeline(&road_pipeline);
|
rpass.set_pipeline(&road_pipeline);
|
||||||
rpass.set_bind_group(0, &camera_bind_group, &[]);
|
rpass.set_bind_group(0, &camera_bind_group, &[]);
|
||||||
@@ -1045,3 +1182,191 @@ fn create_building_pipeline(
|
|||||||
multiview: None,
|
multiview: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_landuse_pipeline(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
format: &wgpu::TextureFormat,
|
||||||
|
bind_group_layout: &wgpu::BindGroupLayout
|
||||||
|
) -> wgpu::RenderPipeline {
|
||||||
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: None,
|
||||||
|
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(r#"
|
||||||
|
struct CameraUniform {
|
||||||
|
params: vec4<f32>,
|
||||||
|
};
|
||||||
|
@group(0) @binding(0)
|
||||||
|
var<uniform> camera: CameraUniform;
|
||||||
|
|
||||||
|
struct VertexInput {
|
||||||
|
@location(0) position: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) clip_position: vec4<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main(
|
||||||
|
model: VertexInput,
|
||||||
|
) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
|
||||||
|
let world_pos = model.position;
|
||||||
|
|
||||||
|
let x = world_pos.x * camera.params.x + camera.params.z;
|
||||||
|
let y = world_pos.y * camera.params.y + camera.params.w;
|
||||||
|
|
||||||
|
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
return vec4<f32>(0.6, 0.8, 0.6, 1.0); // Light green for parks
|
||||||
|
}
|
||||||
|
"#)),
|
||||||
|
});
|
||||||
|
|
||||||
|
let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("Landuse Pipeline Layout"),
|
||||||
|
bind_group_layouts: &[bind_group_layout],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Landuse Pipeline"),
|
||||||
|
layout: Some(&render_pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "vs_main",
|
||||||
|
buffers: &[
|
||||||
|
wgpu::VertexBufferLayout {
|
||||||
|
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &[
|
||||||
|
wgpu::VertexAttribute {
|
||||||
|
offset: 0,
|
||||||
|
shader_location: 0,
|
||||||
|
format: wgpu::VertexFormat::Float32x2,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "fs_main",
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format: *format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
strip_index_format: None,
|
||||||
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
|
cull_mode: None,
|
||||||
|
unclipped_depth: false,
|
||||||
|
polygon_mode: wgpu::PolygonMode::Fill,
|
||||||
|
conservative: false,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_water_pipeline(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
format: &wgpu::TextureFormat,
|
||||||
|
bind_group_layout: &wgpu::BindGroupLayout
|
||||||
|
) -> wgpu::RenderPipeline {
|
||||||
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: None,
|
||||||
|
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(r#"
|
||||||
|
struct CameraUniform {
|
||||||
|
params: vec4<f32>,
|
||||||
|
};
|
||||||
|
@group(0) @binding(0)
|
||||||
|
var<uniform> camera: CameraUniform;
|
||||||
|
|
||||||
|
struct VertexInput {
|
||||||
|
@location(0) position: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) clip_position: vec4<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main(
|
||||||
|
model: VertexInput,
|
||||||
|
) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
|
||||||
|
let world_pos = model.position;
|
||||||
|
|
||||||
|
let x = world_pos.x * camera.params.x + camera.params.z;
|
||||||
|
let y = world_pos.y * camera.params.y + camera.params.w;
|
||||||
|
|
||||||
|
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
return vec4<f32>(0.6, 0.7, 0.9, 1.0); // Light blue for water
|
||||||
|
}
|
||||||
|
"#)),
|
||||||
|
});
|
||||||
|
|
||||||
|
let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("Water Pipeline Layout"),
|
||||||
|
bind_group_layouts: &[bind_group_layout],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Water Pipeline"),
|
||||||
|
layout: Some(&render_pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "vs_main",
|
||||||
|
buffers: &[
|
||||||
|
wgpu::VertexBufferLayout {
|
||||||
|
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &[
|
||||||
|
wgpu::VertexAttribute {
|
||||||
|
offset: 0,
|
||||||
|
shader_location: 0,
|
||||||
|
format: wgpu::VertexFormat::Float32x2,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: "fs_main",
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format: *format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
strip_index_format: None,
|
||||||
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
|
cull_mode: None,
|
||||||
|
unclipped_depth: false,
|
||||||
|
polygon_mode: wgpu::PolygonMode::Fill,
|
||||||
|
conservative: false,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
multiview: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ async fn main() -> Result<()> {
|
|||||||
let mut way_count = 0;
|
let mut way_count = 0;
|
||||||
let mut inserted_nodes = 0;
|
let mut inserted_nodes = 0;
|
||||||
let mut inserted_ways = 0;
|
let mut inserted_ways = 0;
|
||||||
|
let mut inserted_buildings = 0;
|
||||||
|
let mut inserted_water = 0;
|
||||||
|
let mut inserted_landuse = 0;
|
||||||
|
|
||||||
// We process sequentially: Nodes first, then Ways.
|
// We process sequentially: Nodes first, then Ways.
|
||||||
reader.for_each(|element| {
|
reader.for_each(|element| {
|
||||||
@@ -83,11 +86,17 @@ async fn main() -> Result<()> {
|
|||||||
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();
|
||||||
|
|
||||||
// Filter for highways/roads OR buildings
|
// Filter for highways/roads OR buildings OR landuse OR water
|
||||||
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) ||
|
||||||
|
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);
|
||||||
|
|
||||||
if is_highway || is_building {
|
if is_highway || is_building || is_water || is_landuse {
|
||||||
let mut points = Vec::new();
|
let mut points = Vec::new();
|
||||||
|
|
||||||
// Resolve nodes
|
// Resolve nodes
|
||||||
@@ -126,14 +135,42 @@ async fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if is_building {
|
if is_building {
|
||||||
// inserted_buildings += 1; // Need to add this counter
|
let tags_clone = tags.clone();
|
||||||
|
let blob_clone = blob.clone();
|
||||||
let session = session.clone();
|
let session = session.clone();
|
||||||
join_set.spawn(async move {
|
join_set.spawn(async move {
|
||||||
let _ = session.query(
|
let _ = session.query(
|
||||||
"INSERT INTO map_data.buildings (zoom, tile_x, tile_y, id, tags, points) VALUES (?, ?, ?, ?, ?, ?)",
|
"INSERT INTO map_data.buildings (zoom, tile_x, tile_y, id, tags, points) VALUES (?, ?, ?, ?, ?, ?)",
|
||||||
(10, x, y, id, tags, blob),
|
(10, x, y, id, tags_clone, blob_clone),
|
||||||
).await;
|
).await;
|
||||||
});
|
});
|
||||||
|
inserted_buildings += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_water {
|
||||||
|
let tags_clone = tags.clone();
|
||||||
|
let blob_clone = blob.clone();
|
||||||
|
let session = session.clone();
|
||||||
|
join_set.spawn(async move {
|
||||||
|
let _ = session.query(
|
||||||
|
"INSERT INTO map_data.water (zoom, tile_x, tile_y, id, tags, points) VALUES (?, ?, ?, ?, ?, ?)",
|
||||||
|
(10, x, y, id, tags_clone, blob_clone),
|
||||||
|
).await;
|
||||||
|
});
|
||||||
|
inserted_water += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_landuse {
|
||||||
|
let tags_clone = tags.clone();
|
||||||
|
let blob_clone = blob.clone();
|
||||||
|
let session = session.clone();
|
||||||
|
join_set.spawn(async move {
|
||||||
|
let _ = session.query(
|
||||||
|
"INSERT INTO map_data.landuse (zoom, tile_x, tile_y, id, tags, points) VALUES (?, ?, ?, ?, ?, ?)",
|
||||||
|
(10, x, y, id, tags_clone, blob_clone),
|
||||||
|
).await;
|
||||||
|
});
|
||||||
|
inserted_landuse += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +183,8 @@ async fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
println!("Finished processing. Nodes: {}, Ways: {}. Inserted Nodes: {}, Inserted Ways: {}", node_count, way_count, inserted_nodes, inserted_ways);
|
println!("Finished processing. Nodes: {}, Ways: {}. Inserted Nodes: {}, Inserted Ways: {}, Buildings: {}, Water: {}, Landuse: {}",
|
||||||
|
node_count, way_count, inserted_nodes, inserted_ways, inserted_buildings, inserted_water, inserted_landuse);
|
||||||
|
|
||||||
println!("Waiting for pending inserts...");
|
println!("Waiting for pending inserts...");
|
||||||
while let Some(_) = join_set.join_next().await {}
|
while let Some(_) = join_set.join_next().await {}
|
||||||
|
|||||||
Reference in New Issue
Block a user