1use std::ops::{Add, Mul, Neg, Sub};
2
3use crate::{componentwise_min, componentwise_max, Components, Size2D};
4
5#[derive(Copy, Clone, Debug)]
21pub struct Coord2D {
22 pub x: f64,
23 pub y: f64,
24}
25
26impl Components<f64, 2> for Coord2D {
27 fn to_array(self) -> [f64; 2] { [self.x, self.y] }
28 fn from_array(a: [f64; 2]) -> Self { Coord2D { x: a[0], y: a[1] } }
29}
30
31impl From<[f64; 2]> for Coord2D { fn from(a: [f64; 2]) -> Self { Coord2D::from_array(a) } }
32impl From<Coord2D> for [f64; 2] { fn from(c: Coord2D) -> Self { c.to_array() } }
33impl From<(f64, f64)> for Coord2D { fn from(t: (f64, f64)) -> Self { Coord2D { x: t.0, y: t.1 } } }
34
35impl Sub for Coord2D {
37 type Output = CoordOffset;
38 fn sub(self, rhs: Coord2D) -> CoordOffset {
39 CoordOffset { x: self.x - rhs.x, y: self.y - rhs.y }
40 }
41}
42
43impl Add<CoordOffset> for Coord2D {
45 type Output = Coord2D;
46 fn add(self, rhs: CoordOffset) -> Coord2D {
47 Coord2D { x: self.x + rhs.x, y: self.y + rhs.y }
48 }
49}
50impl Sub<CoordOffset> for Coord2D {
51 type Output = Coord2D;
52 fn sub(self, rhs: CoordOffset) -> Coord2D {
53 Coord2D { x: self.x - rhs.x, y: self.y - rhs.y }
54 }
55}
56
57impl Coord2D {
58 pub fn empty() -> Coord2D {
60 Coord2D { x: 0.0, y: 0.0 }
61 }
62 pub fn from(x: f64, y: f64) -> Self {
64 Self { x, y }
65 }
66 pub fn from_tup((x, y): (f64, f64)) -> Self {
68 Self { x, y }
69 }
70 pub fn is_inside(&self, size: Size2D) -> bool {
72 let [w, h] = size.to_array();
73 self.x >= 0.0 && self.y >= 0.0 && self.x <= w as f64 && self.y <= h as f64
74 }
75 pub fn distance_to(&self, other: Coord2D) -> f64 {
77 (*self - other).length()
78 }
79 pub fn midpoint(&self, other: Coord2D) -> Coord2D {
81 Coord2D { x: (self.x + other.x) * 0.5, y: (self.y + other.y) * 0.5 }
82 }
83 pub fn lerp(&self, other: Coord2D, t: f64) -> Coord2D {
85 *self + (other - *self) * t.clamp(0.0, 1.0)
86 }
87 pub fn min(&self, other: Coord2D) -> Coord2D {
89 componentwise_min(*self, other)
90 }
91 pub fn max(&self, other: Coord2D) -> Coord2D {
93 componentwise_max(*self, other)
94 }
95}
96
97#[derive(Copy, Clone, Debug)]
103pub struct CoordOffset {
104 pub x: f64,
105 pub y: f64,
106}
107
108impl Components<f64, 2> for CoordOffset {
109 fn to_array(self) -> [f64; 2] { [self.x, self.y] }
110 fn from_array(a: [f64; 2]) -> Self { CoordOffset { x: a[0], y: a[1] } }
111}
112
113impl From<[f64; 2]> for CoordOffset { fn from(a: [f64; 2]) -> Self { CoordOffset::from_array(a) } }
114impl From<CoordOffset> for [f64; 2] { fn from(v: CoordOffset) -> Self { v.to_array() } }
115impl From<(f64, f64)> for CoordOffset { fn from(t: (f64, f64)) -> Self { CoordOffset { x: t.0, y: t.1 } } }
116
117impl Add for CoordOffset {
118 type Output = CoordOffset;
119 fn add(self, rhs: CoordOffset) -> CoordOffset {
120 CoordOffset { x: self.x + rhs.x, y: self.y + rhs.y }
121 }
122}
123impl Sub for CoordOffset {
124 type Output = CoordOffset;
125 fn sub(self, rhs: CoordOffset) -> CoordOffset {
126 CoordOffset { x: self.x - rhs.x, y: self.y - rhs.y }
127 }
128}
129impl Mul<f64> for CoordOffset {
130 type Output = CoordOffset;
131 fn mul(self, rhs: f64) -> CoordOffset {
132 CoordOffset { x: self.x * rhs, y: self.y * rhs }
133 }
134}
135impl Neg for CoordOffset {
136 type Output = CoordOffset;
137 fn neg(self) -> CoordOffset {
138 CoordOffset { x: -self.x, y: -self.y }
139 }
140}
141
142impl CoordOffset {
143 pub fn empty() -> CoordOffset {
145 CoordOffset { x: 0.0, y: 0.0 }
146 }
147 pub fn from(x: f64, y: f64) -> Self {
149 Self { x, y }
150 }
151 pub fn from_tup((x, y): (f64, f64)) -> Self {
153 Self { x, y }
154 }
155 pub fn is_zero(&self) -> bool {
157 self.x == 0.0 && self.y == 0.0
158 }
159 pub fn length(&self) -> f64 {
161 (self.x * self.x + self.y * self.y).sqrt()
162 }
163 pub fn length_squared(&self) -> f64 {
165 self.x * self.x + self.y * self.y
166 }
167 pub fn normalize(&self) -> CoordOffset {
169 let len = self.length();
170 if len < f64::EPSILON { return CoordOffset { x: 0.0, y: 0.0 }; }
171 CoordOffset { x: self.x / len, y: self.y / len }
172 }
173 pub fn dot(&self, other: CoordOffset) -> f64 {
175 self.x * other.x + self.y * other.y
176 }
177 pub fn lerp(&self, other: CoordOffset, t: f64) -> CoordOffset {
179 *self + (other - *self) * t.clamp(0.0, 1.0)
180 }
181 pub fn min(&self, other: CoordOffset) -> CoordOffset {
183 componentwise_min(*self, other)
184 }
185 pub fn max(&self, other: CoordOffset) -> CoordOffset {
187 componentwise_max(*self, other)
188 }
189}