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