use crate::annotation_system::path_system::PathKey;
use crate::annotation_system::region_system::RegionKey;
use crate::annotation_system::waypoint_system::WaypointKey;
use crate::gui_system::internal_math::MercatorPoint;
use crate::gui_system::latitude_longitude::LatitudeLongitude;
use crate::gui_system::map_widget::focus::FocusTarget;
use iced::Color;
use iced::advanced::image::Handle;
use std::fmt::Debug;
pub(crate) enum LabelPosition {
AtMousePosition,
FixGeoLocation(LatitudeLongitude),
}
pub(crate) trait Annotation: Debug {
fn description(&self, cursor: LatitudeLongitude) -> Option<String>;
fn cull_bounds(&self) -> &MercatorRectangle;
fn get_center(&self) -> LatitudeLongitude {
self.cull_bounds().get_center()
}
fn focus_target(&self, fill: f32) -> FocusTarget {
FocusTarget::Area {
bounds: self.cull_bounds().clone(),
fill,
}
}
fn closest_point(&self, position: MercatorPoint) -> ClosestPoint;
fn label_anchor(&self, cursor: LatitudeLongitude) -> LabelPosition;
fn get_flag(&self) -> Option<DirectionFlag>;
fn get_render_information(&self) -> RenderingInformation<'_>;
fn clone_box(&self) -> Box<dyn Annotation>;
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) enum ClosestPoint {
Inside,
Nearest(MercatorPoint),
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
pub enum AnnotationKey {
Waypoint(WaypointKey),
Region(RegionKey),
Path(PathKey),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AnnotationError {
KeyNotContained,
}
impl From<WaypointKey> for AnnotationKey {
fn from(key: WaypointKey) -> Self {
AnnotationKey::Waypoint(key)
}
}
impl From<RegionKey> for AnnotationKey {
fn from(key: RegionKey) -> Self {
AnnotationKey::Region(key)
}
}
impl From<PathKey> for AnnotationKey {
fn from(key: PathKey) -> Self {
AnnotationKey::Path(key)
}
}
#[derive(Debug, Clone)]
pub(crate) struct RenderingClosedShape {
pub(crate) positions_ccw: Vec<LatitudeLongitude>,
pub(crate) core_color: Color,
pub(crate) border_color: Color,
}
pub(crate) enum RenderingInformation<'a> {
Image(Handle),
Cross(Color),
Polygon(&'a RenderingClosedShape),
Line {
positions: &'a [LatitudeLongitude],
color: Color,
},
}
#[derive(Debug, Clone)]
pub struct MercatorRectangle {
pub(crate) min_max_lat: (f64, f64),
pub(crate) min_max_long: (f64, f64),
pub(crate) pixel_padding: f64,
}
#[derive(Debug, Clone)]
pub(crate) struct TopLeftBottomRight {
pub(crate) top_left: LatitudeLongitude,
pub(crate) bottom_right: LatitudeLongitude,
}
impl From<&MercatorRectangle> for TopLeftBottomRight {
fn from(rect: &MercatorRectangle) -> Self {
Self {
top_left: LatitudeLongitude::new(rect.min_max_lat.1, rect.min_max_long.0),
bottom_right: LatitudeLongitude::new(rect.min_max_lat.0, rect.min_max_long.1),
}
}
}
impl MercatorRectangle {
pub fn create_from_position(
position: LatitudeLongitude,
pixel_padding: f64,
) -> MercatorRectangle {
Self {
min_max_lat: (position.latitude, position.latitude),
min_max_long: (position.longitude, position.longitude),
pixel_padding,
}
}
pub fn create_from_position_array(
mut position_array: impl Iterator<Item = LatitudeLongitude>,
pixel_padding: f64,
) -> Option<MercatorRectangle> {
let first = position_array.next()?;
Some(position_array.fold(
Self::create_from_position(first, pixel_padding),
|rect, position| Self {
min_max_lat: (
rect.min_max_lat.0.min(position.latitude),
rect.min_max_lat.1.max(position.latitude),
),
min_max_long: (
rect.min_max_long.0.min(position.longitude),
rect.min_max_long.1.max(position.longitude),
),
..rect
},
))
}
pub fn create_around(
center: LatitudeLongitude,
radius_meter: f64,
pixel_padding: f64,
) -> MercatorRectangle {
Self::create_from_position_array(
center.circle_extremes(radius_meter).into_iter(),
pixel_padding,
)
.expect("Four extreme points")
}
pub fn get_center(&self) -> LatitudeLongitude {
LatitudeLongitude::new(
(self.min_max_lat.0 + self.min_max_lat.1) * 0.5,
(self.min_max_long.0 + self.min_max_long.1) * 0.5,
)
}
pub fn pixel_padding(&self) -> f32 {
self.pixel_padding as f32
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DirectionFlag {
pub color: Color,
pub priority: u8,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_position_array_has_no_rectangle() {
assert!(MercatorRectangle::create_from_position_array(std::iter::empty(), 0.0).is_none());
}
#[test]
fn position_array_rectangle_spans_all_points() {
let rect = MercatorRectangle::create_from_position_array(
[
LatitudeLongitude::new(50.0, 8.0),
LatitudeLongitude::new(48.0, 11.0),
LatitudeLongitude::new(52.0, 9.0),
]
.into_iter(),
3.0,
)
.unwrap();
assert_eq!(rect.min_max_lat, (48.0, 52.0));
assert_eq!(rect.min_max_long, (8.0, 11.0));
}
}