1use crate::num::*;
11use crate::UnknownUnit;
12use crate::{point2, point3, vec2, vec3, Box2D, Box3D, Rect, Size2D};
13use crate::{Point2D, Point3D, Transform2D, Transform3D, Vector2D, Vector3D};
14
15use core::cmp::{Eq, PartialEq};
16use core::fmt;
17use core::hash::Hash;
18use core::marker::PhantomData;
19use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
20
21#[cfg(feature = "bytemuck")]
22use bytemuck::{Pod, Zeroable};
23use num_traits::NumCast;
24#[cfg(feature = "serde")]
25use serde::{Deserialize, Serialize};
26
27#[repr(C)]
48#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
49#[cfg_attr(
50 feature = "serde",
51 serde(bound(
52 serialize = "T: serde::Serialize",
53 deserialize = "T: serde::Deserialize<'de>"
54 ))
55)]
56pub struct Translation2D<T, Src, Dst> {
57 pub x: T,
58 pub y: T,
59 #[doc(hidden)]
60 pub _unit: PhantomData<(Src, Dst)>,
61}
62
63#[cfg(feature = "arbitrary")]
64impl<'a, T, Src, Dst> arbitrary::Arbitrary<'a> for Translation2D<T, Src, Dst>
65where
66 T: arbitrary::Arbitrary<'a>,
67{
68 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
69 let (x, y) = arbitrary::Arbitrary::arbitrary(u)?;
70 Ok(Translation2D {
71 x,
72 y,
73 _unit: PhantomData,
74 })
75 }
76}
77
78impl<T: Copy, Src, Dst> Copy for Translation2D<T, Src, Dst> {}
79
80impl<T: Clone, Src, Dst> Clone for Translation2D<T, Src, Dst> {
81 fn clone(&self) -> Self {
82 Translation2D {
83 x: self.x.clone(),
84 y: self.y.clone(),
85 _unit: PhantomData,
86 }
87 }
88}
89
90impl<T, Src, Dst> Eq for Translation2D<T, Src, Dst> where T: Eq {}
91
92impl<T, Src, Dst> PartialEq for Translation2D<T, Src, Dst>
93where
94 T: PartialEq,
95{
96 fn eq(&self, other: &Self) -> bool {
97 self.x == other.x && self.y == other.y
98 }
99}
100
101impl<T, Src, Dst> Hash for Translation2D<T, Src, Dst>
102where
103 T: Hash,
104{
105 fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
106 self.x.hash(h);
107 self.y.hash(h);
108 }
109}
110
111impl<T, Src, Dst> Translation2D<T, Src, Dst> {
112 #[inline]
113 pub const fn new(x: T, y: T) -> Self {
114 Translation2D {
115 x,
116 y,
117 _unit: PhantomData,
118 }
119 }
120
121 #[inline]
122 pub fn splat(v: T) -> Self
123 where
124 T: Clone,
125 {
126 Translation2D {
127 x: v.clone(),
128 y: v,
129 _unit: PhantomData,
130 }
131 }
132
133 #[inline]
135 pub fn identity() -> Self
136 where
137 T: Zero,
138 {
139 Self::new(T::zero(), T::zero())
140 }
141
142 #[inline]
153 pub fn is_identity(&self) -> bool
154 where
155 T: Zero + PartialEq,
156 {
157 let _0 = T::zero();
158 self.x == _0 && self.y == _0
159 }
160
161 #[inline]
163 pub fn transform_size(&self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
164 Size2D::new(s.width, s.height)
165 }
166}
167
168impl<T: Copy, Src, Dst> Translation2D<T, Src, Dst> {
169 #[inline]
171 pub fn to_vector(&self) -> Vector2D<T, Src> {
172 vec2(self.x, self.y)
173 }
174
175 #[inline]
177 pub fn to_array(&self) -> [T; 2] {
178 [self.x, self.y]
179 }
180
181 #[inline]
183 pub fn to_tuple(&self) -> (T, T) {
184 (self.x, self.y)
185 }
186
187 #[inline]
189 pub fn to_untyped(&self) -> Translation2D<T, UnknownUnit, UnknownUnit> {
190 Translation2D {
191 x: self.x,
192 y: self.y,
193 _unit: PhantomData,
194 }
195 }
196
197 #[inline]
199 pub fn from_untyped(t: &Translation2D<T, UnknownUnit, UnknownUnit>) -> Self {
200 Translation2D {
201 x: t.x,
202 y: t.y,
203 _unit: PhantomData,
204 }
205 }
206
207 #[inline]
209 pub fn to_transform(&self) -> Transform2D<T, Src, Dst>
210 where
211 T: Zero + One,
212 {
213 (*self).into()
214 }
215
216 #[inline]
218 pub fn transform_point(&self, p: Point2D<T, Src>) -> Point2D<T::Output, Dst>
219 where
220 T: Add,
221 {
222 point2(p.x + self.x, p.y + self.y)
223 }
224
225 #[inline]
227 pub fn transform_rect(&self, r: &Rect<T, Src>) -> Rect<T::Output, Dst>
228 where
229 T: Add<Output = T>,
230 {
231 Rect {
232 origin: self.transform_point(r.origin),
233 size: self.transform_size(r.size),
234 }
235 }
236
237 #[inline]
239 pub fn transform_box(&self, r: &Box2D<T, Src>) -> Box2D<T::Output, Dst>
240 where
241 T: Add,
242 {
243 Box2D {
244 min: self.transform_point(r.min),
245 max: self.transform_point(r.max),
246 }
247 }
248
249 #[inline]
251 pub fn inverse(&self) -> Translation2D<T::Output, Dst, Src>
252 where
253 T: Neg,
254 {
255 Translation2D::new(-self.x, -self.y)
256 }
257}
258
259impl<T: NumCast + Copy, Src, Dst> Translation2D<T, Src, Dst> {
260 #[inline]
266 pub fn cast<NewT: NumCast>(self) -> Translation2D<NewT, Src, Dst> {
267 self.try_cast().unwrap()
268 }
269
270 pub fn try_cast<NewT: NumCast>(self) -> Option<Translation2D<NewT, Src, Dst>> {
276 match (NumCast::from(self.x), NumCast::from(self.y)) {
277 (Some(x), Some(y)) => Some(Translation2D::new(x, y)),
278 _ => None,
279 }
280 }
281
282 #[inline]
286 pub fn to_f32(self) -> Translation2D<f32, Src, Dst> {
287 self.cast()
288 }
289
290 #[inline]
292 pub fn to_f64(self) -> Translation2D<f64, Src, Dst> {
293 self.cast()
294 }
295
296 #[inline]
302 pub fn to_usize(self) -> Translation2D<usize, Src, Dst> {
303 self.cast()
304 }
305
306 #[inline]
312 pub fn to_u32(self) -> Translation2D<u32, Src, Dst> {
313 self.cast()
314 }
315
316 #[inline]
322 pub fn to_i32(self) -> Translation2D<i32, Src, Dst> {
323 self.cast()
324 }
325
326 #[inline]
332 pub fn to_i64(self) -> Translation2D<i64, Src, Dst> {
333 self.cast()
334 }
335}
336
337#[cfg(feature = "bytemuck")]
338unsafe impl<T: Zeroable, Src, Dst> Zeroable for Translation2D<T, Src, Dst> {}
339
340#[cfg(feature = "bytemuck")]
341unsafe impl<T: Pod, Src: 'static, Dst: 'static> Pod for Translation2D<T, Src, Dst> {}
342
343impl<T: Add, Src, Dst1, Dst2> Add<Translation2D<T, Dst1, Dst2>> for Translation2D<T, Src, Dst1> {
344 type Output = Translation2D<T::Output, Src, Dst2>;
345
346 fn add(self, other: Translation2D<T, Dst1, Dst2>) -> Self::Output {
347 Translation2D::new(self.x + other.x, self.y + other.y)
348 }
349}
350
351impl<T: AddAssign, Src, Dst> AddAssign<Translation2D<T, Dst, Dst>> for Translation2D<T, Src, Dst> {
352 fn add_assign(&mut self, other: Translation2D<T, Dst, Dst>) {
353 self.x += other.x;
354 self.y += other.y;
355 }
356}
357
358impl<T: Sub, Src, Dst1, Dst2> Sub<Translation2D<T, Dst1, Dst2>> for Translation2D<T, Src, Dst2> {
359 type Output = Translation2D<T::Output, Src, Dst1>;
360
361 fn sub(self, other: Translation2D<T, Dst1, Dst2>) -> Self::Output {
362 Translation2D::new(self.x - other.x, self.y - other.y)
363 }
364}
365
366impl<T: SubAssign, Src, Dst> SubAssign<Translation2D<T, Dst, Dst>> for Translation2D<T, Src, Dst> {
367 fn sub_assign(&mut self, other: Translation2D<T, Dst, Dst>) {
368 self.x -= other.x;
369 self.y -= other.y;
370 }
371}
372
373impl<T, Src, Dst> From<Vector2D<T, Src>> for Translation2D<T, Src, Dst> {
374 fn from(v: Vector2D<T, Src>) -> Self {
375 Translation2D::new(v.x, v.y)
376 }
377}
378
379impl<T, Src, Dst> From<Translation2D<T, Src, Dst>> for Vector2D<T, Src> {
380 fn from(t: Translation2D<T, Src, Dst>) -> Self {
381 vec2(t.x, t.y)
382 }
383}
384
385impl<T, Src, Dst> From<Translation2D<T, Src, Dst>> for Transform2D<T, Src, Dst>
386where
387 T: Zero + One,
388{
389 fn from(t: Translation2D<T, Src, Dst>) -> Self {
390 Transform2D::translation(t.x, t.y)
391 }
392}
393
394impl<T, Src, Dst> Default for Translation2D<T, Src, Dst>
395where
396 T: Zero,
397{
398 fn default() -> Self {
399 Self::identity()
400 }
401}
402
403impl<T: fmt::Debug, Src, Dst> fmt::Debug for Translation2D<T, Src, Dst> {
404 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
405 write!(f, "Translation({:?},{:?})", self.x, self.y)
406 }
407}
408
409#[repr(C)]
414pub struct Translation3D<T, Src, Dst> {
415 pub x: T,
416 pub y: T,
417 pub z: T,
418 #[doc(hidden)]
419 pub _unit: PhantomData<(Src, Dst)>,
420}
421
422#[cfg(feature = "arbitrary")]
423impl<'a, T, Src, Dst> arbitrary::Arbitrary<'a> for Translation3D<T, Src, Dst>
424where
425 T: arbitrary::Arbitrary<'a>,
426{
427 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
428 let (x, y, z) = arbitrary::Arbitrary::arbitrary(u)?;
429 Ok(Translation3D {
430 x,
431 y,
432 z,
433 _unit: PhantomData,
434 })
435 }
436}
437
438impl<T: Copy, Src, Dst> Copy for Translation3D<T, Src, Dst> {}
439
440impl<T: Clone, Src, Dst> Clone for Translation3D<T, Src, Dst> {
441 fn clone(&self) -> Self {
442 Translation3D {
443 x: self.x.clone(),
444 y: self.y.clone(),
445 z: self.z.clone(),
446 _unit: PhantomData,
447 }
448 }
449}
450
451#[cfg(feature = "serde")]
452impl<'de, T, Src, Dst> serde::Deserialize<'de> for Translation3D<T, Src, Dst>
453where
454 T: serde::Deserialize<'de>,
455{
456 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
457 where
458 D: serde::Deserializer<'de>,
459 {
460 let (x, y, z) = serde::Deserialize::deserialize(deserializer)?;
461 Ok(Translation3D {
462 x,
463 y,
464 z,
465 _unit: PhantomData,
466 })
467 }
468}
469
470#[cfg(feature = "serde")]
471impl<T, Src, Dst> serde::Serialize for Translation3D<T, Src, Dst>
472where
473 T: serde::Serialize,
474{
475 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
476 where
477 S: serde::Serializer,
478 {
479 (&self.x, &self.y, &self.z).serialize(serializer)
480 }
481}
482
483impl<T, Src, Dst> Eq for Translation3D<T, Src, Dst> where T: Eq {}
484
485impl<T, Src, Dst> PartialEq for Translation3D<T, Src, Dst>
486where
487 T: PartialEq,
488{
489 fn eq(&self, other: &Self) -> bool {
490 self.x == other.x && self.y == other.y && self.z == other.z
491 }
492}
493
494impl<T, Src, Dst> Hash for Translation3D<T, Src, Dst>
495where
496 T: Hash,
497{
498 fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
499 self.x.hash(h);
500 self.y.hash(h);
501 self.z.hash(h);
502 }
503}
504
505impl<T, Src, Dst> Translation3D<T, Src, Dst> {
506 #[inline]
507 pub const fn new(x: T, y: T, z: T) -> Self {
508 Translation3D {
509 x,
510 y,
511 z,
512 _unit: PhantomData,
513 }
514 }
515
516 #[inline]
517 pub fn splat(v: T) -> Self
518 where
519 T: Clone,
520 {
521 Translation3D {
522 x: v.clone(),
523 y: v.clone(),
524 z: v,
525 _unit: PhantomData,
526 }
527 }
528
529 #[inline]
531 pub fn identity() -> Self
532 where
533 T: Zero,
534 {
535 Translation3D::new(T::zero(), T::zero(), T::zero())
536 }
537
538 #[inline]
550 pub fn is_identity(&self) -> bool
551 where
552 T: Zero + PartialEq,
553 {
554 let _0 = T::zero();
555 self.x == _0 && self.y == _0 && self.z == _0
556 }
557
558 #[inline]
560 pub fn transform_size(self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
561 Size2D::new(s.width, s.height)
562 }
563}
564
565impl<T: Copy, Src, Dst> Translation3D<T, Src, Dst> {
566 #[inline]
568 pub fn to_vector(&self) -> Vector3D<T, Src> {
569 vec3(self.x, self.y, self.z)
570 }
571
572 #[inline]
574 pub fn to_array(&self) -> [T; 3] {
575 [self.x, self.y, self.z]
576 }
577
578 #[inline]
580 pub fn to_tuple(&self) -> (T, T, T) {
581 (self.x, self.y, self.z)
582 }
583
584 #[inline]
586 pub fn to_untyped(&self) -> Translation3D<T, UnknownUnit, UnknownUnit> {
587 Translation3D {
588 x: self.x,
589 y: self.y,
590 z: self.z,
591 _unit: PhantomData,
592 }
593 }
594
595 #[inline]
597 pub fn from_untyped(t: &Translation3D<T, UnknownUnit, UnknownUnit>) -> Self {
598 Translation3D {
599 x: t.x,
600 y: t.y,
601 z: t.z,
602 _unit: PhantomData,
603 }
604 }
605
606 #[inline]
608 pub fn to_transform(&self) -> Transform3D<T, Src, Dst>
609 where
610 T: Zero + One,
611 {
612 (*self).into()
613 }
614
615 #[inline]
617 pub fn transform_point3d(&self, p: &Point3D<T, Src>) -> Point3D<T::Output, Dst>
618 where
619 T: Add,
620 {
621 point3(p.x + self.x, p.y + self.y, p.z + self.z)
622 }
623
624 #[inline]
626 pub fn transform_point2d(&self, p: &Point2D<T, Src>) -> Point2D<T::Output, Dst>
627 where
628 T: Add,
629 {
630 point2(p.x + self.x, p.y + self.y)
631 }
632
633 #[inline]
635 pub fn transform_box2d(&self, b: &Box2D<T, Src>) -> Box2D<T::Output, Dst>
636 where
637 T: Add,
638 {
639 Box2D {
640 min: self.transform_point2d(&b.min),
641 max: self.transform_point2d(&b.max),
642 }
643 }
644
645 #[inline]
647 pub fn transform_box3d(&self, b: &Box3D<T, Src>) -> Box3D<T::Output, Dst>
648 where
649 T: Add,
650 {
651 Box3D {
652 min: self.transform_point3d(&b.min),
653 max: self.transform_point3d(&b.max),
654 }
655 }
656
657 #[inline]
659 pub fn transform_rect(&self, r: &Rect<T, Src>) -> Rect<T, Dst>
660 where
661 T: Add<Output = T>,
662 {
663 Rect {
664 origin: self.transform_point2d(&r.origin),
665 size: self.transform_size(r.size),
666 }
667 }
668
669 #[inline]
671 pub fn inverse(&self) -> Translation3D<T::Output, Dst, Src>
672 where
673 T: Neg,
674 {
675 Translation3D::new(-self.x, -self.y, -self.z)
676 }
677}
678
679impl<T: NumCast + Copy, Src, Dst> Translation3D<T, Src, Dst> {
680 #[inline]
686 pub fn cast<NewT: NumCast>(self) -> Translation3D<NewT, Src, Dst> {
687 self.try_cast().unwrap()
688 }
689
690 pub fn try_cast<NewT: NumCast>(self) -> Option<Translation3D<NewT, Src, Dst>> {
696 match (
697 NumCast::from(self.x),
698 NumCast::from(self.y),
699 NumCast::from(self.z),
700 ) {
701 (Some(x), Some(y), Some(z)) => Some(Translation3D::new(x, y, z)),
702 _ => None,
703 }
704 }
705
706 #[inline]
710 pub fn to_f32(self) -> Translation3D<f32, Src, Dst> {
711 self.cast()
712 }
713
714 #[inline]
716 pub fn to_f64(self) -> Translation3D<f64, Src, Dst> {
717 self.cast()
718 }
719
720 #[inline]
726 pub fn to_usize(self) -> Translation3D<usize, Src, Dst> {
727 self.cast()
728 }
729
730 #[inline]
736 pub fn to_u32(self) -> Translation3D<u32, Src, Dst> {
737 self.cast()
738 }
739
740 #[inline]
746 pub fn to_i32(self) -> Translation3D<i32, Src, Dst> {
747 self.cast()
748 }
749
750 #[inline]
756 pub fn to_i64(self) -> Translation3D<i64, Src, Dst> {
757 self.cast()
758 }
759}
760
761#[cfg(feature = "bytemuck")]
762unsafe impl<T: Zeroable, Src, Dst> Zeroable for Translation3D<T, Src, Dst> {}
763
764#[cfg(feature = "bytemuck")]
765unsafe impl<T: Pod, Src: 'static, Dst: 'static> Pod for Translation3D<T, Src, Dst> {}
766
767impl<T: Add, Src, Dst1, Dst2> Add<Translation3D<T, Dst1, Dst2>> for Translation3D<T, Src, Dst1> {
768 type Output = Translation3D<T::Output, Src, Dst2>;
769
770 fn add(self, other: Translation3D<T, Dst1, Dst2>) -> Self::Output {
771 Translation3D::new(self.x + other.x, self.y + other.y, self.z + other.z)
772 }
773}
774
775impl<T: AddAssign, Src, Dst> AddAssign<Translation3D<T, Dst, Dst>> for Translation3D<T, Src, Dst> {
776 fn add_assign(&mut self, other: Translation3D<T, Dst, Dst>) {
777 self.x += other.x;
778 self.y += other.y;
779 self.z += other.z;
780 }
781}
782
783impl<T: Sub, Src, Dst1, Dst2> Sub<Translation3D<T, Dst1, Dst2>> for Translation3D<T, Src, Dst2> {
784 type Output = Translation3D<T::Output, Src, Dst1>;
785
786 fn sub(self, other: Translation3D<T, Dst1, Dst2>) -> Self::Output {
787 Translation3D::new(self.x - other.x, self.y - other.y, self.z - other.z)
788 }
789}
790
791impl<T: SubAssign, Src, Dst> SubAssign<Translation3D<T, Dst, Dst>> for Translation3D<T, Src, Dst> {
792 fn sub_assign(&mut self, other: Translation3D<T, Dst, Dst>) {
793 self.x -= other.x;
794 self.y -= other.y;
795 self.z -= other.z;
796 }
797}
798
799impl<T, Src, Dst> From<Vector3D<T, Src>> for Translation3D<T, Src, Dst> {
800 fn from(v: Vector3D<T, Src>) -> Self {
801 Translation3D::new(v.x, v.y, v.z)
802 }
803}
804
805impl<T, Src, Dst> From<Translation3D<T, Src, Dst>> for Vector3D<T, Src> {
806 fn from(t: Translation3D<T, Src, Dst>) -> Self {
807 vec3(t.x, t.y, t.z)
808 }
809}
810
811impl<T, Src, Dst> From<Translation3D<T, Src, Dst>> for Transform3D<T, Src, Dst>
812where
813 T: Zero + One,
814{
815 fn from(t: Translation3D<T, Src, Dst>) -> Self {
816 Transform3D::translation(t.x, t.y, t.z)
817 }
818}
819
820impl<T, Src, Dst> Default for Translation3D<T, Src, Dst>
821where
822 T: Zero,
823{
824 fn default() -> Self {
825 Self::identity()
826 }
827}
828
829impl<T: fmt::Debug, Src, Dst> fmt::Debug for Translation3D<T, Src, Dst> {
830 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
831 write!(f, "Translation({:?},{:?},{:?})", self.x, self.y, self.z)
832 }
833}
834
835#[cfg(test)]
836mod _2d {
837 #[test]
838 fn simple() {
839 use crate::{rect, Rect, Translation2D};
840
841 struct A;
842 struct B;
843
844 type Translation = Translation2D<i32, A, B>;
845 type SrcRect = Rect<i32, A>;
846 type DstRect = Rect<i32, B>;
847
848 let tx = Translation::new(10, -10);
849 let r1: SrcRect = rect(10, 20, 30, 40);
850 let r2: DstRect = tx.transform_rect(&r1);
851 assert_eq!(r2, rect(20, 10, 30, 40));
852
853 let inv_tx = tx.inverse();
854 assert_eq!(inv_tx.transform_rect(&r2), r1);
855
856 assert!((tx + inv_tx).is_identity());
857 }
858
859 mod ops {
861 use crate::default::Translation2D;
862
863 #[test]
864 fn test_add() {
865 let t1 = Translation2D::new(1.0, 2.0);
866 let t2 = Translation2D::new(3.0, 4.0);
867 assert_eq!(t1 + t2, Translation2D::new(4.0, 6.0));
868
869 let t1 = Translation2D::new(1.0, 2.0);
870 let t2 = Translation2D::new(0.0, 0.0);
871 assert_eq!(t1 + t2, Translation2D::new(1.0, 2.0));
872
873 let t1 = Translation2D::new(1.0, 2.0);
874 let t2 = Translation2D::new(-3.0, -4.0);
875 assert_eq!(t1 + t2, Translation2D::new(-2.0, -2.0));
876
877 let t1 = Translation2D::new(0.0, 0.0);
878 let t2 = Translation2D::new(0.0, 0.0);
879 assert_eq!(t1 + t2, Translation2D::new(0.0, 0.0));
880 }
881
882 #[test]
883 pub fn test_add_assign() {
884 let mut t = Translation2D::new(1.0, 2.0);
885 t += Translation2D::new(3.0, 4.0);
886 assert_eq!(t, Translation2D::new(4.0, 6.0));
887
888 let mut t = Translation2D::new(1.0, 2.0);
889 t += Translation2D::new(0.0, 0.0);
890 assert_eq!(t, Translation2D::new(1.0, 2.0));
891
892 let mut t = Translation2D::new(1.0, 2.0);
893 t += Translation2D::new(-3.0, -4.0);
894 assert_eq!(t, Translation2D::new(-2.0, -2.0));
895
896 let mut t = Translation2D::new(0.0, 0.0);
897 t += Translation2D::new(0.0, 0.0);
898 assert_eq!(t, Translation2D::new(0.0, 0.0));
899 }
900
901 #[test]
902 pub fn test_sub() {
903 let t1 = Translation2D::new(1.0, 2.0);
904 let t2 = Translation2D::new(3.0, 4.0);
905 assert_eq!(t1 - t2, Translation2D::new(-2.0, -2.0));
906
907 let t1 = Translation2D::new(1.0, 2.0);
908 let t2 = Translation2D::new(0.0, 0.0);
909 assert_eq!(t1 - t2, Translation2D::new(1.0, 2.0));
910
911 let t1 = Translation2D::new(1.0, 2.0);
912 let t2 = Translation2D::new(-3.0, -4.0);
913 assert_eq!(t1 - t2, Translation2D::new(4.0, 6.0));
914
915 let t1 = Translation2D::new(0.0, 0.0);
916 let t2 = Translation2D::new(0.0, 0.0);
917 assert_eq!(t1 - t2, Translation2D::new(0.0, 0.0));
918 }
919
920 #[test]
921 pub fn test_sub_assign() {
922 let mut t = Translation2D::new(1.0, 2.0);
923 t -= Translation2D::new(3.0, 4.0);
924 assert_eq!(t, Translation2D::new(-2.0, -2.0));
925
926 let mut t = Translation2D::new(1.0, 2.0);
927 t -= Translation2D::new(0.0, 0.0);
928 assert_eq!(t, Translation2D::new(1.0, 2.0));
929
930 let mut t = Translation2D::new(1.0, 2.0);
931 t -= Translation2D::new(-3.0, -4.0);
932 assert_eq!(t, Translation2D::new(4.0, 6.0));
933
934 let mut t = Translation2D::new(0.0, 0.0);
935 t -= Translation2D::new(0.0, 0.0);
936 assert_eq!(t, Translation2D::new(0.0, 0.0));
937 }
938 }
939}
940
941#[cfg(test)]
942mod _3d {
943 #[test]
944 fn simple() {
945 use crate::{point3, Point3D, Translation3D};
946
947 struct A;
948 struct B;
949
950 type Translation = Translation3D<i32, A, B>;
951 type SrcPoint = Point3D<i32, A>;
952 type DstPoint = Point3D<i32, B>;
953
954 let tx = Translation::new(10, -10, 100);
955 let p1: SrcPoint = point3(10, 20, 30);
956 let p2: DstPoint = tx.transform_point3d(&p1);
957 assert_eq!(p2, point3(20, 10, 130));
958
959 let inv_tx = tx.inverse();
960 assert_eq!(inv_tx.transform_point3d(&p2), p1);
961
962 assert!((tx + inv_tx).is_identity());
963 }
964
965 mod ops {
967 use crate::default::Translation3D;
968
969 #[test]
970 pub fn test_add() {
971 let t1 = Translation3D::new(1.0, 2.0, 3.0);
972 let t2 = Translation3D::new(4.0, 5.0, 6.0);
973 assert_eq!(t1 + t2, Translation3D::new(5.0, 7.0, 9.0));
974
975 let t1 = Translation3D::new(1.0, 2.0, 3.0);
976 let t2 = Translation3D::new(0.0, 0.0, 0.0);
977 assert_eq!(t1 + t2, Translation3D::new(1.0, 2.0, 3.0));
978
979 let t1 = Translation3D::new(1.0, 2.0, 3.0);
980 let t2 = Translation3D::new(-4.0, -5.0, -6.0);
981 assert_eq!(t1 + t2, Translation3D::new(-3.0, -3.0, -3.0));
982
983 let t1 = Translation3D::new(0.0, 0.0, 0.0);
984 let t2 = Translation3D::new(0.0, 0.0, 0.0);
985 assert_eq!(t1 + t2, Translation3D::new(0.0, 0.0, 0.0));
986 }
987
988 #[test]
989 pub fn test_add_assign() {
990 let mut t = Translation3D::new(1.0, 2.0, 3.0);
991 t += Translation3D::new(4.0, 5.0, 6.0);
992 assert_eq!(t, Translation3D::new(5.0, 7.0, 9.0));
993
994 let mut t = Translation3D::new(1.0, 2.0, 3.0);
995 t += Translation3D::new(0.0, 0.0, 0.0);
996 assert_eq!(t, Translation3D::new(1.0, 2.0, 3.0));
997
998 let mut t = Translation3D::new(1.0, 2.0, 3.0);
999 t += Translation3D::new(-4.0, -5.0, -6.0);
1000 assert_eq!(t, Translation3D::new(-3.0, -3.0, -3.0));
1001
1002 let mut t = Translation3D::new(0.0, 0.0, 0.0);
1003 t += Translation3D::new(0.0, 0.0, 0.0);
1004 assert_eq!(t, Translation3D::new(0.0, 0.0, 0.0));
1005 }
1006
1007 #[test]
1008 pub fn test_sub() {
1009 let t1 = Translation3D::new(1.0, 2.0, 3.0);
1010 let t2 = Translation3D::new(4.0, 5.0, 6.0);
1011 assert_eq!(t1 - t2, Translation3D::new(-3.0, -3.0, -3.0));
1012
1013 let t1 = Translation3D::new(1.0, 2.0, 3.0);
1014 let t2 = Translation3D::new(0.0, 0.0, 0.0);
1015 assert_eq!(t1 - t2, Translation3D::new(1.0, 2.0, 3.0));
1016
1017 let t1 = Translation3D::new(1.0, 2.0, 3.0);
1018 let t2 = Translation3D::new(-4.0, -5.0, -6.0);
1019 assert_eq!(t1 - t2, Translation3D::new(5.0, 7.0, 9.0));
1020
1021 let t1 = Translation3D::new(0.0, 0.0, 0.0);
1022 let t2 = Translation3D::new(0.0, 0.0, 0.0);
1023 assert_eq!(t1 - t2, Translation3D::new(0.0, 0.0, 0.0));
1024 }
1025
1026 #[test]
1027 pub fn test_sub_assign() {
1028 let mut t = Translation3D::new(1.0, 2.0, 3.0);
1029 t -= Translation3D::new(4.0, 5.0, 6.0);
1030 assert_eq!(t, Translation3D::new(-3.0, -3.0, -3.0));
1031
1032 let mut t = Translation3D::new(1.0, 2.0, 3.0);
1033 t -= Translation3D::new(0.0, 0.0, 0.0);
1034 assert_eq!(t, Translation3D::new(1.0, 2.0, 3.0));
1035
1036 let mut t = Translation3D::new(1.0, 2.0, 3.0);
1037 t -= Translation3D::new(-4.0, -5.0, -6.0);
1038 assert_eq!(t, Translation3D::new(5.0, 7.0, 9.0));
1039
1040 let mut t = Translation3D::new(0.0, 0.0, 0.0);
1041 t -= Translation3D::new(0.0, 0.0, 0.0);
1042 assert_eq!(t, Translation3D::new(0.0, 0.0, 0.0));
1043 }
1044 }
1045}