Skip to main content

scad_tree_math/
pt4.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::Pt3;
25
26/// Wraps a `Vec<Pt4>`.
27#[derive(Clone, PartialEq)]
28pub struct Pt4s {
29    inner: Vec<Pt4>,
30}
31
32impl std::ops::Deref for Pt4s {
33    type Target = Vec<Pt4>;
34
35    fn deref(&self) -> &Self::Target {
36        &self.inner
37    }
38}
39
40impl std::ops::DerefMut for Pt4s {
41    fn deref_mut(&mut self) -> &mut Self::Target {
42        &mut self.inner
43    }
44}
45
46impl std::fmt::Display for Pt4s {
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 Pt4s {
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_pt4s(pt4s: Vec<Pt4>) -> Self {
68        Self { inner: pt4s }
69    }
70}
71
72/// A 4D point.
73#[derive(Clone, Copy, Debug, Default, PartialEq)]
74pub struct Pt4 {
75    pub x: f64,
76    pub y: f64,
77    pub z: f64,
78    pub w: f64,
79}
80
81impl std::fmt::Display for Pt4 {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        write!(f, "[{}, {}, {}, {}]", self.x, self.y, self.z, self.w)
84    }
85}
86
87impl std::ops::Index<usize> for Pt4 {
88    type Output = f64;
89
90    fn index(&self, index: usize) -> &Self::Output {
91        match index {
92            0 => &self.x,
93            1 => &self.y,
94            2 => &self.z,
95            3 => &self.w,
96            _ => panic!("Index {} is out of bounds.", index),
97        }
98    }
99}
100
101impl std::ops::IndexMut<usize> for Pt4 {
102    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
103        match index {
104            0 => &mut self.x,
105            1 => &mut self.y,
106            2 => &mut self.z,
107            3 => &mut self.w,
108            _ => panic!("Index {} is out of bounds.", index),
109        }
110    }
111}
112
113impl std::ops::Add for Pt4 {
114    type Output = Self;
115
116    fn add(self, rhs: Self) -> Self::Output {
117        Self::new(
118            self.x + rhs.x,
119            self.y + rhs.y,
120            self.z + rhs.z,
121            self.w + rhs.w,
122        )
123    }
124}
125
126impl std::ops::AddAssign for Pt4 {
127    fn add_assign(&mut self, rhs: Self) {
128        *self = *self + rhs;
129    }
130}
131
132impl std::ops::Sub for Pt4 {
133    type Output = Self;
134
135    fn sub(self, rhs: Self) -> Self::Output {
136        Self::new(
137            self.x - rhs.x,
138            self.y - rhs.y,
139            self.z - rhs.z,
140            self.w - rhs.w,
141        )
142    }
143}
144
145impl std::ops::SubAssign for Pt4 {
146    fn sub_assign(&mut self, rhs: Self) {
147        *self = *self - rhs;
148    }
149}
150
151impl std::ops::Mul<f64> for Pt4 {
152    type Output = Self;
153
154    fn mul(self, rhs: f64) -> Self::Output {
155        Self::new(self.x * rhs, self.y * rhs, self.z * rhs, self.w * rhs)
156    }
157}
158
159impl std::ops::MulAssign<f64> for Pt4 {
160    fn mul_assign(&mut self, rhs: f64) {
161        *self = *self * rhs;
162    }
163}
164
165impl std::ops::Div<f64> for Pt4 {
166    type Output = Self;
167
168    fn div(self, rhs: f64) -> Self::Output {
169        Self::new(self.x / rhs, self.y / rhs, self.z / rhs, self.w / rhs)
170    }
171}
172
173impl std::ops::DivAssign<f64> for Pt4 {
174    fn div_assign(&mut self, rhs: f64) {
175        *self = *self / rhs;
176    }
177}
178
179impl std::ops::Neg for Pt4 {
180    type Output = Self;
181
182    fn neg(self) -> Self::Output {
183        self * -1.0
184    }
185}
186
187impl Pt4 {
188    pub fn new(x: f64, y: f64, z: f64, w: f64) -> Self {
189        Self { x, y, z, w }
190    }
191
192    pub fn dot(self, rhs: Self) -> f64 {
193        self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
194    }
195
196    pub fn cross(self, rhs: Self) -> Self {
197        Pt4::new(
198            self.y * rhs.z - self.z * rhs.y,
199            self.z * rhs.x - self.x * rhs.z,
200            self.x * rhs.y - self.y * rhs.x,
201            0.0,
202        )
203    }
204
205    pub fn len2(self) -> f64 {
206        self.dot(self)
207    }
208
209    pub fn len(self) -> f64 {
210        self.len2().sqrt()
211    }
212
213    pub fn normalize(&mut self) {
214        *self /= self.len();
215    }
216
217    pub fn normalized(self) -> Self {
218        let l = self.len();
219        Self::new(self.x / l, self.y / l, self.z / l, 0.0)
220    }
221
222    pub fn lerp(self, b: Self, t: f64) -> Self {
223        self + (b - self) * t
224    }
225
226    pub fn as_pt3(&self) -> Pt3 {
227        Pt3::new(self.x, self.y, self.z)
228    }
229}