plexus/geometry/
ops.rs

1use decorum::{Real, R64};
2use num::{Num, NumCast};
3use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub};
4
5use crate::geometry::{self, Duplet, Triplet};
6use crate::Half;
7
8pub trait Normalize {
9    fn normalize(self) -> Self;
10}
11
12pub trait Average: Sized {
13    fn average<I>(values: I) -> Self
14    where
15        I: IntoIterator<Item = Self>;
16}
17
18pub trait Interpolate<T = Self>: Sized {
19    type Output;
20
21    fn lerp(self, other: T, f: R64) -> Self::Output;
22
23    fn midpoint(self, other: T) -> Self::Output {
24        self.lerp(other, Half::half())
25    }
26}
27
28pub trait Dot<T = Self> {
29    type Output;
30
31    fn dot(self, other: T) -> Self::Output;
32}
33
34pub trait Cross<T = Self> {
35    type Output;
36
37    fn cross(self, other: T) -> Self::Output;
38}
39
40pub trait Project<T = Self> {
41    type Output;
42
43    fn project(self, other: T) -> Self::Output;
44}
45
46impl<T> Project<T> for T
47where
48    T: Dot + Clone + Mul<<<Self as Dot>::Output as Div>::Output, Output = Self>,
49    <T as Dot>::Output: Div,
50{
51    type Output = T;
52
53    fn project(self, other: T) -> Self::Output {
54        let n = other.dot(self.clone());
55        let d = self.clone().dot(self.clone());
56        self * (n / d)
57    }
58}
59
60impl<T> Interpolate for Duplet<T>
61where
62    T: Copy + Num + NumCast,
63{
64    type Output = Self;
65
66    fn lerp(self, other: Self, f: R64) -> Self::Output {
67        Duplet(
68            geometry::lerp(self.0, other.0, f),
69            geometry::lerp(self.1, other.1, f),
70        )
71    }
72}
73
74impl<T> Normalize for Duplet<T>
75where
76    T: Real,
77{
78    fn normalize(self) -> Self {
79        let m = (self.0.powi(2) + self.1.powi(2)).sqrt();
80        Duplet(self.0 / m, self.1 / m)
81    }
82}
83
84impl<T> Average for Duplet<T>
85where
86    T: AddAssign + Clone + Num + NumCast,
87{
88    fn average<I>(values: I) -> Self
89    where
90        I: IntoIterator<Item = Self>,
91    {
92        let (n, sum) = {
93            let mut n = T::zero();
94            let mut sum = Duplet(T::zero(), T::zero());
95            for point in values {
96                n += T::one();
97                sum = Duplet(sum.0 + point.0, sum.1 + point.1);
98            }
99            (n, sum)
100        };
101        let m = T::one() / n;
102        Duplet(sum.0 * m.clone(), sum.1 * m)
103    }
104}
105
106impl<T> Dot for Duplet<T>
107where
108    T: Mul,
109    <T as Mul>::Output: Add<Output = T>,
110{
111    type Output = T;
112
113    fn dot(self, other: Self) -> Self::Output {
114        (self.0 * other.0) + (self.1 * other.1)
115    }
116}
117
118impl<T> Interpolate for Triplet<T>
119where
120    T: Copy + Num + NumCast,
121{
122    type Output = Self;
123
124    fn lerp(self, other: Self, f: R64) -> Self::Output {
125        Triplet(
126            geometry::lerp(self.0, other.0, f),
127            geometry::lerp(self.1, other.1, f),
128            geometry::lerp(self.2, other.2, f),
129        )
130    }
131}
132
133impl<T> Normalize for Triplet<T>
134where
135    T: Real,
136{
137    fn normalize(self) -> Self {
138        let m = (self.0.powi(2) + self.1.powi(2) + self.2.powi(2)).sqrt();
139        Triplet(self.0 / m, self.1 / m, self.2 / m)
140    }
141}
142
143impl<T> Average for Triplet<T>
144where
145    T: AddAssign + Clone + Num + NumCast,
146{
147    fn average<I>(values: I) -> Self
148    where
149        I: IntoIterator<Item = Self>,
150    {
151        let (n, sum) = {
152            let mut n = T::zero();
153            let mut sum = Triplet(T::zero(), T::zero(), T::zero());
154            for point in values {
155                n += T::one();
156                sum = Triplet(sum.0 + point.0, sum.1 + point.1, sum.2 + point.2);
157            }
158            (n, sum)
159        };
160        let m = T::one() / n;
161        Triplet(sum.0 * m.clone(), sum.1 * m.clone(), sum.2 * m)
162    }
163}
164
165impl<T> Dot for Triplet<T>
166where
167    T: Mul<Output = T>,
168    <T as Mul>::Output: Add<Output = T>,
169{
170    type Output = T;
171
172    fn dot(self, other: Self) -> Self::Output {
173        (self.0 * other.0) + (self.1 * other.1) + (self.2 * other.2)
174    }
175}
176
177impl<T> Cross for Triplet<T>
178where
179    T: Clone + Mul + Neg,
180    <T as Mul>::Output: Sub<Output = T>,
181    <<T as Mul>::Output as Sub>::Output: Neg<Output = T>,
182{
183    type Output = Self;
184
185    fn cross(self, other: Self) -> Self::Output {
186        Triplet(
187            (self.1.clone() * other.2.clone()) - (self.2.clone() * other.1.clone()),
188            -((self.0.clone() * other.2.clone()) - (self.2 * other.0.clone())),
189            (self.0.clone() * other.1.clone()) - (self.1 * other.0),
190        )
191    }
192}
193
194#[cfg(feature = "geometry-cgmath")]
195mod feature_geometry_cgmath {
196    use cgmath::{
197        BaseFloat, BaseNum, EuclideanSpace, InnerSpace, Point2, Point3, Vector2, Vector3,
198    };
199    use num::{Num, NumCast};
200    use std::ops::AddAssign;
201
202    use crate::geometry;
203    use crate::geometry::ops::*;
204
205    impl<T> Normalize for Vector2<T>
206    where
207        T: BaseFloat,
208    {
209        fn normalize(self) -> Self {
210            <Self as InnerSpace>::normalize(self)
211        }
212    }
213
214    impl<T> Normalize for Vector3<T>
215    where
216        T: BaseFloat,
217    {
218        fn normalize(self) -> Self {
219            <Self as InnerSpace>::normalize(self)
220        }
221    }
222
223    impl<T> Average for Point2<T>
224    where
225        T: AddAssign + BaseNum + NumCast,
226    {
227        fn average<I>(values: I) -> Self
228        where
229            I: IntoIterator<Item = Self>,
230        {
231            let (n, sum) = {
232                let mut n = T::zero();
233                let mut sum = Point2::origin();
234                for point in values {
235                    n += T::one();
236                    sum += Vector2::<T>::new(point.x, point.y);
237                }
238                (n, sum)
239            };
240            sum * (T::one() / n)
241        }
242    }
243
244    impl<T> Average for Point3<T>
245    where
246        T: AddAssign + BaseNum + NumCast,
247    {
248        fn average<I>(values: I) -> Self
249        where
250            I: IntoIterator<Item = Self>,
251        {
252            let (n, sum) = {
253                let mut n = T::zero();
254                let mut sum = Point3::origin();
255                for point in values {
256                    n += T::one();
257                    sum += Vector3::<T>::new(point.x, point.y, point.z);
258                }
259                (n, sum)
260            };
261            sum * (T::one() / n)
262        }
263    }
264
265    impl<T> Interpolate for Point2<T>
266    where
267        T: Num + NumCast,
268    {
269        type Output = Self;
270
271        fn lerp(self, other: Self, f: R64) -> Self::Output {
272            Point2::new(
273                geometry::lerp(self.x, other.x, f),
274                geometry::lerp(self.y, other.y, f),
275            )
276        }
277    }
278
279    impl<T> Interpolate for Point3<T>
280    where
281        T: Num + NumCast,
282    {
283        type Output = Self;
284
285        fn lerp(self, other: Self, f: R64) -> Self::Output {
286            Point3::new(
287                geometry::lerp(self.x, other.x, f),
288                geometry::lerp(self.y, other.y, f),
289                geometry::lerp(self.z, other.z, f),
290            )
291        }
292    }
293
294    impl<T> Interpolate for Vector2<T>
295    where
296        T: Num + NumCast,
297    {
298        type Output = Self;
299
300        fn lerp(self, other: Self, f: R64) -> Self::Output {
301            Vector2::new(
302                geometry::lerp(self.x, other.x, f),
303                geometry::lerp(self.y, other.y, f),
304            )
305        }
306    }
307
308    impl<T> Interpolate for Vector3<T>
309    where
310        T: Num + NumCast,
311    {
312        type Output = Self;
313
314        fn lerp(self, other: Self, f: R64) -> Self::Output {
315            Vector3::new(
316                geometry::lerp(self.x, other.x, f),
317                geometry::lerp(self.y, other.y, f),
318                geometry::lerp(self.z, other.z, f),
319            )
320        }
321    }
322
323    impl<T> Dot for Vector2<T>
324    where
325        T: BaseFloat,
326    {
327        type Output = T;
328
329        fn dot(self, other: Self) -> Self::Output {
330            <Self as InnerSpace>::dot(self, other)
331        }
332    }
333
334    impl<T> Dot for Vector3<T>
335    where
336        T: BaseFloat,
337    {
338        type Output = T;
339
340        fn dot(self, other: Self) -> Self::Output {
341            <Self as InnerSpace>::dot(self, other)
342        }
343    }
344
345    impl<T> Cross for Vector3<T>
346    where
347        T: BaseFloat,
348    {
349        type Output = Self;
350
351        fn cross(self, other: Self) -> Self::Output {
352            Self::cross(self, other)
353        }
354    }
355}
356
357#[cfg(feature = "geometry-mint")]
358mod feature_geometry_mint {
359    use decorum::Real;
360    use mint::{Point2, Point3, Vector2, Vector3};
361    use num::{Num, NumCast};
362    use std::ops::{Add, Mul, Neg, Sub};
363
364    use crate::geometry;
365    use crate::geometry::ops::*;
366
367    impl<T> Normalize for Vector2<T>
368    where
369        T: Real,
370    {
371        fn normalize(self) -> Self {
372            let m = (self.x.powi(2) + self.y.powi(2)).sqrt();
373            Vector2 {
374                x: self.x / m,
375                y: self.y / m,
376            }
377        }
378    }
379
380    impl<T> Normalize for Vector3<T>
381    where
382        T: Real,
383    {
384        fn normalize(self) -> Self {
385            let m = (self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).sqrt();
386            Vector3 {
387                x: self.x / m,
388                y: self.y / m,
389                z: self.z / m,
390            }
391        }
392    }
393
394    impl<T> Average for Point2<T>
395    where
396        T: AddAssign + Clone + Num + NumCast,
397    {
398        fn average<I>(values: I) -> Self
399        where
400            I: IntoIterator<Item = Self>,
401        {
402            let (n, sum) = {
403                let mut n = T::zero();
404                let mut sum = Point2 {
405                    x: T::zero(),
406                    y: T::zero(),
407                };
408                for point in values {
409                    n += T::one();
410                    sum = Point2 {
411                        x: sum.x + point.x,
412                        y: sum.y + point.y,
413                    };
414                }
415                (n, sum)
416            };
417            let m = T::one() / n;
418            Point2 {
419                x: sum.x * m.clone(),
420                y: sum.y * m,
421            }
422        }
423    }
424
425    impl<T> Average for Point3<T>
426    where
427        T: AddAssign + Clone + Num + NumCast,
428    {
429        fn average<I>(values: I) -> Self
430        where
431            I: IntoIterator<Item = Self>,
432        {
433            let (n, sum) = {
434                let mut n = T::zero();
435                let mut sum = Point3 {
436                    x: T::zero(),
437                    y: T::zero(),
438                    z: T::zero(),
439                };
440                for point in values {
441                    n += T::one();
442                    sum = Point3 {
443                        x: sum.x + point.x,
444                        y: sum.y + point.y,
445                        z: sum.z + point.z,
446                    };
447                }
448                (n, sum)
449            };
450            let m = T::one() / n;
451            Point3 {
452                x: sum.x * m.clone(),
453                y: sum.y * m.clone(),
454                z: sum.z * m,
455            }
456        }
457    }
458
459    impl<T> Interpolate for Point2<T>
460    where
461        T: Num + NumCast,
462    {
463        type Output = Self;
464
465        fn lerp(self, other: Self, f: R64) -> Self::Output {
466            Point2 {
467                x: geometry::lerp(self.x, other.x, f),
468                y: geometry::lerp(self.y, other.y, f),
469            }
470        }
471    }
472
473    impl<T> Interpolate for Point3<T>
474    where
475        T: Num + NumCast,
476    {
477        type Output = Self;
478
479        fn lerp(self, other: Self, f: R64) -> Self::Output {
480            Point3 {
481                x: geometry::lerp(self.x, other.x, f),
482                y: geometry::lerp(self.y, other.y, f),
483                z: geometry::lerp(self.z, other.z, f),
484            }
485        }
486    }
487
488    impl<T> Interpolate for Vector2<T>
489    where
490        T: Num + NumCast,
491    {
492        type Output = Self;
493
494        fn lerp(self, other: Self, f: R64) -> Self::Output {
495            Vector2 {
496                x: geometry::lerp(self.x, other.x, f),
497                y: geometry::lerp(self.y, other.y, f),
498            }
499        }
500    }
501
502    impl<T> Interpolate for Vector3<T>
503    where
504        T: Num + NumCast,
505    {
506        type Output = Self;
507
508        fn lerp(self, other: Self, f: R64) -> Self::Output {
509            Vector3 {
510                x: geometry::lerp(self.x, other.x, f),
511                y: geometry::lerp(self.y, other.y, f),
512                z: geometry::lerp(self.z, other.z, f),
513            }
514        }
515    }
516
517    impl<T> Dot for Vector2<T>
518    where
519        T: Mul,
520        <T as Mul>::Output: Add<Output = T>,
521    {
522        type Output = T;
523
524        fn dot(self, other: Self) -> Self::Output {
525            (self.x * other.x) + (self.y * other.y)
526        }
527    }
528
529    impl<T> Dot for Vector3<T>
530    where
531        T: Mul<Output = T>,
532        <T as Mul>::Output: Add<Output = T>,
533    {
534        type Output = T;
535
536        fn dot(self, other: Self) -> Self::Output {
537            (self.x * other.x) + (self.y * other.y) + (self.z * other.z)
538        }
539    }
540
541    impl<T> Cross for Vector3<T>
542    where
543        T: Clone + Mul + Neg,
544        <T as Mul>::Output: Sub<Output = T>,
545        <<T as Mul>::Output as Sub>::Output: Neg<Output = T>,
546    {
547        type Output = Self;
548
549        fn cross(self, other: Self) -> Self::Output {
550            Vector3 {
551                x: (self.y.clone() * other.z.clone()) - (self.z.clone() * other.y.clone()),
552                y: -((self.x.clone() * other.z.clone()) - (self.z * other.x.clone())),
553                z: (self.x.clone() * other.y.clone()) - (self.y * other.x),
554            }
555        }
556    }
557}
558
559#[cfg(feature = "geometry-nalgebra")]
560mod feature_geometry_nalgebra {
561    use decorum::Real;
562    use nalgebra::core::Matrix;
563    use nalgebra::{Point2, Point3, Scalar, Vector2, Vector3};
564    use num::{Num, NumCast, Zero};
565    use std::ops::{AddAssign, Mul, MulAssign, Neg, Sub};
566
567    use crate::geometry;
568    use crate::geometry::ops::*;
569
570    impl<T> Normalize for Vector2<T>
571    where
572        T: Real + Scalar,
573    {
574        // nalgebra provides an implementation via:
575        //
576        // ```rust
577        // Matrix::normalize(&self)
578        // ```
579        //
580        // However, that requires a bound on nalgebra's `Real` trait, which is
581        // only implemented for a limited set of types.
582        fn normalize(self) -> Self {
583            let m = (self.x.powi(2) + self.y.powi(2)).sqrt();
584            Vector2::new(self.x / m, self.y / m)
585        }
586    }
587
588    impl<T> Normalize for Vector3<T>
589    where
590        T: Real + Scalar,
591    {
592        // nalgebra provides an implementation via:
593        //
594        // ```rust
595        // Matrix::normalize(&self)
596        // ```
597        //
598        // However, that requires a bound on nalgebra's `Real` trait, which is
599        // only implemented for a limited set of types.
600        fn normalize(self) -> Self {
601            let m = (self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).sqrt();
602            Vector3::new(self.x / m, self.y / m, self.z / m)
603        }
604    }
605
606    // TODO: Implement `Average` for points and vectors of arbitrary dimension.
607    impl<T> Average for Point2<T>
608    where
609        T: AddAssign + MulAssign + Num + NumCast + Scalar,
610    {
611        fn average<I>(values: I) -> Self
612        where
613            I: IntoIterator<Item = Self>,
614        {
615            let (n, sum) = {
616                let mut n = T::zero();
617                let mut sum = Point2::origin();
618                for point in values {
619                    n += T::one();
620                    sum += Vector2::<T>::new(point.x, point.y);
621                }
622                (n, sum)
623            };
624            sum * (T::one() / n)
625        }
626    }
627
628    impl<T> Average for Point3<T>
629    where
630        T: AddAssign + MulAssign + Num + NumCast + Scalar,
631    {
632        fn average<I>(values: I) -> Self
633        where
634            I: IntoIterator<Item = Self>,
635        {
636            let (n, sum) = {
637                let mut n = T::zero();
638                let mut sum = Point3::origin();
639                for point in values {
640                    n += T::one();
641                    sum += Vector3::<T>::new(point.x, point.y, point.z);
642                }
643                (n, sum)
644            };
645            sum * (T::one() / n)
646        }
647    }
648
649    impl<T> Interpolate for Point2<T>
650    where
651        T: Num + NumCast + Scalar,
652    {
653        type Output = Self;
654
655        fn lerp(self, other: Self, f: R64) -> Self::Output {
656            Point2::new(
657                geometry::lerp(self.x, other.x, f),
658                geometry::lerp(self.y, other.y, f),
659            )
660        }
661    }
662
663    impl<T> Interpolate for Point3<T>
664    where
665        T: Num + NumCast + Scalar,
666    {
667        type Output = Self;
668
669        fn lerp(self, other: Self, f: R64) -> Self::Output {
670            Point3::new(
671                geometry::lerp(self.x, other.x, f),
672                geometry::lerp(self.y, other.y, f),
673                geometry::lerp(self.z, other.z, f),
674            )
675        }
676    }
677
678    impl<T> Interpolate for Vector2<T>
679    where
680        T: Num + NumCast + Scalar,
681    {
682        type Output = Self;
683
684        fn lerp(self, other: Self, f: R64) -> Self::Output {
685            Vector2::new(
686                geometry::lerp(self.x, other.x, f),
687                geometry::lerp(self.y, other.y, f),
688            )
689        }
690    }
691
692    impl<T> Interpolate for Vector3<T>
693    where
694        T: Num + NumCast + Scalar,
695    {
696        type Output = Self;
697
698        fn lerp(self, other: Self, f: R64) -> Self::Output {
699            Vector3::new(
700                geometry::lerp(self.x, other.x, f),
701                geometry::lerp(self.y, other.y, f),
702                geometry::lerp(self.z, other.z, f),
703            )
704        }
705    }
706
707    impl<T> Dot for Vector2<T>
708    where
709        T: AddAssign + Mul<Output = T> + MulAssign + Scalar + Zero,
710    {
711        type Output = T;
712
713        fn dot(self, other: Self) -> Self::Output {
714            Matrix::dot(&self, &other)
715        }
716    }
717
718    impl<T> Dot for Vector3<T>
719    where
720        T: AddAssign + Mul<Output = T> + MulAssign + Scalar + Zero,
721    {
722        type Output = T;
723
724        fn dot(self, other: Self) -> Self::Output {
725            Matrix::dot(&self, &other)
726        }
727    }
728
729    impl<T> Cross for Vector3<T>
730    where
731        T: Mul + Neg + Scalar,
732        <T as Mul>::Output: Sub<Output = T>,
733        <<T as Mul>::Output as Sub>::Output: Neg<Output = T>,
734    {
735        type Output = Self;
736
737        // nalgebra provides an implementation via:
738        //
739        // ```rust
740        // Matrix::cross(&self, &other)
741        // ```
742        //
743        // However, that requires a bound on alga's `AbstractRing` trait.
744        fn cross(self, other: Self) -> Self::Output {
745            Vector3::new(
746                (self.y * other.z) - (self.z * other.y),
747                -((self.x * other.z) - (self.z * other.x)),
748                (self.x * other.y) - (self.y * other.x),
749            )
750        }
751    }
752}