implement phase 5~7
This commit is contained in:
parent
8664a80f1e
commit
6140548774
1 changed files with 591 additions and 6 deletions
77
src/projection.rs
Normal file
77
src/projection.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
use eframe::egui;
|
||||
|
||||
pub trait MapProjection: Send + Sync {
|
||||
fn project(&self, lon: f64, lat: f64, rect: egui::Rect) -> egui::Pos2;
|
||||
fn unproject(&self, pos: egui::Pos2, rect: egui::Rect) -> (f64, f64);
|
||||
fn name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
pub struct Equirectangular;
|
||||
|
||||
impl MapProjection for Equirectangular {
|
||||
fn project(&self, lon: f64, lat: f64, rect: egui::Rect) -> egui::Pos2 {
|
||||
egui::pos2(
|
||||
rect.left() + ((lon + 180.0) / 360.0) as f32 * rect.width(),
|
||||
rect.top() + ((90.0 - lat) / 180.0) as f32 * rect.height(),
|
||||
)
|
||||
}
|
||||
|
||||
fn unproject(&self, pos: egui::Pos2, rect: egui::Rect) -> (f64, f64) {
|
||||
let lon = (pos.x - rect.left()) as f64 / rect.width() as f64 * 360.0 - 180.0;
|
||||
let lat = 90.0 - (pos.y - rect.top()) as f64 / rect.height() as f64 * 180.0;
|
||||
(lon, lat)
|
||||
}
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
"Equirectangular"
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn unit_rect() -> egui::Rect {
|
||||
egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(360.0, 180.0))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_center() {
|
||||
let proj = Equirectangular;
|
||||
let r = unit_rect();
|
||||
let pos = proj.project(0.0, 0.0, r);
|
||||
let (lon, lat) = proj.unproject(pos, r);
|
||||
assert!((lon).abs() < 1e-4);
|
||||
assert!((lat).abs() < 1e-4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_corners() {
|
||||
let proj = Equirectangular;
|
||||
let r = unit_rect();
|
||||
for (lon, lat) in [(-180.0_f64, 90.0_f64), (180.0, -90.0), (-180.0, -90.0), (180.0, 90.0)] {
|
||||
let pos = proj.project(lon, lat, r);
|
||||
let (lon2, lat2) = proj.unproject(pos, r);
|
||||
assert!((lon - lon2).abs() < 1e-4, "lon {lon} → {lon2}");
|
||||
assert!((lat - lat2).abs() < 1e-4, "lat {lat} → {lat2}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn project_prime_meridian_equator() {
|
||||
let proj = Equirectangular;
|
||||
let r = unit_rect();
|
||||
let pos = proj.project(0.0, 0.0, r);
|
||||
assert!((pos.x - 180.0).abs() < 1e-3, "x={}", pos.x);
|
||||
assert!((pos.y - 90.0).abs() < 1e-3, "y={}", pos.y);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rect_scaling() {
|
||||
let proj = Equirectangular;
|
||||
let r = egui::Rect::from_min_size(egui::pos2(10.0, 20.0), egui::vec2(720.0, 360.0));
|
||||
let pos = proj.project(0.0, 0.0, r);
|
||||
assert!((pos.x - 370.0).abs() < 1e-3, "x={}", pos.x);
|
||||
assert!((pos.y - 200.0).abs() < 1e-3, "y={}", pos.y);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue