1#![cfg_attr(feature = "strict", deny(warnings))]
10#![deny(missing_docs)]
11
12#[cfg(feature = "serde1")]
19#[macro_use]
20extern crate serde_derive;
21
22#[cfg(feature = "auto-args")]
23use auto_args::AutoArgs;
24#[cfg(feature = "clapme")]
25use clapme::ClapMe;
26
27use std::fmt::Alignment;
28
29#[derive(Clone, Copy, Debug, PartialEq, Default)]
31#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
32#[cfg_attr(feature = "clapme", derive(ClapMe))]
33#[cfg_attr(feature = "auto-args", derive(AutoArgs))]
34pub struct Vector3d<T> {
35 pub x: T,
37 pub y: T,
39 pub z: T,
41}
42
43impl<T> Vector3d<T> {
44 pub fn new(x: T, y: T, z: T) -> Vector3d<T> {
46 Vector3d { x, y, z }
47 }
48 pub fn dot<U: Mul<T, Output = X>, X: Add<Output = X>>(self, rhs: Vector3d<U>) -> X {
51 rhs.x * self.x + rhs.y * self.y + rhs.z * self.z
52 }
53}
54
55use std::ops::Add;
94impl<T: Add<T, Output = T>> Add<Vector3d<T>> for Vector3d<T> {
95 type Output = Vector3d<T>;
96 fn add(self, rhs: Vector3d<T>) -> Self::Output {
97 Vector3d::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
98 }
99}
100
101use std::ops::Sub;
102impl<T: Sub<T, Output = T>> Sub<Vector3d<T>> for Vector3d<T> {
103 type Output = Vector3d<T>;
104 fn sub(self, rhs: Vector3d<T>) -> Self::Output {
105 Vector3d::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
106 }
107}
108
109use std::iter::Sum;
110impl<T: Add<T, Output = T> + Sum<T>> Sum<Vector3d<T>> for Vector3d<T> {
111 fn sum<I: Iterator<Item = Vector3d<T>>>(mut iter: I) -> Vector3d<T> {
112 if let Some(first) = iter.next() {
113 iter.fold(first, |a, b| a + b)
114 } else {
115 let x: Option<T> = None;
118 let zero_x: T = x.into_iter().sum();
119 let y: Option<T> = None;
120 let zero_y: T = y.into_iter().sum();
121 let z: Option<T> = None;
122 let zero_z: T = z.into_iter().sum();
123 Vector3d::new(zero_x, zero_y, zero_z)
124 }
125 }
126}
127impl<'a, T: 'a + Add<T, Output = T> + Sum<T> + Clone> Sum<&'a Vector3d<T>> for Vector3d<T> {
128 fn sum<I: Iterator<Item = &'a Vector3d<T>>>(iter: I) -> Vector3d<T> {
129 iter.cloned().sum()
130 }
131}
132
133#[test]
134fn sum_f64() {
135 let x: f64 = [0.0, 0.0, 0.1].iter().cloned().sum();
136 assert_eq!(x, 0.1f64);
137 let total: Vector3d<f64> = [Vector3d::new(0.0, 0.0, 0.1), Vector3d::new(0.0, 0.2, 0.0)]
138 .iter()
139 .cloned()
140 .sum();
141 assert_eq!(total, Vector3d::new(0.0, 0.2, 0.1));
142 let total: Vector3d<f64> = [Vector3d::new(0.0, 0.0, 0.1), Vector3d::new(0.0, 0.2, 0.0)]
143 .iter()
144 .sum();
145 assert_eq!(total, Vector3d::new(0.0, 0.2, 0.1));
146}
147
148use std::ops::Neg;
149impl<T: Neg<Output = T>> Neg for Vector3d<T> {
150 type Output = Vector3d<T>;
151 fn neg(self) -> Self::Output {
152 Vector3d::new(-self.x, -self.y, -self.z)
153 }
154}
155
156use std::ops::Mul;
157impl<S: Clone, X, T: Mul<S, Output = X>> Mul<S> for Vector3d<T> {
158 type Output = Vector3d<X>;
159 fn mul(self, rhs: S) -> Self::Output {
160 Vector3d::new(self.x * rhs.clone(), self.y * rhs.clone(), self.z * rhs)
161 }
162}
163
164use std::ops::Div;
165impl<S: Clone, X, T: Div<S, Output = X>> Div<S> for Vector3d<T> {
166 type Output = Vector3d<X>;
167 fn div(self, rhs: S) -> Self::Output {
168 Vector3d::new(self.x / rhs.clone(), self.y / rhs.clone(), self.z / rhs)
169 }
170}
171
172impl<T: Clone> Vector3d<T> {
173 pub fn cross<U: Clone + Mul<T, Output = X>, X: Add<Output = X> + Sub<Output = X>>(
177 self,
178 rhs: Vector3d<U>,
179 ) -> Vector3d<X> {
180 Vector3d::new(
181 rhs.z.clone() * self.y.clone() - rhs.y.clone() * self.z.clone(),
182 rhs.x.clone() * self.z.clone() - rhs.z * self.x.clone(),
183 rhs.y * self.x - rhs.x * self.y,
184 )
185 }
186}
187
188impl<T: Clone + Mul<T, Output = X>, X: Add<Output = X>> Vector3d<T> {
189 pub fn norm2(self) -> X {
191 self.x.clone() * self.x + self.y.clone() * self.y + self.z.clone() * self.z
192 }
193}
194
195use std::ops::Index;
196impl<T> Index<usize> for Vector3d<T> {
197 type Output = T;
198 fn index(&self, index: usize) -> &T {
199 match index {
200 0 => &self.x,
201 1 => &self.y,
202 2 => &self.z,
203 _ => panic!("Invalid index"),
204 }
205 }
206}
207
208use std::ops::IndexMut;
209impl<T> IndexMut<usize> for Vector3d<T> {
210 fn index_mut(&mut self, index: usize) -> &mut T {
211 match index {
212 0 => &mut self.x,
213 1 => &mut self.y,
214 2 => &mut self.z,
215 _ => panic!("Invalid index"),
216 }
217 }
218}
219
220use std::fmt;
221impl<T: fmt::Display> fmt::Display for Vector3d<T> {
222 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223 if let Some(decimals) = f.precision() {
224 let s = format!(
225 "({:.decimals$}, {:.decimals$}, {:.decimals$})",
226 self.x,
227 self.y,
228 self.z,
229 decimals = decimals
230 );
231 if let Some(width) = f.width() {
232 match f.align().unwrap_or(Alignment::Left) {
233 Alignment::Left => write!(f, "{:<width$}", s, width = width),
234 Alignment::Right => write!(f, "{:>width$}", s, width = width),
235 Alignment::Center => write!(f, "{:^width$}", s, width = width),
236 }
237 } else {
238 f.write_str(&s)
239 }
240 } else {
241 let string = format!("({}, {}, {})", self.x, self.y, self.z);
242 f.pad(&string)
243 }
244 }
245}
246
247#[test]
248fn padding_works() {
249 let v = Vector3d::new(0, 0, 0);
250 assert_eq!(&format!("{}", v), "(0, 0, 0)");
251 assert_eq!(&format!("{:10}", v), "(0, 0, 0) ");
252 assert_eq!(&format!("{:<10}", v), "(0, 0, 0) ");
253 assert_eq!(&format!("{:>10}", v), " (0, 0, 0)");
254 assert_eq!(&format!("{:^11}", v), " (0, 0, 0) ");
255 assert_eq!(&format!("{:>11}", v), " (0, 0, 0)");
256
257 let v = Vector3d::new(0., 0., 0.);
258 assert_eq!(&format!("{}", v), "(0, 0, 0)");
259 assert_eq!(&format!("{:.2}", v), "(0.00, 0.00, 0.00)");
260 assert_eq!(&format!("{:19.2}", v), "(0.00, 0.00, 0.00) ");
261 assert_eq!(&format!("{:<19.2}", v), "(0.00, 0.00, 0.00) ");
262 assert_eq!(&format!("{:>19.2}", v), " (0.00, 0.00, 0.00)");
263 assert_eq!(&format!("{:^20.2}", v), " (0.00, 0.00, 0.00) ");
264}