mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
LonLat to Pt2D more explicit
This commit is contained in:
parent
c7c9fa64df
commit
987f039404
@ -42,10 +42,7 @@ pub fn osm_to_raw_roads(osm_path: &str) -> (map_model::raw_data::Map, map_model:
|
|||||||
osm_xml::UnresolvedReference::Node(id) => match id_to_node.get(&id) {
|
osm_xml::UnresolvedReference::Node(id) => match id_to_node.get(&id) {
|
||||||
Some(node) => {
|
Some(node) => {
|
||||||
bounds.update(node.lon, node.lat);
|
bounds.update(node.lon, node.lat);
|
||||||
pts.push(map_model::raw_data::LonLat {
|
pts.push(map_model::raw_data::LonLat::new(node.lon, node.lat));
|
||||||
longitude: node.lon,
|
|
||||||
latitude: node.lat,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
valid = false;
|
valid = false;
|
||||||
@ -115,10 +112,7 @@ pub fn split_up_roads(
|
|||||||
|
|
||||||
for pt in &intersections {
|
for pt in &intersections {
|
||||||
map.intersections.push(map_model::raw_data::Intersection {
|
map.intersections.push(map_model::raw_data::Intersection {
|
||||||
point: map_model::raw_data::LonLat {
|
point: map_model::raw_data::LonLat::new(pt.x(), pt.y()),
|
||||||
longitude: pt.x(),
|
|
||||||
latitude: pt.y(),
|
|
||||||
},
|
|
||||||
elevation_meters: elevation.get(pt.x(), pt.y()),
|
elevation_meters: elevation.get(pt.x(), pt.y()),
|
||||||
has_traffic_signal: false,
|
has_traffic_signal: false,
|
||||||
});
|
});
|
||||||
|
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
use aabb_quadtree::QuadTree;
|
use aabb_quadtree::QuadTree;
|
||||||
use aabb_quadtree::geom::{Point, Rect};
|
use aabb_quadtree::geom::{Point, Rect};
|
||||||
use map_model::{BuildingID, IntersectionID, Map, ParcelID, Pt2D, RoadID, TurnID};
|
use map_model::{raw_data, BuildingID, IntersectionID, Map, ParcelID, Pt2D, RoadID, TurnID};
|
||||||
use map_model::{geometry, raw_data};
|
|
||||||
use render::building::DrawBuilding;
|
use render::building::DrawBuilding;
|
||||||
use render::intersection::DrawIntersection;
|
use render::intersection::DrawIntersection;
|
||||||
use render::parcel::DrawParcel;
|
use render::parcel::DrawParcel;
|
||||||
@ -73,13 +72,8 @@ impl DrawMap {
|
|||||||
|
|
||||||
// min_y here due to the wacky y inversion
|
// min_y here due to the wacky y inversion
|
||||||
let bounds = map.get_gps_bounds();
|
let bounds = map.get_gps_bounds();
|
||||||
let max_screen_pt = geometry::gps_to_screen_space(
|
let max_screen_pt =
|
||||||
&raw_data::LonLat {
|
Pt2D::from_gps(&raw_data::LonLat::new(bounds.max_x, bounds.min_y), &bounds);
|
||||||
longitude: bounds.max_x,
|
|
||||||
latitude: bounds.min_y,
|
|
||||||
},
|
|
||||||
&bounds,
|
|
||||||
);
|
|
||||||
let map_bbox = Rect {
|
let map_bbox = Rect {
|
||||||
top_left: Point { x: 0.0, y: 0.0 },
|
top_left: Point { x: 0.0, y: 0.0 },
|
||||||
bottom_right: Point {
|
bottom_right: Point {
|
||||||
|
@ -39,10 +39,9 @@ pub fn load(
|
|||||||
for pt in text.split(" ") {
|
for pt in text.split(" ") {
|
||||||
if let Some((lon, lat)) = parse_pt(pt) {
|
if let Some((lon, lat)) = parse_pt(pt) {
|
||||||
if b.contains(lon, lat) {
|
if b.contains(lon, lat) {
|
||||||
parcel.points.push(map_model::raw_data::LonLat {
|
parcel
|
||||||
longitude: lon,
|
.points
|
||||||
latitude: lat,
|
.push(map_model::raw_data::LonLat::new(lon, lat));
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
ok = false;
|
ok = false;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use aabb_quadtree::geom::{Point, Rect};
|
|||||||
use dimensioned::si;
|
use dimensioned::si;
|
||||||
use graphics::math::Vec2d;
|
use graphics::math::Vec2d;
|
||||||
use polyline;
|
use polyline;
|
||||||
use raw_data;
|
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use vecmath;
|
use vecmath;
|
||||||
|
|
||||||
@ -157,24 +156,6 @@ pub fn get_bbox_for_polygons(polygons: &[Vec<Vec2d>]) -> Rect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gps_to_screen_space(gps: &raw_data::LonLat, b: &Bounds) -> Pt2D {
|
|
||||||
let gps_x = gps.longitude;
|
|
||||||
let gps_y = gps.latitude;
|
|
||||||
|
|
||||||
// If not, havoc ensues
|
|
||||||
assert!(b.contains(gps_x, gps_y));
|
|
||||||
|
|
||||||
// Invert y, so that the northernmost latitude is 0. Screen drawing order, not Cartesian grid.
|
|
||||||
let base = Pt2D::new(b.min_x, b.max_y);
|
|
||||||
// Apparently the aabb_quadtree can't handle 0, so add a bit.
|
|
||||||
// TODO epsilon or epsilon - 1.0?
|
|
||||||
let dx = base.gps_dist_meters(&Pt2D::new(gps_x, base.y())) + f64::EPSILON;
|
|
||||||
let dy = base.gps_dist_meters(&Pt2D::new(base.x(), gps_y)) + f64::EPSILON;
|
|
||||||
// By default, 1 meter is one pixel. Normal zooming can change that. If we did scaling here,
|
|
||||||
// then we'd have to update all of the other constants too.
|
|
||||||
Pt2D::new(dx, dy)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn circle(center_x: f64, center_y: f64, radius: f64) -> [f64; 4] {
|
pub fn circle(center_x: f64, center_y: f64, radius: f64) -> [f64; 4] {
|
||||||
[
|
[
|
||||||
center_x - radius,
|
center_x - radius,
|
||||||
|
@ -32,6 +32,7 @@ pub use map::Map;
|
|||||||
use ordered_float::NotNaN;
|
use ordered_float::NotNaN;
|
||||||
pub use parcel::{Parcel, ParcelID};
|
pub use parcel::{Parcel, ParcelID};
|
||||||
pub use polyline::{polygons_for_polyline, shift_line, shift_polyline};
|
pub use polyline::{polygons_for_polyline, shift_line, shift_polyline};
|
||||||
|
use raw_data::LonLat;
|
||||||
pub use road::{LaneType, Road, RoadID};
|
pub use road::{LaneType, Road, RoadID};
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -76,12 +77,32 @@ pub struct Pt2D {
|
|||||||
|
|
||||||
impl Pt2D {
|
impl Pt2D {
|
||||||
pub fn new(x: f64, y: f64) -> Pt2D {
|
pub fn new(x: f64, y: f64) -> Pt2D {
|
||||||
assert!(x >= 0.0);
|
// TODO enforce after fixing:
|
||||||
assert!(y >= 0.0);
|
// - shift_polyline goes OOB sometimes
|
||||||
|
// - convert_map uses this for GPS I think?
|
||||||
Pt2D {
|
if x < 0.0 || y < 0.0 {
|
||||||
x, y
|
println!("Bad pt: {}, {}", x, y);
|
||||||
}
|
}
|
||||||
|
//assert!(x >= 0.0);
|
||||||
|
//assert!(y >= 0.0);
|
||||||
|
|
||||||
|
Pt2D { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_gps(gps: &LonLat, b: &Bounds) -> Pt2D {
|
||||||
|
// If not, havoc ensues
|
||||||
|
assert!(b.contains(gps.longitude, gps.latitude));
|
||||||
|
|
||||||
|
// Invert y, so that the northernmost latitude is 0. Screen drawing order, not Cartesian grid.
|
||||||
|
let base = raw_data::LonLat::new(b.min_x, b.max_y);
|
||||||
|
|
||||||
|
// Apparently the aabb_quadtree can't handle 0, so add a bit.
|
||||||
|
// TODO epsilon or epsilon - 1.0?
|
||||||
|
let dx = base.gps_dist_meters(LonLat::new(gps.longitude, base.latitude)) + f64::EPSILON;
|
||||||
|
let dy = base.gps_dist_meters(LonLat::new(base.longitude, gps.latitude)) + f64::EPSILON;
|
||||||
|
// By default, 1 meter is one pixel. Normal zooming can change that. If we did scaling here,
|
||||||
|
// then we'd have to update all of the other constants too.
|
||||||
|
Pt2D::new(dx, dy)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn x(&self) -> f64 {
|
pub fn x(&self) -> f64 {
|
||||||
@ -92,24 +113,6 @@ impl Pt2D {
|
|||||||
self.y
|
self.y
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO move to LonLat
|
|
||||||
// Interprets the Pt2D as GPS coordinates, using Haversine distance
|
|
||||||
pub fn gps_dist_meters(&self, other: &Pt2D) -> f64 {
|
|
||||||
let earth_radius_m = 6371000.0;
|
|
||||||
let lon1 = self.x().to_radians();
|
|
||||||
let lon2 = other.x().to_radians();
|
|
||||||
let lat1 = self.y().to_radians();
|
|
||||||
let lat2 = other.y().to_radians();
|
|
||||||
|
|
||||||
let delta_lat = lat2 - lat1;
|
|
||||||
let delta_lon = lon2 - lon1;
|
|
||||||
|
|
||||||
let a = (delta_lat / 2.0).sin().powi(2)
|
|
||||||
+ (delta_lon / 2.0).sin().powi(2) * lat1.cos() * lat2.cos();
|
|
||||||
let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
|
|
||||||
earth_radius_m * c
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO probably remove this
|
// TODO probably remove this
|
||||||
pub fn to_vec(&self) -> Vec2d {
|
pub fn to_vec(&self) -> Vec2d {
|
||||||
[self.x(), self.y()]
|
[self.x(), self.y()]
|
||||||
@ -123,6 +126,7 @@ impl fmt::Display for Pt2D {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO argh, use this in kml too
|
// TODO argh, use this in kml too
|
||||||
|
// TODO this maybe represents LonLat only?
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Bounds {
|
pub struct Bounds {
|
||||||
pub min_x: f64,
|
pub min_x: f64,
|
||||||
|
@ -6,7 +6,6 @@ use Pt2D;
|
|||||||
use Road;
|
use Road;
|
||||||
use RoadID;
|
use RoadID;
|
||||||
use geo;
|
use geo;
|
||||||
use geometry;
|
|
||||||
use ordered_float::NotNaN;
|
use ordered_float::NotNaN;
|
||||||
use raw_data;
|
use raw_data;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -20,7 +19,7 @@ pub(crate) fn make_building(
|
|||||||
// TODO consume data, so we dont have to clone tags?
|
// TODO consume data, so we dont have to clone tags?
|
||||||
let points = b.points
|
let points = b.points
|
||||||
.iter()
|
.iter()
|
||||||
.map(|coord| geometry::gps_to_screen_space(coord, bounds))
|
.map(|coord| Pt2D::from_gps(coord, bounds))
|
||||||
.collect();
|
.collect();
|
||||||
let front_path = find_front_path(&points, &b.osm_tags, roads);
|
let front_path = find_front_path(&points, &b.osm_tags, roads);
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ impl Map {
|
|||||||
|
|
||||||
for (idx, i) in data.intersections.iter().enumerate() {
|
for (idx, i) in data.intersections.iter().enumerate() {
|
||||||
let id = IntersectionID(idx);
|
let id = IntersectionID(idx);
|
||||||
let pt = geometry::gps_to_screen_space(&i.point, &bounds);
|
let pt = Pt2D::from_gps(&i.point, &bounds);
|
||||||
m.intersections.push(Intersection {
|
m.intersections.push(Intersection {
|
||||||
id,
|
id,
|
||||||
point: pt,
|
point: pt,
|
||||||
@ -72,7 +72,7 @@ impl Map {
|
|||||||
|
|
||||||
let mut unshifted_pts: Vec<Pt2D> = r.points
|
let mut unshifted_pts: Vec<Pt2D> = r.points
|
||||||
.iter()
|
.iter()
|
||||||
.map(|coord| geometry::gps_to_screen_space(&coord, &bounds))
|
.map(|coord| Pt2D::from_gps(coord, &bounds))
|
||||||
.collect();
|
.collect();
|
||||||
if lane.reverse_pts {
|
if lane.reverse_pts {
|
||||||
unshifted_pts.reverse();
|
unshifted_pts.reverse();
|
||||||
@ -136,7 +136,7 @@ impl Map {
|
|||||||
id: ParcelID(idx),
|
id: ParcelID(idx),
|
||||||
points: p.points
|
points: p.points
|
||||||
.iter()
|
.iter()
|
||||||
.map(|coord| geometry::gps_to_screen_space(coord, &bounds))
|
.map(|coord| Pt2D::from_gps(coord, &bounds))
|
||||||
.collect(),
|
.collect(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,33 @@ pub struct LonLat {
|
|||||||
pub latitude: f64,
|
pub latitude: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LonLat {
|
||||||
|
pub fn new(lon: f64, lat: f64) -> LonLat {
|
||||||
|
LonLat {
|
||||||
|
longitude: lon,
|
||||||
|
latitude: lat,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO use dimensioned?
|
||||||
|
pub fn gps_dist_meters(&self, other: LonLat) -> f64 {
|
||||||
|
// Haversine distance
|
||||||
|
let earth_radius_m = 6371000.0;
|
||||||
|
let lon1 = self.longitude.to_radians();
|
||||||
|
let lon2 = other.longitude.to_radians();
|
||||||
|
let lat1 = self.latitude.to_radians();
|
||||||
|
let lat2 = other.latitude.to_radians();
|
||||||
|
|
||||||
|
let delta_lat = lat2 - lat1;
|
||||||
|
let delta_lon = lon2 - lon1;
|
||||||
|
|
||||||
|
let a = (delta_lat / 2.0).sin().powi(2)
|
||||||
|
+ (delta_lon / 2.0).sin().powi(2) * lat1.cos() * lat2.cos();
|
||||||
|
let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
|
||||||
|
earth_radius_m * c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct Road {
|
pub struct Road {
|
||||||
pub points: Vec<LonLat>,
|
pub points: Vec<LonLat>,
|
||||||
|
Loading…
Reference in New Issue
Block a user