use std::hash::{Hash, Hasher};
use glam::Vec2;
use ordered_float::OrderedFloat;
use crate::handle::Handle;
#[derive(Debug, Default, Clone, PartialEq)]
pub struct Rect {
pub min: Vec2,
pub max: Vec2,
}
impl Rect {
pub fn new(center: Vec2, radius: f32) -> Self {
Self {
min: center - Vec2::splat(radius),
max: center + Vec2::splat(radius),
}
}
pub fn is_touching(&self, other: &Self) -> bool {
!(self.min.x > other.max.x
|| self.max.x < other.min.x
|| self.min.y > other.max.y
|| self.max.y < other.min.y)
}
pub fn contains_pos(&self, pos: Vec2) -> bool {
let Rect { min, max } = self;
pos.x >= min.x && pos.y >= min.y && pos.x <= max.x && pos.y <= max.y
}
pub fn center(&self) -> Vec2 {
(self.min + self.max) * 0.5
}
pub fn size(&self) -> Vec2 {
self.max - self.min
}
pub fn overlap(&self, other: &Self) -> Vec2 {
(self.max - other.min).min(other.max - self.min)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum LinePattern {
Solid,
Dashed { dash_length: f32, gap_length: f32 },
Dotted { spacing: f32 },
}
impl Hash for LinePattern {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
LinePattern::Solid => 0.hash(state),
LinePattern::Dashed {
dash_length,
gap_length,
} => {
1.hash(state);
OrderedFloat(*dash_length).hash(state);
OrderedFloat(*gap_length).hash(state);
}
LinePattern::Dotted { spacing } => {
2.hash(state);
OrderedFloat(*spacing).hash(state);
}
}
}
}
impl Eq for LinePattern {}
impl PartialOrd for LinePattern {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for LinePattern {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(LinePattern::Solid, LinePattern::Solid) => std::cmp::Ordering::Equal,
(LinePattern::Solid, _) => std::cmp::Ordering::Less,
(_, LinePattern::Solid) => std::cmp::Ordering::Greater,
(
LinePattern::Dashed {
dash_length: d1,
gap_length: g1,
},
LinePattern::Dashed {
dash_length: d2,
gap_length: g2,
},
) => OrderedFloat(*d1)
.cmp(&OrderedFloat(*d2))
.then(OrderedFloat(*g1).cmp(&OrderedFloat(*g2))),
(LinePattern::Dashed { .. }, LinePattern::Dotted { .. }) => std::cmp::Ordering::Less,
(LinePattern::Dotted { .. }, LinePattern::Dashed { .. }) => std::cmp::Ordering::Greater,
(LinePattern::Dotted { spacing: s1 }, LinePattern::Dotted { spacing: s2 }) => {
OrderedFloat(*s1).cmp(&OrderedFloat(*s2))
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LineStyle {
pub pattern: LinePattern,
pub offset: f32,
}
impl Hash for LineStyle {
fn hash<H: Hasher>(&self, state: &mut H) {
self.pattern.hash(state);
OrderedFloat(self.offset).hash(state);
}
}
impl Eq for LineStyle {}
impl PartialOrd for LineStyle {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for LineStyle {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.pattern
.cmp(&other.pattern)
.then(OrderedFloat(self.offset).cmp(&OrderedFloat(other.offset)))
}
}
impl Default for LineStyle {
fn default() -> Self {
Self {
pattern: LinePattern::Solid,
offset: 0.0,
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum DrawContent {
Texture(Handle), Line {
vector: Vec2,
thickness: f32,
style: LineStyle,
}, Circle(f32), }
impl Hash for DrawContent {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
DrawContent::Texture(handle) => {
0.hash(state);
handle.id().hash(state);
}
DrawContent::Line {
vector,
thickness,
style,
} => {
1.hash(state);
OrderedFloat(vector.x).hash(state);
OrderedFloat(vector.y).hash(state);
OrderedFloat(*thickness).hash(state);
style.hash(state);
}
DrawContent::Circle(radius) => {
2.hash(state);
OrderedFloat(*radius).hash(state);
}
}
}
}
impl PartialEq for DrawContent {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(DrawContent::Texture(h1), DrawContent::Texture(h2)) => h1.id() == h2.id(),
(
DrawContent::Line {
vector: v1,
thickness: t1,
style: s1,
},
DrawContent::Line {
vector: v2,
thickness: t2,
style: s2,
},
) => {
OrderedFloat(v1.x) == OrderedFloat(v2.x)
&& OrderedFloat(v1.y) == OrderedFloat(v2.y)
&& OrderedFloat(*t1) == OrderedFloat(*t2)
&& s1 == s2
}
(DrawContent::Circle(r1), DrawContent::Circle(r2)) => {
OrderedFloat(*r1) == OrderedFloat(*r2)
}
_ => false,
}
}
}
impl Eq for DrawContent {}
impl PartialOrd for DrawContent {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for DrawContent {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match (self, other) {
(DrawContent::Texture(h1), DrawContent::Texture(h2)) => h1.id().cmp(&h2.id()),
(DrawContent::Texture(_), _) => std::cmp::Ordering::Less,
(_, DrawContent::Texture(_)) => std::cmp::Ordering::Greater,
(
DrawContent::Line {
vector: v1,
thickness: t1,
style: s1,
},
DrawContent::Line {
vector: v2,
thickness: t2,
style: s2,
},
) => OrderedFloat(v1.x)
.cmp(&OrderedFloat(v2.x))
.then(OrderedFloat(v1.y).cmp(&OrderedFloat(v2.y)))
.then(OrderedFloat(*t1).cmp(&OrderedFloat(*t2)))
.then(s1.cmp(s2)),
(DrawContent::Line { .. }, DrawContent::Circle(_)) => std::cmp::Ordering::Less,
(DrawContent::Circle(_), DrawContent::Line { .. }) => std::cmp::Ordering::Greater,
(DrawContent::Circle(r1), DrawContent::Circle(r2)) => {
OrderedFloat(*r1).cmp(&OrderedFloat(*r2))
}
}
}
}
impl DrawContent {
pub fn texture_handle(&self) -> Option<&Handle> {
if let Self::Texture(texture) = self {
Some(texture)
} else {
None
}
}
}