use crate::mercator::{project, unproject};
use egui::Vec2;
pub type Position = geo_types::Point;
pub fn lat_lon(lat: f64, lon: f64) -> Position {
Position::new(lon, lat)
}
pub fn lon_lat(lon: f64, lat: f64) -> Position {
Position::new(lon, lat)
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
pub struct AdjustedPosition {
position: Position,
offset: Pixels,
zoom: f64,
}
impl AdjustedPosition {
pub fn new(position: Position) -> Self {
Self {
position,
offset: Pixels::new(0.0, 0.0),
zoom: 1.0, }
}
pub fn position(&self) -> Position {
unproject(project(self.position, self.zoom) - self.offset, self.zoom)
}
pub fn shift(self, offset: Vec2, zoom: f64) -> Self {
let changed_zoom_factor = 2.0_f64.powf(zoom - self.zoom);
Self {
position: self.position,
offset: self.offset * changed_zoom_factor + Pixels::from_vec2(offset),
zoom,
}
}
pub fn offset_length(&self) -> f32 {
self.offset.to_vec2().length()
}
pub fn half_offset(self) -> Self {
Self {
position: self.position,
offset: self.offset / 2.0,
zoom: self.zoom,
}
}
}
pub type Pixels = geo_types::Point;
pub trait PixelsExt {
fn to_vec2(&self) -> egui::Vec2;
fn from_vec2(_: egui::Vec2) -> Self;
}
impl PixelsExt for Pixels {
fn to_vec2(&self) -> egui::Vec2 {
egui::Vec2::new(self.x() as f32, self.y() as f32)
}
fn from_vec2(vec2: egui::Vec2) -> Self {
Pixels::new(vec2.x as f64, vec2.y as f64)
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
fn base_adjusted_position() -> AdjustedPosition {
AdjustedPosition::new(lat_lon(51.0, 17.0))
}
#[test]
fn shifting_adjusted_position() {
let position = base_adjusted_position().shift(Pixels::new(10.0, 20.0).to_vec2(), 10.0);
assert_relative_eq!(position.position().x(), 16.98626708984377);
assert_relative_eq!(position.position().y(), 51.017281581280216);
let position = base_adjusted_position().shift(Pixels::new(10.0, 20.0).to_vec2(), 2.0);
assert_relative_eq!(position.position().x(), 13.48437500000002);
assert_relative_eq!(position.position().y(), 55.21655462355652);
}
#[test]
fn shifting_adjusted_position_by_nothing() {
let position = base_adjusted_position()
.shift(Pixels::new(10.0, 20.0).to_vec2(), 2.0)
.shift(Pixels::new(0.0, 0.0).to_vec2(), 10.0);
assert_relative_eq!(position.position().x(), 13.48437500000002);
assert_relative_eq!(position.position().y(), 55.21655462355652);
}
#[test]
fn shifting_adjusted_position_using_different_zoom() {
let position = base_adjusted_position()
.shift(Pixels::new(5.0, 10.0).to_vec2(), 10.0)
.shift(Pixels::new(10.0, 20.0).to_vec2(), 11.0);
assert_relative_eq!(position.position().x(), 16.98626708984377);
assert_relative_eq!(position.position().y(), 51.017281581280216);
}
#[test]
fn test_adjusted_position_offset_length() {
let position = base_adjusted_position().shift(Pixels::new(10.0, 0.0).to_vec2(), 10.0);
assert_relative_eq!(position.offset_length(), 10.0);
let position = position.shift(Pixels::new(10.0, 0.0).to_vec2(), 10.0);
assert_relative_eq!(position.offset_length(), 20.0);
}
}