new algorithm for waypoints detection

master
frederic wagner 2022-07-22 17:36:04 +02:00
parent f276e9e4f2
commit f35967d502
2 changed files with 47 additions and 32 deletions

View File

@ -1,4 +1,5 @@
use itertools::Itertools;
use osmio::ObjId;
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::{BufReader, BufWriter, Write};
@ -549,7 +550,7 @@ fn save_svg<'a, P: AsRef<Path>, I: IntoIterator<Item = &'a InterestPoint>>(
waypoints.iter().try_for_each(|p| {
writeln!(
&mut writer,
"<circle cx='{}' cy='{}' fill='black' r='0.8%'/>",
"<circle cx='{}' cy='{}' fill='black' r='0.5%'/>",
p.x, p.y,
)
})?;
@ -558,27 +559,40 @@ fn save_svg<'a, P: AsRef<Path>, I: IntoIterator<Item = &'a InterestPoint>>(
Ok(())
}
fn detect_waypoints(points: &[Point], osm_waypoints: &HashSet<Point>) -> HashSet<Point> {
fn detect_waypoints(
points: &[Point],
osm_waypoints: &HashMap<Point, Vec<ObjId>>,
) -> HashSet<Point> {
points
.first()
.into_iter()
.chain(points.iter().tuple_windows().filter_map(|(p1, p2, p3)| {
if !osm_waypoints.contains(&p2) {
return None;
}
let x1 = p2.x - p1.x;
let y1 = p2.y - p1.y;
let a1 = y1.atan2(x1);
let x2 = p3.x - p2.x;
let y2 = p3.y - p2.y;
let a2 = y2.atan2(x2);
let a = (a2 - a1).abs();
if a <= std::f64::consts::PI / 3.0 || a >= std::f64::consts::PI * 5.0 / 3.0 {
None
} else {
Some(p2)
}
}))
.chain(
points
.iter()
.filter_map(|p: &Point| -> Option<(&Point, &Vec<ObjId>)> {
osm_waypoints.get(p).map(|l| (p, l))
})
.tuple_windows()
.filter_map(|((p1, l1), (p2, _), (p3, l2))| {
if l1.iter().all(|e| !l2.contains(e)) {
let x1 = p2.x - p1.x;
let y1 = p2.y - p1.y;
let a1 = y1.atan2(x1);
let x2 = p3.x - p2.x;
let y2 = p3.y - p2.y;
let a2 = y2.atan2(x2);
let a = (a2 - a1).abs();
if a <= std::f64::consts::PI / 4.0 || a >= std::f64::consts::PI * 7.0 / 4.0
{
None
} else {
Some(p2)
}
} else {
None
}
}),
)
.chain(points.last().into_iter())
.copied()
.collect::<HashSet<_>>()
@ -640,19 +654,20 @@ fn position_interests_along_path(
async fn main() {
let input_file = std::env::args().nth(1).unwrap_or("m.gpx".to_string());
let osm_file = std::env::args().nth(2);
eprintln!("input is {}", input_file);
let p = points(&input_file);
eprintln!("initialy we have {} points", p.len());
let rp = simplify_path(&p, 0.00015);
eprintln!("we now have {} points", rp.len());
let (mut interests, osm_waypoints) = if let Some(osm) = osm_file {
parse_osm_data(osm)
} else {
(Vec::new(), HashSet::new())
(Vec::new(), HashMap::new())
};
eprintln!("input is {}", input_file);
let p = points(&input_file);
eprintln!("initialy we have {} points", p.len());
let rp = simplify_path(&p, 0.00015);
eprintln!("we now have {} points", rp.len());
let waypoints = detect_waypoints(&rp, &osm_waypoints);
eprintln!("we found {} waypoints", waypoints.len());

View File

@ -150,9 +150,9 @@ async fn get_openstreetmap_data(points: &[(f64, f64)]) -> HashSet<InterestPoint>
interest_points
}
pub fn parse_osm_data<P: AsRef<Path>>(path: P) -> (Vec<InterestPoint>, HashSet<Point>) {
pub fn parse_osm_data<P: AsRef<Path>>(path: P) -> (Vec<InterestPoint>, HashMap<Point, Vec<ObjId>>) {
let reader = osmio::read_pbf(path).ok();
let mut crossroads: HashMap<ObjId, usize> = HashMap::new();
let mut crossroads: HashMap<ObjId, Vec<ObjId>> = HashMap::new();
let mut coordinates: HashMap<ObjId, Point> = HashMap::new();
let interests = reader
.map(|mut reader| {
@ -175,7 +175,7 @@ pub fn parse_osm_data<P: AsRef<Path>>(path: P) -> (Vec<InterestPoint>, HashSet<P
osmio::obj_types::ArcOSMObj::Way(w) => {
if !w.is_area() {
for node in w.nodes() {
*crossroads.entry(*node).or_default() += 1;
crossroads.entry(*node).or_default().push(w.id());
}
}
}
@ -188,9 +188,9 @@ pub fn parse_osm_data<P: AsRef<Path>>(path: P) -> (Vec<InterestPoint>, HashSet<P
(
interests,
crossroads
.iter()
.filter(|&(_, c)| *c >= 3)
.filter_map(|(id, _)| coordinates.get(&id).copied())
.into_iter()
.filter(|(_, r)| r.len() >= 2)
.filter_map(|(id, l)| coordinates.get(&id).copied().map(|c| (c, l)))
.collect(),
)
}