This commit is contained in:
Dongho Kim
2025-12-19 02:24:05 +09:00
parent 1dcdce3ef1
commit 136723ca24
20 changed files with 1422 additions and 603 deletions

View File

@@ -38,6 +38,13 @@ async fn main() -> Result<()> {
// Truncate tables
scylla_repo.truncate_tables().await?;
// Initialize GPU mesh generation service
println!("Initializing GPU mesh generation service...");
let mesh_service = Arc::new(
pollster::block_on(services::mesh_service::MeshGenerationService::new())?
);
println!("Mesh service initialized!");
let path = std::env::var("OSM_PBF_PATH")
.or_else(|_| std::env::var("HOST_PBF_PATH"))
.unwrap_or_else(|_| "europe-latest.osm.pbf".to_string());
@@ -79,9 +86,9 @@ async fn main() -> Result<()> {
let _ = repo.insert_node(zoom, id, lat, lon, tags, x, y).await;
});
}
DbTask::Way { zoom, table, id, tags, points, x, y } => {
DbTask::Way { zoom, table, id, tags, points, vertex_buffer, x, y } => {
join_set.spawn(async move {
let _ = repo.insert_way(table, zoom, id, tags, points, x, y).await;
let _ = repo.insert_way(table, zoom, id, tags, points, vertex_buffer, x, y).await;
});
}
}
@@ -95,8 +102,10 @@ async fn main() -> Result<()> {
// Run the PBF reader in a blocking task
let tx_clone = tx.clone();
let mesh_service_clone = mesh_service.clone();
let reader_handle = tokio::task::spawn_blocking(move || -> Result<(usize, usize, usize)> {
let tx = tx_clone;
let mesh_svc = mesh_service_clone;
let mut node_count = 0;
let mut way_count = 0;
let mut relation_count = 0;
@@ -259,22 +268,140 @@ async fn main() -> Result<()> {
}
if is_highway || treat_as_water_line {
let task = DbTask::Way { zoom: zoom_i32, table: "ways", id, tags: tags.clone(), points: line_blob.clone(), x, y };
// Generate road geometry
let projected_points: Vec<[f32; 2]> = simplified_points.iter()
.map(|(lat, lon)| {
let (x, y) = GeometryService::project(*lat, *lon);
[x, y]
})
.collect();
let highway_tag = tags.get("highway").map(|s| s.as_str());
let road_type = match highway_tag.unwrap_or("") {
"motorway" | "motorway_link" | "trunk" | "trunk_link" => 0.0,
"primary" | "primary_link" => 1.0,
"secondary" | "secondary_link" => 2.0,
_ => 3.0,
};
let default_lanes: f32 = match highway_tag.unwrap_or("") {
"motorway" | "trunk" => 4.0,
"motorway_link" | "trunk_link" | "primary" => 2.0,
_ => 2.0,
};
let lanes: f32 = tags.get("lanes")
.and_then(|s| s.parse().ok())
.unwrap_or(default_lanes);
// DEBUG: Log first way to validate mesh generation
if way_count == 1 {
println!("DEBUG Way {}: {} projected points, generating mesh...", id, projected_points.len());
}
let vertex_buffer = if treat_as_water_line {
mesh_svc.generate_polygon_geometry(&projected_points)
} else {
mesh_svc.generate_road_geometry(&projected_points, lanes, road_type)
};
// DEBUG: Log buffer size
if way_count == 1 {
println!("DEBUG Way {}: vertex_buffer size = {} bytes", id, vertex_buffer.len());
}
let task = DbTask::Way {
zoom: zoom_i32,
table: "ways",
id,
tags: tags.clone(),
points: line_blob.clone(),
vertex_buffer,
x,
y
};
let _ = tx.blocking_send(task);
}
if treat_as_building {
let task = DbTask::Way { zoom: zoom_i32, table: "buildings", id, tags: tags.clone(), points: polygon_blob.clone(), x, y };
// Generate building mesh
let projected_points: Vec<[f32; 2]> = final_points.iter()
.map(|(lat, lon)| {
let (x, y) = GeometryService::project(*lat, *lon);
[x, y]
})
.collect();
let building_type = tags.get("building").map(|s| s.as_str()).unwrap_or("yes");
let color: [f32; 3] = match building_type {
"house" | "apartments" | "residential" | "detached" | "semidetached_house" | "terrace" | "dormitory" =>
[0.95, 0.94, 0.91],
"commercial" | "retail" | "office" | "supermarket" | "kiosk" | "hotel" =>
[0.91, 0.89, 0.86],
"industrial" | "warehouse" | "factory" | "manufacture" =>
[0.85, 0.84, 0.80],
_ => [0.85, 0.85, 0.85],
};
let vertex_buffer = mesh_svc.generate_building_geometry(&projected_points, color);
let task = DbTask::Way {
zoom: zoom_i32,
table: "buildings",
id,
tags: tags.clone(),
points: polygon_blob.clone(),
vertex_buffer,
x,
y
};
let _ = tx.blocking_send(task);
}
if treat_as_water_area {
let task = DbTask::Way { zoom: zoom_i32, table: "water", id, tags: tags.clone(), points: polygon_blob.clone(), x, y };
// Generate water polygon mesh
let projected_points: Vec<[f32; 2]> = final_points.iter()
.map(|(lat, lon)| {
let (x, y) = GeometryService::project(*lat, *lon);
[x, y]
})
.collect();
let vertex_buffer = mesh_svc.generate_polygon_geometry(&projected_points);
let task = DbTask::Way {
zoom: zoom_i32,
table: "water",
id,
tags: tags.clone(),
points: polygon_blob.clone(),
vertex_buffer,
x,
y
};
let _ = tx.blocking_send(task);
}
if treat_as_landuse {
let task = DbTask::Way { zoom: zoom_i32, table: "landuse", id, tags: tags.clone(), points: polygon_blob.clone(), x, y };
// Generate landuse polygon mesh
let projected_points: Vec<[f32; 2]> = final_points.iter()
.map(|(lat, lon)| {
let (x, y) = GeometryService::project(*lat, *lon);
[x, y]
})
.collect();
let vertex_buffer = mesh_svc.generate_polygon_geometry(&projected_points);
let task = DbTask::Way {
zoom: zoom_i32,
table: "landuse",
id,
tags: tags.clone(),
points: polygon_blob.clone(),
vertex_buffer,
x,
y
};
let _ = tx.blocking_send(task);
}
@@ -303,6 +430,20 @@ async fn main() -> Result<()> {
}
}
// Also extract line ref (e.g., S1, U4) from route relations
if let Some(line_ref) = tags.get("ref") {
// Only propagate S-Bahn/U-Bahn style refs (starts with S or U followed by digit)
if (line_ref.starts_with('S') || line_ref.starts_with('U')) && line_ref.len() >= 2 {
let member_count = rel.members().filter(|m| matches!(m.member_type, osmpbf::RelMemberType::Way)).count();
println!("DEBUG: Found transit line ref '{}' with {} way members", line_ref, member_count);
for member in rel.members() {
if let osmpbf::RelMemberType::Way = member.member_type {
railway_store.set_ref(member.member_id, line_ref.clone());
}
}
}
}
if tags.get("type").map(|t| t == "multipolygon").unwrap_or(false) {
let is_water = tags.get("natural").map(|v| v == "water" || v == "wetland" || v == "bay").unwrap_or(false) ||
tags.get("waterway").map(|v| v == "riverbank" || v == "river" || v == "canal").unwrap_or(false) ||
@@ -355,7 +496,27 @@ async fn main() -> Result<()> {
}
let table = if is_water { "water" } else { "landuse" };
let task = DbTask::Way { zoom: zoom_i32, table, id, tags: tags.clone(), points: polygon_blob.clone(), x, y };
// Generate polygon mesh for multipolygons
let projected_points: Vec<[f32; 2]> = final_points.iter()
.map(|(lat, lon)| {
let (x, y) = GeometryService::project(*lat, *lon);
[x, y]
})
.collect();
let vertex_buffer = mesh_svc.generate_polygon_geometry(&projected_points);
let task = DbTask::Way {
zoom: zoom_i32,
table,
id,
tags: tags.clone(),
points: polygon_blob.clone(),
vertex_buffer,
x,
y
};
let _ = tx.blocking_send(task);
}
}
@@ -372,14 +533,18 @@ async fn main() -> Result<()> {
}
})?;
let (railways, colors) = railway_store.into_data();
println!("Inserting {} railway ways with colors...", railways.len());
let (railways, colors, refs) = railway_store.into_data();
println!("Inserting {} railway ways with colors and line refs...", railways.len());
for (id, railway) in railways {
let mut tags = railway.tags;
if let Some(colour) = colors.get(&id) {
tags.insert("colour".to_string(), colour.clone());
}
if let Some(line_ref) = refs.get(&id) {
tags.insert("line_ref".to_string(), line_ref.clone());
}
// Insert for all applicable zoom levels
for &zoom in &FilteringService::ZOOM_LEVELS {
@@ -387,6 +552,41 @@ async fn main() -> Result<()> {
let (x, y) = TileService::lat_lon_to_tile(railway.first_lat, railway.first_lon, zoom);
let zoom_i32 = zoom as i32;
// Parse geometry from blob and generate railway mesh
let mut points: Vec<[f32; 2]> = Vec::new();
for chunk in railway.points.chunks(8) {
if chunk.len() < 8 { break; }
let lat = f32::from_le_bytes(chunk[0..4].try_into().unwrap_or([0u8; 4])) as f64;
let lon = f32::from_le_bytes(chunk[4..8].try_into().unwrap_or([0u8; 4])) as f64;
let (x, y) = GeometryService::project(lat, lon);
points.push([x, y]);
}
// Parse color and rail type
let color_str = tags.get("colour").or(tags.get("color"));
let color = color_str
.map(|c| {
let c = c.trim_start_matches('#');
if c.len() == 6 {
let r = u8::from_str_radix(&c[0..2], 16).unwrap_or(0) as f32 / 255.0;
let g = u8::from_str_radix(&c[2..4], 16).unwrap_or(0) as f32 / 255.0;
let b = u8::from_str_radix(&c[4..6], 16).unwrap_or(0) as f32 / 255.0;
[r, g, b]
} else {
[0.0, 0.0, 0.0]
}
})
.unwrap_or([0.0, 0.0, 0.0]);
let rail_type_str = tags.get("railway").map(|s| s.as_str()).unwrap_or("rail");
let rail_type: f32 = match rail_type_str {
"subway" => 1.0,
"tram" => 2.0,
_ => 0.0,
};
let vertex_buffer = mesh_svc.generate_railway_geometry(&points, color, rail_type);
let task = DbTask::Way {
zoom: zoom_i32,
@@ -394,6 +594,7 @@ async fn main() -> Result<()> {
id,
tags: tags.clone(),
points: railway.points.clone(),
vertex_buffer,
x,
y
};