scad_tree_math/
pt2.rs

1// MIT License
2//
3// Copyright (c) 2023 Michael H. Phillips
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22//
23
24use crate::{dcos, dsin, Pt3};
25
26/// Wraps a `Vec<Pt2>`.
27#[derive(Clone, PartialEq)]
28pub struct Pt2s {
29    inner: Vec<Pt2>,
30}
31
32impl std::ops::Deref for Pt2s {
33    type Target = Vec<Pt2>;
34
35    fn deref(&self) -> &Self::Target {
36        &self.inner
37    }
38}
39
40impl std::ops::DerefMut for Pt2s {
41    fn deref_mut(&mut self) -> &mut Self::Target {
42        &mut self.inner
43    }
44}
45
46impl std::fmt::Display for Pt2s {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        write!(f, "[")?;
49        for i in 0..self.len() - 1 {
50            write!(f, "{},", self[i])?
51        }
52        write!(f, "{}]", self[self.len() - 1])
53    }
54}
55
56impl Pt2s {
57    pub fn new() -> Self {
58        Self { inner: Vec::new() }
59    }
60
61    pub fn with_capacity(capacity: usize) -> Self {
62        Self {
63            inner: Vec::with_capacity(capacity),
64        }
65    }
66
67    pub fn from_pt2s(pt2s: Vec<Pt2>) -> Self {
68        Self { inner: pt2s }
69    }
70
71    pub fn translate(&mut self, point: Pt2) {
72        for pt in self.iter_mut() {
73            *pt = *pt + point
74        }
75    }
76
77    pub fn rotate(&mut self, degrees: f64) -> &mut Self {
78        for p in self.iter_mut() {
79            p.rotate(degrees);
80        }
81        self
82    }
83}
84
85/// A 2D point.
86#[derive(Clone, Copy, Debug, Default, PartialEq)]
87pub struct Pt2 {
88    pub x: f64,
89    pub y: f64,
90}
91
92impl std::fmt::Display for Pt2 {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        write!(f, "[{}, {}]", self.x, self.y)
95    }
96}
97
98impl std::ops::Index<usize> for Pt2 {
99    type Output = f64;
100
101    fn index(&self, index: usize) -> &Self::Output {
102        match index {
103            0 => &self.x,
104            1 => &self.y,
105            _ => panic!("Index {} is out of bounds.", index),
106        }
107    }
108}
109
110impl std::ops::IndexMut<usize> for Pt2 {
111    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
112        match index {
113            0 => &mut self.x,
114            1 => &mut self.y,
115            _ => panic!("Index {} is out of bounds.", index),
116        }
117    }
118}
119
120impl std::ops::Add for Pt2 {
121    type Output = Self;
122
123    fn add(self, rhs: Self) -> Self::Output {
124        Self::new(self.x + rhs.x, self.y + rhs.y)
125    }
126}
127
128impl std::ops::AddAssign for Pt2 {
129    fn add_assign(&mut self, rhs: Self) {
130        *self = *self + rhs;
131    }
132}
133
134impl std::ops::Sub for Pt2 {
135    type Output = Self;
136
137    fn sub(self, rhs: Self) -> Self::Output {
138        Self::new(self.x - rhs.x, self.y - rhs.y)
139    }
140}
141
142impl std::ops::SubAssign for Pt2 {
143    fn sub_assign(&mut self, rhs: Self) {
144        *self = *self - rhs;
145    }
146}
147
148impl std::ops::Mul<f64> for Pt2 {
149    type Output = Self;
150
151    fn mul(self, rhs: f64) -> Self::Output {
152        Self::new(self.x * rhs, self.y * rhs)
153    }
154}
155
156impl std::ops::MulAssign<f64> for Pt2 {
157    fn mul_assign(&mut self, rhs: f64) {
158        *self = *self * rhs;
159    }
160}
161
162impl std::ops::Div<f64> for Pt2 {
163    type Output = Self;
164
165    fn div(self, rhs: f64) -> Self::Output {
166        Self::new(self.x / rhs, self.y / rhs)
167    }
168}
169
170impl std::ops::DivAssign<f64> for Pt2 {
171    fn div_assign(&mut self, rhs: f64) {
172        *self = *self / rhs;
173    }
174}
175
176impl std::ops::Neg for Pt2 {
177    type Output = Self;
178
179    fn neg(self) -> Self::Output {
180        self * -1.0
181    }
182}
183
184impl Pt2 {
185    pub fn new(x: f64, y: f64) -> Self {
186        Self { x, y }
187    }
188
189    pub fn dot(self, rhs: Pt2) -> f64 {
190        self.x * rhs.x + self.y * rhs.y
191    }
192
193    pub fn len2(self) -> f64 {
194        self.dot(self)
195    }
196
197    pub fn len(self) -> f64 {
198        self.len2().sqrt()
199    }
200
201    pub fn normalize(&mut self) {
202        *self /= self.len();
203    }
204
205    pub fn normalized(self) -> Self {
206        let l = self.len();
207        Self::new(self.x / l, self.y / l)
208    }
209
210    pub fn rotate(&mut self, degrees: f64) {
211        *self = self.rotated(degrees);
212    }
213
214    pub fn rotated(self, degrees: f64) -> Self {
215        let c = dcos(degrees);
216        let s = dsin(degrees);
217        Self::new(self.x * c - self.y * s, self.x * s + self.y * c)
218    }
219
220    pub fn lerp(self, b: Self, t: f64) -> Self {
221        self + (b - self) * t
222    }
223
224    pub fn to_xz(self) -> Pt3 {
225        Pt3::new(self.x, 0.0, self.y)
226    }
227
228    pub fn as_pt3(self, z: f64) -> Pt3 {
229        Pt3::new(self.x, self.y, z)
230    }
231}