From f276e9e4f2ea91dc3752649642b5290c5d36112f Mon Sep 17 00:00:00 2001 From: frederic wagner Date: Fri, 22 Jul 2022 13:50:53 +0200 Subject: [PATCH] trying some fixes for the various pb --- apps/gipy/ChangeLog | 2 + apps/gipy/TODO | 9 ++-- apps/gipy/app.js | 15 ++---- apps/gipy/gpconv/src/main.rs | 91 +++++++++++++----------------------- apps/gipy/gpconv/src/osm.rs | 27 +++++++++-- 5 files changed, 68 insertions(+), 76 deletions(-) diff --git a/apps/gipy/ChangeLog b/apps/gipy/ChangeLog index 19d8f7b55..1664fc513 100644 --- a/apps/gipy/ChangeLog +++ b/apps/gipy/ChangeLog @@ -30,3 +30,5 @@ * Waypoints information is embedded in file and extracted from comments on points. * Bugfix in map display (last segment was missing + wrong colors). + * Waypoint detections using OSM + sharp angles + * New algorith for direction detection diff --git a/apps/gipy/TODO b/apps/gipy/TODO index 923390335..179b73b2c 100644 --- a/apps/gipy/TODO +++ b/apps/gipy/TODO @@ -1,19 +1,22 @@ * bugs -- waypoints seem wrong -- direction is still shitty on gps -- we are always lost - meters seem to be a bit too long +- direction is still shitty on gps ? +- we are always lost (done ?) +- waypoints seem wrong ? + * additional features +- display direction to nearest point - turn off gps when moving to next waypoint - display distance to next water/toilet - display distance to next waypoint - display average speed - dynamic map rescale - display scale (100m) +- get waypoints from osm - compress path ? diff --git a/apps/gipy/app.js b/apps/gipy/app.js index 6ed2546e9..c77a40f24 100644 --- a/apps/gipy/app.js +++ b/apps/gipy/app.js @@ -541,16 +541,11 @@ function start(fn) { } } if (old_points.length == 4) { - // let's just take average angle of 3 previous segments - let angles_sum = 0; - for (let i = 0; i < 3; i++) { - let p1 = old_points[i]; - let p2 = old_points[i + 1]; - let diff = p2.minus(p1); - let angle = Math.atan2(diff.lat, diff.lon); - angles_sum += angle; - } - status.update_position(position, angles_sum / 3.0); + // let's just take angle of segment between oldest and newest point + let oldest = old_points[0]; + let diff = position.minus(oldest); + let angle = Math.atan2(diff.lat, diff.lon); + status.update_position(position, angle); } else { status.update_position(position, direction); } diff --git a/apps/gipy/gpconv/src/main.rs b/apps/gipy/gpconv/src/main.rs index 57944e1bc..6794b5c2e 100644 --- a/apps/gipy/gpconv/src/main.rs +++ b/apps/gipy/gpconv/src/main.rs @@ -13,17 +13,26 @@ use osm::{parse_osm_data, InterestPoint}; const KEY: u16 = 47490; const FILE_VERSION: u16 = 3; -#[derive(Debug, PartialEq, Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub struct Point { x: f64, y: f64, } +impl PartialEq for Point { + fn eq(&self, other: &Self) -> bool { + (self.x - other.x).abs() < 0.0005 && (self.y - other.y).abs() < 0.0005 + } +} impl Eq for Point {} impl std::hash::Hash for Point { fn hash(&self, state: &mut H) { - unsafe { std::mem::transmute::(self.x) }.hash(state); - unsafe { std::mem::transmute::(self.y) }.hash(state); + let x = format!("{:.4}", self.x); + let y = format!("{:.4}", self.y); + x.hash(state); + y.hash(state); + // unsafe { std::mem::transmute::(self.x) }.hash(state); + // unsafe { std::mem::transmute::(self.y) }.hash(state); } } @@ -58,7 +67,7 @@ impl Point { } } -fn points(filename: &str) -> Vec> { +fn points(filename: &str) -> Vec { let file = File::open(filename).unwrap(); let reader = BufReader::new(file); @@ -66,38 +75,15 @@ fn points(filename: &str) -> Vec> { let mut gpx: Gpx = read(reader).unwrap(); eprintln!("we have {} tracks", gpx.tracks.len()); - let mut points = Vec::new(); - - let mut iter = gpx - .tracks + gpx.tracks .pop() .unwrap() .segments .into_iter() - .flat_map(|segment| segment.points.into_iter()) - .map(|p| { - let geop = p.point(); - ( - Point { - x: geop.x(), - y: geop.y(), - }, - p.comment.is_some(), - ) - }) - .dedup(); - let mut current_segment = iter.next().map(|(p, _)| p).into_iter().collect::>(); - for (p, is_waypoint) in iter { - if is_waypoint { - points.push(current_segment); - current_segment = Vec::new(); - } - current_segment.push(p); - } - let last_point = current_segment.pop(); - points.push(current_segment); - points.extend(last_point.map(|p| vec![p])); - points + .flat_map(|segment| segment.linestring()) + .map(|c| c.x_y()) + .map(|(x, y)| Point { x, y }) + .collect() } // // NOTE: this angles idea could maybe be use to get dp from n^3 to n^2 @@ -553,7 +539,7 @@ fn save_svg<'a, P: AsRef, I: IntoIterator>( for point in interest_points { writeln!( &mut writer, - "", + "", point.point.x, point.point.y, point.color(), @@ -563,7 +549,7 @@ fn save_svg<'a, P: AsRef, I: IntoIterator>( waypoints.iter().try_for_each(|p| { writeln!( &mut writer, - "", + "", p.x, p.y, ) })?; @@ -572,11 +558,14 @@ fn save_svg<'a, P: AsRef, I: IntoIterator>( Ok(()) } -fn detect_waypoints(points: &[Point]) -> HashSet { +fn detect_waypoints(points: &[Point], osm_waypoints: &HashSet) -> HashSet { 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); @@ -652,35 +641,21 @@ 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 mut segmented_points = points(&input_file); - let p = segmented_points - .iter() - .flatten() - .copied() - .collect::>(); + 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()); - eprintln!("we have {} waypoints", segmented_points.len()); - - let mut waypoints = HashSet::new(); - let mut rp = Vec::new(); - for (i1, i2) in (0..segmented_points.len()).tuple_windows() { - if let [s1, s2] = &mut segmented_points[i1..=i2] { - s1.extend(s2.first().copied()); - waypoints.insert(s1.first().copied().unwrap()); - let mut simplified = simplify_path(&s1, 0.00015); - rp.append(&mut simplified); - rp.pop(); - } - } - rp.extend(segmented_points.last().and_then(|l| l.last()).copied()); - - let mut interests = if let Some(osm) = osm_file { + let (mut interests, osm_waypoints) = if let Some(osm) = osm_file { parse_osm_data(osm) } else { - Vec::new() + (Vec::new(), HashSet::new()) }; + + let waypoints = detect_waypoints(&rp, &osm_waypoints); + eprintln!("we found {} waypoints", waypoints.len()); + // let mut interests = parse_osm_data("isere.osm.pbf"); let buckets = position_interests_along_path(&mut interests, &rp, 0.001, 5, 3); // let i = get_openstreetmap_data(&rp).await; diff --git a/apps/gipy/gpconv/src/osm.rs b/apps/gipy/gpconv/src/osm.rs index 17425023a..a862a3638 100644 --- a/apps/gipy/gpconv/src/osm.rs +++ b/apps/gipy/gpconv/src/osm.rs @@ -5,8 +5,8 @@ use openstreetmap_api::{ types::{BoundingBox, Credentials}, Openstreetmap, }; -use osmio::prelude::*; use osmio::OSMObjBase; +use osmio::{prelude::*, ObjId}; use std::collections::{HashMap, HashSet}; use std::path::Path; @@ -150,9 +150,11 @@ async fn get_openstreetmap_data(points: &[(f64, f64)]) -> HashSet interest_points } -pub fn parse_osm_data>(path: P) -> Vec { +pub fn parse_osm_data>(path: P) -> (Vec, HashSet) { let reader = osmio::read_pbf(path).ok(); - reader + let mut crossroads: HashMap = HashMap::new(); + let mut coordinates: HashMap = HashMap::new(); + let interests = reader .map(|mut reader| { let mut interests = Vec::new(); for obj in reader.objects() { @@ -167,13 +169,28 @@ pub fn parse_osm_data>(path: P) -> Vec { }) { interests.push(p); } + coordinates.insert(n.id(), Point { x: lon, y: lat }); }); } - osmio::obj_types::ArcOSMObj::Way(_) => {} + osmio::obj_types::ArcOSMObj::Way(w) => { + if !w.is_area() { + for node in w.nodes() { + *crossroads.entry(*node).or_default() += 1; + } + } + } osmio::obj_types::ArcOSMObj::Relation(_) => {} } } interests }) - .unwrap_or_default() + .unwrap_or_default(); + ( + interests, + crossroads + .iter() + .filter(|&(_, c)| *c >= 3) + .filter_map(|(id, _)| coordinates.get(&id).copied()) + .collect(), + ) }