update
This commit is contained in:
@@ -8,7 +8,7 @@ use std::io::{BufWriter, Write, Seek, SeekFrom};
|
||||
use std::path::{Path, PathBuf};
|
||||
use memmap2::Mmap;
|
||||
|
||||
const ZOOM_LEVELS: [u32; 4] = [6, 9, 12, 14];
|
||||
const ZOOM_LEVELS: [u32; 5] = [2, 6, 9, 12, 14];
|
||||
|
||||
struct NodeStore {
|
||||
writer: Option<BufWriter<File>>,
|
||||
@@ -80,6 +80,58 @@ impl NodeStore {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Ramer-Douglas-Peucker simplification
|
||||
fn perpendicular_distance(p: (f64, f64), line_start: (f64, f64), line_end: (f64, f64)) -> f64 {
|
||||
let (x, y) = p;
|
||||
let (x1, y1) = line_start;
|
||||
let (x2, y2) = line_end;
|
||||
|
||||
let dx = x2 - x1;
|
||||
let dy = y2 - y1;
|
||||
|
||||
if dx == 0.0 && dy == 0.0 {
|
||||
return ((x - x1).powi(2) + (y - y1).powi(2)).sqrt();
|
||||
}
|
||||
|
||||
let num = (dy * x - dx * y + x2 * y1 - y2 * x1).abs();
|
||||
let den = (dx.powi(2) + dy.powi(2)).sqrt();
|
||||
|
||||
num / den
|
||||
}
|
||||
|
||||
fn simplify_points(points: &[(f64, f64)], epsilon: f64) -> Vec<(f64, f64)> {
|
||||
if points.len() < 3 {
|
||||
return points.to_vec();
|
||||
}
|
||||
|
||||
let start = points[0];
|
||||
let end = points[points.len() - 1];
|
||||
|
||||
let mut max_dist = 0.0;
|
||||
let mut index = 0;
|
||||
|
||||
for i in 1..points.len() - 1 {
|
||||
let dist = perpendicular_distance(points[i], start, end);
|
||||
if dist > max_dist {
|
||||
max_dist = dist;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if max_dist > epsilon {
|
||||
let mut left = simplify_points(&points[..=index], epsilon);
|
||||
let mut right = simplify_points(&points[index..], epsilon);
|
||||
|
||||
// Remove duplicate point at split
|
||||
left.pop();
|
||||
left.extend(right);
|
||||
left
|
||||
} else {
|
||||
vec![start, end]
|
||||
}
|
||||
}
|
||||
|
||||
fn should_include(tags: &HashMap<String, String>, zoom: u32) -> bool {
|
||||
@@ -92,21 +144,28 @@ fn should_include(tags: &HashMap<String, String>, zoom: u32) -> bool {
|
||||
let waterway = tags.get("waterway").map(|s| s.as_str());
|
||||
|
||||
match zoom {
|
||||
match zoom {
|
||||
2 => {
|
||||
// Space View: Continents and Countries
|
||||
matches!(place, Some("continent" | "country")) ||
|
||||
matches!(natural, Some("water")) // Major water bodies
|
||||
},
|
||||
6 => {
|
||||
matches!(highway, Some("motorway" | "trunk" | "primary" | "secondary")) ||
|
||||
// Enterprise Grade: ONLY Motorways and Trunk roads. No primary/secondary.
|
||||
// ONLY Cities. No nature/landuse.
|
||||
matches!(highway, Some("motorway" | "trunk")) ||
|
||||
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"))
|
||||
matches!(natural, Some("water")) || // Only major water bodies
|
||||
matches!(waterway, Some("river")) // Only major rivers
|
||||
},
|
||||
9 => {
|
||||
matches!(highway, Some("motorway" | "trunk" | "primary" | "secondary")) ||
|
||||
// Enterprise Grade: Add Primary roads.
|
||||
// Add Towns.
|
||||
// Limited nature.
|
||||
matches!(highway, Some("motorway" | "trunk" | "primary")) ||
|
||||
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!(natural, Some("water" | "wood")) ||
|
||||
matches!(waterway, Some("river" | "riverbank"))
|
||||
},
|
||||
12 => {
|
||||
@@ -333,19 +392,36 @@ async fn main() -> Result<()> {
|
||||
// Insert into the tile of the first point
|
||||
let (first_lat, first_lon) = points[0];
|
||||
|
||||
// Serialize points to blob (f64, f64) pairs
|
||||
let mut blob = Vec::with_capacity(points.len() * 16);
|
||||
for (lat, lon) in points {
|
||||
blob.extend_from_slice(&lat.to_be_bytes());
|
||||
blob.extend_from_slice(&lon.to_be_bytes());
|
||||
}
|
||||
|
||||
for &zoom in &ZOOM_LEVELS {
|
||||
if !should_include(&tags, zoom) { continue; }
|
||||
|
||||
// Apply simplification based on zoom level
|
||||
let epsilon = match zoom {
|
||||
2 => 0.1, // Very high simplification
|
||||
6 => 0.005, // High simplification
|
||||
9 => 0.001, // Medium simplification
|
||||
_ => 0.0, // No simplification
|
||||
};
|
||||
|
||||
let simplified_points = if epsilon > 0.0 {
|
||||
simplify_points(&points, epsilon)
|
||||
} else {
|
||||
points.clone()
|
||||
};
|
||||
|
||||
if simplified_points.len() < 2 { continue; }
|
||||
|
||||
let (first_lat, first_lon) = simplified_points[0];
|
||||
let (x, y) = lat_lon_to_tile(first_lat, first_lon, zoom);
|
||||
let zoom_i32 = zoom as i32;
|
||||
|
||||
// Serialize simplified points
|
||||
let mut blob = Vec::with_capacity(simplified_points.len() * 16);
|
||||
for (lat, lon) in simplified_points {
|
||||
blob.extend_from_slice(&lat.to_be_bytes());
|
||||
blob.extend_from_slice(&lon.to_be_bytes());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user