1use crate::num::*;
11use crate::UnknownUnit;
12use crate::{point2, point3, vec2, vec3, Box2D, Box3D, Rect, Size2D};
13use crate::{Point2D, Point3D, Transform2D, Transform3D, Vector2D, Vector3D};
14use core::cmp::{Eq, PartialEq};
15use core::fmt;
16use core::hash::Hash;
17use core::marker::PhantomData;
18use core::ops::{Add, AddAssign, Neg, Sub, SubAssign};
19#[cfg(feature = "serde")]
20use serde::{Deserialize, Serialize};
21
22#[repr(C)]
43#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
44#[cfg_attr(
45 feature = "serde",
46 serde(bound(
47 serialize = "T: serde::Serialize",
48 deserialize = "T: serde::Deserialize<'de>"
49 ))
50)]
51pub struct Translation2D<T, Src, Dst> {
52 pub x: T,
53 pub y: T,
54 #[doc(hidden)]
55 pub _unit: PhantomData<(Src, Dst)>,
56}
57
58impl<T: Copy, Src, Dst> Copy for Translation2D<T, Src, Dst> {}
59
60impl<T: Clone, Src, Dst> Clone for Translation2D<T, Src, Dst> {
61 fn clone(&self) -> Self {
62 Translation2D {
63 x: self.x.clone(),
64 y: self.y.clone(),
65 _unit: PhantomData,
66 }
67 }
68}
69
70impl<T, Src, Dst> Eq for Translation2D<T, Src, Dst> where T: Eq {}
71
72impl<T, Src, Dst> PartialEq for Translation2D<T, Src, Dst>
73where
74 T: PartialEq,
75{
76 fn eq(&self, other: &Self) -> bool {
77 self.x == other.x && self.y == other.y
78 }
79}
80
81impl<T, Src, Dst> Hash for Translation2D<T, Src, Dst>
82where
83 T: Hash,
84{
85 fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
86 self.x.hash(h);
87 self.y.hash(h);
88 }
89}
90
91impl<T, Src, Dst> Translation2D<T, Src, Dst> {
92 #[inline]
93 pub const fn new(x: T, y: T) -> Self {
94 Translation2D {
95 x,
96 y,
97 _unit: PhantomData,
98 }
99 }
100
101 #[inline]
103 pub fn identity() -> Self
104 where
105 T: Zero,
106 {
107 Self::new(T::zero(), T::zero())
108 }
109
110 #[inline]
121 pub fn is_identity(&self) -> bool
122 where
123 T: Zero + PartialEq,
124 {
125 let _0 = T::zero();
126 self.x == _0 && self.y == _0
127 }
128
129 #[inline]
131 pub fn transform_size(&self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
132 Size2D::new(s.width, s.height)
133 }
134}
135
136impl<T: Copy, Src, Dst> Translation2D<T, Src, Dst> {
137 #[inline]
139 pub fn to_vector(&self) -> Vector2D<T, Src> {
140 vec2(self.x, self.y)
141 }
142
143 #[inline]
145 pub fn to_array(&self) -> [T; 2] {
146 [self.x, self.y]
147 }
148
149 #[inline]
151 pub fn to_tuple(&self) -> (T, T) {
152 (self.x, self.y)
153 }
154
155 #[inline]
157 pub fn to_untyped(&self) -> Translation2D<T, UnknownUnit, UnknownUnit> {
158 Translation2D {
159 x: self.x,
160 y: self.y,
161 _unit: PhantomData,
162 }
163 }
164
165 #[inline]
167 pub fn from_untyped(t: &Translation2D<T, UnknownUnit, UnknownUnit>) -> Self {
168 Translation2D {
169 x: t.x,
170 y: t.y,
171 _unit: PhantomData,
172 }
173 }
174
175 #[inline]
177 pub fn to_transform(&self) -> Transform2D<T, Src, Dst>
178 where
179 T: Zero + One,
180 {
181 (*self).into()
182 }
183
184 #[inline]
186 pub fn transform_point(&self, p: Point2D<T, Src>) -> Point2D<T::Output, Dst>
187 where
188 T: Add,
189 {
190 point2(p.x + self.x, p.y + self.y)
191 }
192
193 #[inline]
195 pub fn transform_rect(&self, r: &Rect<T, Src>) -> Rect<T::Output, Dst>
196 where
197 T: Add<Output = T>,
198 {
199 Rect {
200 origin: self.transform_point(r.origin),
201 size: self.transform_size(r.size),
202 }
203 }
204
205 #[inline]
207 pub fn transform_box(&self, r: &Box2D<T, Src>) -> Box2D<T::Output, Dst>
208 where
209 T: Add,
210 {
211 Box2D {
212 min: self.transform_point(r.min),
213 max: self.transform_point(r.max),
214 }
215 }
216
217 #[inline]
219 pub fn inverse(&self) -> Translation2D<T::Output, Dst, Src>
220 where
221 T: Neg,
222 {
223 Translation2D::new(-self.x, -self.y)
224 }
225}
226
227impl<T: Add, Src, Dst1, Dst2> Add<Translation2D<T, Dst1, Dst2>> for Translation2D<T, Src, Dst1> {
228 type Output = Translation2D<T::Output, Src, Dst2>;
229
230 fn add(self, other: Translation2D<T, Dst1, Dst2>) -> Self::Output {
231 Translation2D::new(self.x + other.x, self.y + other.y)
232 }
233}
234
235impl<T: AddAssign, Src, Dst> AddAssign<Translation2D<T, Dst, Dst>> for Translation2D<T, Src, Dst> {
236 fn add_assign(&mut self, other: Translation2D<T, Dst, Dst>) {
237 self.x += other.x;
238 self.y += other.y;
239 }
240}
241
242impl<T: Sub, Src, Dst1, Dst2> Sub<Translation2D<T, Dst1, Dst2>> for Translation2D<T, Src, Dst2> {
243 type Output = Translation2D<T::Output, Src, Dst1>;
244
245 fn sub(self, other: Translation2D<T, Dst1, Dst2>) -> Self::Output {
246 Translation2D::new(self.x - other.x, self.y - other.y)
247 }
248}
249
250impl<T: SubAssign, Src, Dst> SubAssign<Translation2D<T, Dst, Dst>> for Translation2D<T, Src, Dst> {
251 fn sub_assign(&mut self, other: Translation2D<T, Dst, Dst>) {
252 self.x -= other.x;
253 self.y -= other.y;
254 }
255}
256
257impl<T, Src, Dst> From<Vector2D<T, Src>> for Translation2D<T, Src, Dst> {
258 fn from(v: Vector2D<T, Src>) -> Self {
259 Translation2D::new(v.x, v.y)
260 }
261}
262
263impl<T, Src, Dst> Into<Vector2D<T, Src>> for Translation2D<T, Src, Dst> {
264 fn into(self) -> Vector2D<T, Src> {
265 vec2(self.x, self.y)
266 }
267}
268
269impl<T, Src, Dst> Into<Transform2D<T, Src, Dst>> for Translation2D<T, Src, Dst>
270where
271 T: Zero + One,
272{
273 fn into(self) -> Transform2D<T, Src, Dst> {
274 Transform2D::translation(self.x, self.y)
275 }
276}
277
278impl<T, Src, Dst> Default for Translation2D<T, Src, Dst>
279where
280 T: Zero,
281{
282 fn default() -> Self {
283 Self::identity()
284 }
285}
286
287impl<T: fmt::Debug, Src, Dst> fmt::Debug for Translation2D<T, Src, Dst> {
288 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
289 write!(f, "Translation({:?},{:?})", self.x, self.y)
290 }
291}
292
293#[repr(C)]
298pub struct Translation3D<T, Src, Dst> {
299 pub x: T,
300 pub y: T,
301 pub z: T,
302 #[doc(hidden)]
303 pub _unit: PhantomData<(Src, Dst)>,
304}
305
306impl<T: Copy, Src, Dst> Copy for Translation3D<T, Src, Dst> {}
307
308impl<T: Clone, Src, Dst> Clone for Translation3D<T, Src, Dst> {
309 fn clone(&self) -> Self {
310 Translation3D {
311 x: self.x.clone(),
312 y: self.y.clone(),
313 z: self.z.clone(),
314 _unit: PhantomData,
315 }
316 }
317}
318
319#[cfg(feature = "serde")]
320impl<'de, T, Src, Dst> serde::Deserialize<'de> for Translation3D<T, Src, Dst>
321where
322 T: serde::Deserialize<'de>,
323{
324 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
325 where
326 D: serde::Deserializer<'de>,
327 {
328 let (x, y, z) = serde::Deserialize::deserialize(deserializer)?;
329 Ok(Translation3D {
330 x,
331 y,
332 z,
333 _unit: PhantomData,
334 })
335 }
336}
337
338#[cfg(feature = "serde")]
339impl<T, Src, Dst> serde::Serialize for Translation3D<T, Src, Dst>
340where
341 T: serde::Serialize,
342{
343 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
344 where
345 S: serde::Serializer,
346 {
347 (&self.x, &self.y, &self.z).serialize(serializer)
348 }
349}
350
351impl<T, Src, Dst> Eq for Translation3D<T, Src, Dst> where T: Eq {}
352
353impl<T, Src, Dst> PartialEq for Translation3D<T, Src, Dst>
354where
355 T: PartialEq,
356{
357 fn eq(&self, other: &Self) -> bool {
358 self.x == other.x && self.y == other.y && self.z == other.z
359 }
360}
361
362impl<T, Src, Dst> Hash for Translation3D<T, Src, Dst>
363where
364 T: Hash,
365{
366 fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
367 self.x.hash(h);
368 self.y.hash(h);
369 self.z.hash(h);
370 }
371}
372
373impl<T, Src, Dst> Translation3D<T, Src, Dst> {
374 #[inline]
375 pub const fn new(x: T, y: T, z: T) -> Self {
376 Translation3D {
377 x,
378 y,
379 z,
380 _unit: PhantomData,
381 }
382 }
383
384 #[inline]
386 pub fn identity() -> Self
387 where
388 T: Zero,
389 {
390 Translation3D::new(T::zero(), T::zero(), T::zero())
391 }
392
393 #[inline]
405 pub fn is_identity(&self) -> bool
406 where
407 T: Zero + PartialEq,
408 {
409 let _0 = T::zero();
410 self.x == _0 && self.y == _0 && self.z == _0
411 }
412
413 #[inline]
415 pub fn transform_size(self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
416 Size2D::new(s.width, s.height)
417 }
418}
419
420impl<T: Copy, Src, Dst> Translation3D<T, Src, Dst> {
421 #[inline]
423 pub fn to_vector(&self) -> Vector3D<T, Src> {
424 vec3(self.x, self.y, self.z)
425 }
426
427 #[inline]
429 pub fn to_array(&self) -> [T; 3] {
430 [self.x, self.y, self.z]
431 }
432
433 #[inline]
435 pub fn to_tuple(&self) -> (T, T, T) {
436 (self.x, self.y, self.z)
437 }
438
439 #[inline]
441 pub fn to_untyped(&self) -> Translation3D<T, UnknownUnit, UnknownUnit> {
442 Translation3D {
443 x: self.x,
444 y: self.y,
445 z: self.z,
446 _unit: PhantomData,
447 }
448 }
449
450 #[inline]
452 pub fn from_untyped(t: &Translation3D<T, UnknownUnit, UnknownUnit>) -> Self {
453 Translation3D {
454 x: t.x,
455 y: t.y,
456 z: t.z,
457 _unit: PhantomData,
458 }
459 }
460
461 #[inline]
463 pub fn to_transform(&self) -> Transform3D<T, Src, Dst>
464 where
465 T: Zero + One,
466 {
467 (*self).into()
468 }
469
470 #[inline]
472 pub fn transform_point3d(&self, p: &Point3D<T, Src>) -> Point3D<T::Output, Dst>
473 where
474 T: Add,
475 {
476 point3(p.x + self.x, p.y + self.y, p.z + self.z)
477 }
478
479 #[inline]
481 pub fn transform_point2d(&self, p: &Point2D<T, Src>) -> Point2D<T::Output, Dst>
482 where
483 T: Add,
484 {
485 point2(p.x + self.x, p.y + self.y)
486 }
487
488 #[inline]
490 pub fn transform_box2d(&self, b: &Box2D<T, Src>) -> Box2D<T::Output, Dst>
491 where
492 T: Add,
493 {
494 Box2D {
495 min: self.transform_point2d(&b.min),
496 max: self.transform_point2d(&b.max),
497 }
498 }
499
500 #[inline]
502 pub fn transform_box3d(&self, b: &Box3D<T, Src>) -> Box3D<T::Output, Dst>
503 where
504 T: Add,
505 {
506 Box3D {
507 min: self.transform_point3d(&b.min),
508 max: self.transform_point3d(&b.max),
509 }
510 }
511
512 #[inline]
514 pub fn transform_rect(&self, r: &Rect<T, Src>) -> Rect<T, Dst>
515 where
516 T: Add<Output = T>,
517 {
518 Rect {
519 origin: self.transform_point2d(&r.origin),
520 size: self.transform_size(r.size),
521 }
522 }
523
524 #[inline]
526 pub fn inverse(&self) -> Translation3D<T::Output, Dst, Src>
527 where
528 T: Neg,
529 {
530 Translation3D::new(-self.x, -self.y, -self.z)
531 }
532}
533
534impl<T: Add, Src, Dst1, Dst2> Add<Translation3D<T, Dst1, Dst2>> for Translation3D<T, Src, Dst1> {
535 type Output = Translation3D<T::Output, Src, Dst2>;
536
537 fn add(self, other: Translation3D<T, Dst1, Dst2>) -> Self::Output {
538 Translation3D::new(self.x + other.x, self.y + other.y, self.z + other.z)
539 }
540}
541
542impl<T: AddAssign, Src, Dst> AddAssign<Translation3D<T, Dst, Dst>> for Translation3D<T, Src, Dst> {
543 fn add_assign(&mut self, other: Translation3D<T, Dst, Dst>) {
544 self.x += other.x;
545 self.y += other.y;
546 self.z += other.z;
547 }
548}
549
550impl<T: Sub, Src, Dst1, Dst2> Sub<Translation3D<T, Dst1, Dst2>> for Translation3D<T, Src, Dst2> {
551 type Output = Translation3D<T::Output, Src, Dst1>;
552
553 fn sub(self, other: Translation3D<T, Dst1, Dst2>) -> Self::Output {
554 Translation3D::new(self.x - other.x, self.y - other.y, self.z - other.z)
555 }
556}
557
558impl<T: SubAssign, Src, Dst> SubAssign<Translation3D<T, Dst, Dst>> for Translation3D<T, Src, Dst> {
559 fn sub_assign(&mut self, other: Translation3D<T, Dst, Dst>) {
560 self.x -= other.x;
561 self.y -= other.y;
562 self.z -= other.z;
563 }
564}
565
566impl<T, Src, Dst> From<Vector3D<T, Src>> for Translation3D<T, Src, Dst> {
567 fn from(v: Vector3D<T, Src>) -> Self {
568 Translation3D::new(v.x, v.y, v.z)
569 }
570}
571
572impl<T, Src, Dst> Into<Vector3D<T, Src>> for Translation3D<T, Src, Dst> {
573 fn into(self) -> Vector3D<T, Src> {
574 vec3(self.x, self.y, self.z)
575 }
576}
577
578impl<T, Src, Dst> Into<Transform3D<T, Src, Dst>> for Translation3D<T, Src, Dst>
579where
580 T: Zero + One,
581{
582 fn into(self) -> Transform3D<T, Src, Dst> {
583 Transform3D::translation(self.x, self.y, self.z)
584 }
585}
586
587impl<T, Src, Dst> Default for Translation3D<T, Src, Dst>
588where
589 T: Zero,
590{
591 fn default() -> Self {
592 Self::identity()
593 }
594}
595
596impl<T: fmt::Debug, Src, Dst> fmt::Debug for Translation3D<T, Src, Dst> {
597 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
598 write!(f, "Translation({:?},{:?},{:?})", self.x, self.y, self.z)
599 }
600}
601
602#[cfg(test)]
603mod _2d {
604 #[test]
605 fn simple() {
606 use crate::{rect, Rect, Translation2D};
607
608 struct A;
609 struct B;
610
611 type Translation = Translation2D<i32, A, B>;
612 type SrcRect = Rect<i32, A>;
613 type DstRect = Rect<i32, B>;
614
615 let tx = Translation::new(10, -10);
616 let r1: SrcRect = rect(10, 20, 30, 40);
617 let r2: DstRect = tx.transform_rect(&r1);
618 assert_eq!(r2, rect(20, 10, 30, 40));
619
620 let inv_tx = tx.inverse();
621 assert_eq!(inv_tx.transform_rect(&r2), r1);
622
623 assert!((tx + inv_tx).is_identity());
624 }
625
626 mod ops {
628 use crate::default::Translation2D;
629
630 #[test]
631 fn test_add() {
632 let t1 = Translation2D::new(1.0, 2.0);
633 let t2 = Translation2D::new(3.0, 4.0);
634 assert_eq!(t1 + t2, Translation2D::new(4.0, 6.0));
635
636 let t1 = Translation2D::new(1.0, 2.0);
637 let t2 = Translation2D::new(0.0, 0.0);
638 assert_eq!(t1 + t2, Translation2D::new(1.0, 2.0));
639
640 let t1 = Translation2D::new(1.0, 2.0);
641 let t2 = Translation2D::new(-3.0, -4.0);
642 assert_eq!(t1 + t2, Translation2D::new(-2.0, -2.0));
643
644 let t1 = Translation2D::new(0.0, 0.0);
645 let t2 = Translation2D::new(0.0, 0.0);
646 assert_eq!(t1 + t2, Translation2D::new(0.0, 0.0));
647 }
648
649 #[test]
650 pub fn test_add_assign() {
651 let mut t = Translation2D::new(1.0, 2.0);
652 t += Translation2D::new(3.0, 4.0);
653 assert_eq!(t, Translation2D::new(4.0, 6.0));
654
655 let mut t = Translation2D::new(1.0, 2.0);
656 t += Translation2D::new(0.0, 0.0);
657 assert_eq!(t, Translation2D::new(1.0, 2.0));
658
659 let mut t = Translation2D::new(1.0, 2.0);
660 t += Translation2D::new(-3.0, -4.0);
661 assert_eq!(t, Translation2D::new(-2.0, -2.0));
662
663 let mut t = Translation2D::new(0.0, 0.0);
664 t += Translation2D::new(0.0, 0.0);
665 assert_eq!(t, Translation2D::new(0.0, 0.0));
666 }
667
668 #[test]
669 pub fn test_sub() {
670 let t1 = Translation2D::new(1.0, 2.0);
671 let t2 = Translation2D::new(3.0, 4.0);
672 assert_eq!(t1 - t2, Translation2D::new(-2.0, -2.0));
673
674 let t1 = Translation2D::new(1.0, 2.0);
675 let t2 = Translation2D::new(0.0, 0.0);
676 assert_eq!(t1 - t2, Translation2D::new(1.0, 2.0));
677
678 let t1 = Translation2D::new(1.0, 2.0);
679 let t2 = Translation2D::new(-3.0, -4.0);
680 assert_eq!(t1 - t2, Translation2D::new(4.0, 6.0));
681
682 let t1 = Translation2D::new(0.0, 0.0);
683 let t2 = Translation2D::new(0.0, 0.0);
684 assert_eq!(t1 - t2, Translation2D::new(0.0, 0.0));
685 }
686
687 #[test]
688 pub fn test_sub_assign() {
689 let mut t = Translation2D::new(1.0, 2.0);
690 t -= Translation2D::new(3.0, 4.0);
691 assert_eq!(t, Translation2D::new(-2.0, -2.0));
692
693 let mut t = Translation2D::new(1.0, 2.0);
694 t -= Translation2D::new(0.0, 0.0);
695 assert_eq!(t, Translation2D::new(1.0, 2.0));
696
697 let mut t = Translation2D::new(1.0, 2.0);
698 t -= Translation2D::new(-3.0, -4.0);
699 assert_eq!(t, Translation2D::new(4.0, 6.0));
700
701 let mut t = Translation2D::new(0.0, 0.0);
702 t -= Translation2D::new(0.0, 0.0);
703 assert_eq!(t, Translation2D::new(0.0, 0.0));
704 }
705 }
706}
707
708#[cfg(test)]
709mod _3d {
710 #[test]
711 fn simple() {
712 use crate::{point3, Point3D, Translation3D};
713
714 struct A;
715 struct B;
716
717 type Translation = Translation3D<i32, A, B>;
718 type SrcPoint = Point3D<i32, A>;
719 type DstPoint = Point3D<i32, B>;
720
721 let tx = Translation::new(10, -10, 100);
722 let p1: SrcPoint = point3(10, 20, 30);
723 let p2: DstPoint = tx.transform_point3d(&p1);
724 assert_eq!(p2, point3(20, 10, 130));
725
726 let inv_tx = tx.inverse();
727 assert_eq!(inv_tx.transform_point3d(&p2), p1);
728
729 assert!((tx + inv_tx).is_identity());
730 }
731
732 mod ops {
734 use crate::default::Translation3D;
735
736 #[test]
737 pub fn test_add() {
738 let t1 = Translation3D::new(1.0, 2.0, 3.0);
739 let t2 = Translation3D::new(4.0, 5.0, 6.0);
740 assert_eq!(t1 + t2, Translation3D::new(5.0, 7.0, 9.0));
741
742 let t1 = Translation3D::new(1.0, 2.0, 3.0);
743 let t2 = Translation3D::new(0.0, 0.0, 0.0);
744 assert_eq!(t1 + t2, Translation3D::new(1.0, 2.0, 3.0));
745
746 let t1 = Translation3D::new(1.0, 2.0, 3.0);
747 let t2 = Translation3D::new(-4.0, -5.0, -6.0);
748 assert_eq!(t1 + t2, Translation3D::new(-3.0, -3.0, -3.0));
749
750 let t1 = Translation3D::new(0.0, 0.0, 0.0);
751 let t2 = Translation3D::new(0.0, 0.0, 0.0);
752 assert_eq!(t1 + t2, Translation3D::new(0.0, 0.0, 0.0));
753 }
754
755 #[test]
756 pub fn test_add_assign() {
757 let mut t = Translation3D::new(1.0, 2.0, 3.0);
758 t += Translation3D::new(4.0, 5.0, 6.0);
759 assert_eq!(t, Translation3D::new(5.0, 7.0, 9.0));
760
761 let mut t = Translation3D::new(1.0, 2.0, 3.0);
762 t += Translation3D::new(0.0, 0.0, 0.0);
763 assert_eq!(t, Translation3D::new(1.0, 2.0, 3.0));
764
765 let mut t = Translation3D::new(1.0, 2.0, 3.0);
766 t += Translation3D::new(-4.0, -5.0, -6.0);
767 assert_eq!(t, Translation3D::new(-3.0, -3.0, -3.0));
768
769 let mut t = Translation3D::new(0.0, 0.0, 0.0);
770 t += Translation3D::new(0.0, 0.0, 0.0);
771 assert_eq!(t, Translation3D::new(0.0, 0.0, 0.0));
772 }
773
774 #[test]
775 pub fn test_sub() {
776 let t1 = Translation3D::new(1.0, 2.0, 3.0);
777 let t2 = Translation3D::new(4.0, 5.0, 6.0);
778 assert_eq!(t1 - t2, Translation3D::new(-3.0, -3.0, -3.0));
779
780 let t1 = Translation3D::new(1.0, 2.0, 3.0);
781 let t2 = Translation3D::new(0.0, 0.0, 0.0);
782 assert_eq!(t1 - t2, Translation3D::new(1.0, 2.0, 3.0));
783
784 let t1 = Translation3D::new(1.0, 2.0, 3.0);
785 let t2 = Translation3D::new(-4.0, -5.0, -6.0);
786 assert_eq!(t1 - t2, Translation3D::new(5.0, 7.0, 9.0));
787
788 let t1 = Translation3D::new(0.0, 0.0, 0.0);
789 let t2 = Translation3D::new(0.0, 0.0, 0.0);
790 assert_eq!(t1 - t2, Translation3D::new(0.0, 0.0, 0.0));
791 }
792
793 #[test]
794 pub fn test_sub_assign() {
795 let mut t = Translation3D::new(1.0, 2.0, 3.0);
796 t -= Translation3D::new(4.0, 5.0, 6.0);
797 assert_eq!(t, Translation3D::new(-3.0, -3.0, -3.0));
798
799 let mut t = Translation3D::new(1.0, 2.0, 3.0);
800 t -= Translation3D::new(0.0, 0.0, 0.0);
801 assert_eq!(t, Translation3D::new(1.0, 2.0, 3.0));
802
803 let mut t = Translation3D::new(1.0, 2.0, 3.0);
804 t -= Translation3D::new(-4.0, -5.0, -6.0);
805 assert_eq!(t, Translation3D::new(5.0, 7.0, 9.0));
806
807 let mut t = Translation3D::new(0.0, 0.0, 0.0);
808 t -= Translation3D::new(0.0, 0.0, 0.0);
809 assert_eq!(t, Translation3D::new(0.0, 0.0, 0.0));
810 }
811 }
812}