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)]
852#[cfg(any(feature = "std", feature = "libm"))]
853mod _2d {
854 #[test]
855 fn simple() {
856 use crate::{rect, Rect, Translation2D};
857
858 struct A;
859 struct B;
860
861 type Translation = Translation2D<i32, A, B>;
862 type SrcRect = Rect<i32, A>;
863 type DstRect = Rect<i32, B>;
864
865 let tx = Translation::new(10, -10);
866 let r1: SrcRect = rect(10, 20, 30, 40);
867 let r2: DstRect = tx.transform_rect(&r1);
868 assert_eq!(r2, rect(20, 10, 30, 40));
869
870 let inv_tx = tx.inverse();
871 assert_eq!(inv_tx.transform_rect(&r2), r1);
872
873 assert!((tx + inv_tx).is_identity());
874 }
875
876 mod ops {
878 use crate::default::Translation2D;
879
880 #[test]
881 fn test_add() {
882 let t1 = Translation2D::new(1.0, 2.0);
883 let t2 = Translation2D::new(3.0, 4.0);
884 assert_eq!(t1 + t2, Translation2D::new(4.0, 6.0));
885
886 let t1 = Translation2D::new(1.0, 2.0);
887 let t2 = Translation2D::new(0.0, 0.0);
888 assert_eq!(t1 + t2, Translation2D::new(1.0, 2.0));
889
890 let t1 = Translation2D::new(1.0, 2.0);
891 let t2 = Translation2D::new(-3.0, -4.0);
892 assert_eq!(t1 + t2, Translation2D::new(-2.0, -2.0));
893
894 let t1 = Translation2D::new(0.0, 0.0);
895 let t2 = Translation2D::new(0.0, 0.0);
896 assert_eq!(t1 + t2, Translation2D::new(0.0, 0.0));
897 }
898
899 #[test]
900 pub fn test_add_assign() {
901 let mut t = Translation2D::new(1.0, 2.0);
902 t += Translation2D::new(3.0, 4.0);
903 assert_eq!(t, Translation2D::new(4.0, 6.0));
904
905 let mut t = Translation2D::new(1.0, 2.0);
906 t += Translation2D::new(0.0, 0.0);
907 assert_eq!(t, Translation2D::new(1.0, 2.0));
908
909 let mut t = Translation2D::new(1.0, 2.0);
910 t += Translation2D::new(-3.0, -4.0);
911 assert_eq!(t, Translation2D::new(-2.0, -2.0));
912
913 let mut t = Translation2D::new(0.0, 0.0);
914 t += Translation2D::new(0.0, 0.0);
915 assert_eq!(t, Translation2D::new(0.0, 0.0));
916 }
917
918 #[test]
919 pub fn test_sub() {
920 let t1 = Translation2D::new(1.0, 2.0);
921 let t2 = Translation2D::new(3.0, 4.0);
922 assert_eq!(t1 - t2, Translation2D::new(-2.0, -2.0));
923
924 let t1 = Translation2D::new(1.0, 2.0);
925 let t2 = Translation2D::new(0.0, 0.0);
926 assert_eq!(t1 - t2, Translation2D::new(1.0, 2.0));
927
928 let t1 = Translation2D::new(1.0, 2.0);
929 let t2 = Translation2D::new(-3.0, -4.0);
930 assert_eq!(t1 - t2, Translation2D::new(4.0, 6.0));
931
932 let t1 = Translation2D::new(0.0, 0.0);
933 let t2 = Translation2D::new(0.0, 0.0);
934 assert_eq!(t1 - t2, Translation2D::new(0.0, 0.0));
935 }
936
937 #[test]
938 pub fn test_sub_assign() {
939 let mut t = Translation2D::new(1.0, 2.0);
940 t -= Translation2D::new(3.0, 4.0);
941 assert_eq!(t, Translation2D::new(-2.0, -2.0));
942
943 let mut t = Translation2D::new(1.0, 2.0);
944 t -= Translation2D::new(0.0, 0.0);
945 assert_eq!(t, Translation2D::new(1.0, 2.0));
946
947 let mut t = Translation2D::new(1.0, 2.0);
948 t -= Translation2D::new(-3.0, -4.0);
949 assert_eq!(t, Translation2D::new(4.0, 6.0));
950
951 let mut t = Translation2D::new(0.0, 0.0);
952 t -= Translation2D::new(0.0, 0.0);
953 assert_eq!(t, Translation2D::new(0.0, 0.0));
954 }
955 }
956}
957
958#[cfg(test)]
959#[cfg(any(feature = "std", feature = "libm"))]
960mod _3d {
961 #[test]
962 fn simple() {
963 use crate::{point3, Point3D, Translation3D};
964
965 struct A;
966 struct B;
967
968 type Translation = Translation3D<i32, A, B>;
969 type SrcPoint = Point3D<i32, A>;
970 type DstPoint = Point3D<i32, B>;
971
972 let tx = Translation::new(10, -10, 100);
973 let p1: SrcPoint = point3(10, 20, 30);
974 let p2: DstPoint = tx.transform_point3d(&p1);
975 assert_eq!(p2, point3(20, 10, 130));
976
977 let inv_tx = tx.inverse();
978 assert_eq!(inv_tx.transform_point3d(&p2), p1);
979
980 assert!((tx + inv_tx).is_identity());
981 }
982
983 mod ops {
985 use crate::default::Translation3D;
986
987 #[test]
988 pub fn test_add() {
989 let t1 = Translation3D::new(1.0, 2.0, 3.0);
990 let t2 = Translation3D::new(4.0, 5.0, 6.0);
991 assert_eq!(t1 + t2, Translation3D::new(5.0, 7.0, 9.0));
992
993 let t1 = Translation3D::new(1.0, 2.0, 3.0);
994 let t2 = Translation3D::new(0.0, 0.0, 0.0);
995 assert_eq!(t1 + t2, Translation3D::new(1.0, 2.0, 3.0));
996
997 let t1 = Translation3D::new(1.0, 2.0, 3.0);
998 let t2 = Translation3D::new(-4.0, -5.0, -6.0);
999 assert_eq!(t1 + t2, Translation3D::new(-3.0, -3.0, -3.0));
1000
1001 let t1 = Translation3D::new(0.0, 0.0, 0.0);
1002 let t2 = Translation3D::new(0.0, 0.0, 0.0);
1003 assert_eq!(t1 + t2, Translation3D::new(0.0, 0.0, 0.0));
1004 }
1005
1006 #[test]
1007 pub fn test_add_assign() {
1008 let mut t = Translation3D::new(1.0, 2.0, 3.0);
1009 t += Translation3D::new(4.0, 5.0, 6.0);
1010 assert_eq!(t, Translation3D::new(5.0, 7.0, 9.0));
1011
1012 let mut t = Translation3D::new(1.0, 2.0, 3.0);
1013 t += Translation3D::new(0.0, 0.0, 0.0);
1014 assert_eq!(t, Translation3D::new(1.0, 2.0, 3.0));
1015
1016 let mut t = Translation3D::new(1.0, 2.0, 3.0);
1017 t += Translation3D::new(-4.0, -5.0, -6.0);
1018 assert_eq!(t, Translation3D::new(-3.0, -3.0, -3.0));
1019
1020 let mut t = Translation3D::new(0.0, 0.0, 0.0);
1021 t += Translation3D::new(0.0, 0.0, 0.0);
1022 assert_eq!(t, Translation3D::new(0.0, 0.0, 0.0));
1023 }
1024
1025 #[test]
1026 pub fn test_sub() {
1027 let t1 = Translation3D::new(1.0, 2.0, 3.0);
1028 let t2 = Translation3D::new(4.0, 5.0, 6.0);
1029 assert_eq!(t1 - t2, Translation3D::new(-3.0, -3.0, -3.0));
1030
1031 let t1 = Translation3D::new(1.0, 2.0, 3.0);
1032 let t2 = Translation3D::new(0.0, 0.0, 0.0);
1033 assert_eq!(t1 - t2, Translation3D::new(1.0, 2.0, 3.0));
1034
1035 let t1 = Translation3D::new(1.0, 2.0, 3.0);
1036 let t2 = Translation3D::new(-4.0, -5.0, -6.0);
1037 assert_eq!(t1 - t2, Translation3D::new(5.0, 7.0, 9.0));
1038
1039 let t1 = Translation3D::new(0.0, 0.0, 0.0);
1040 let t2 = Translation3D::new(0.0, 0.0, 0.0);
1041 assert_eq!(t1 - t2, Translation3D::new(0.0, 0.0, 0.0));
1042 }
1043
1044 #[test]
1045 pub fn test_sub_assign() {
1046 let mut t = Translation3D::new(1.0, 2.0, 3.0);
1047 t -= Translation3D::new(4.0, 5.0, 6.0);
1048 assert_eq!(t, Translation3D::new(-3.0, -3.0, -3.0));
1049
1050 let mut t = Translation3D::new(1.0, 2.0, 3.0);
1051 t -= Translation3D::new(0.0, 0.0, 0.0);
1052 assert_eq!(t, Translation3D::new(1.0, 2.0, 3.0));
1053
1054 let mut t = Translation3D::new(1.0, 2.0, 3.0);
1055 t -= Translation3D::new(-4.0, -5.0, -6.0);
1056 assert_eq!(t, Translation3D::new(5.0, 7.0, 9.0));
1057
1058 let mut t = Translation3D::new(0.0, 0.0, 0.0);
1059 t -= Translation3D::new(0.0, 0.0, 0.0);
1060 assert_eq!(t, Translation3D::new(0.0, 0.0, 0.0));
1061 }
1062 }
1063}