1 // Copyright 2018 The Servo Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9 
10 use {Vector2D, Point2D, Vector3D, Point3D, Transform2D, Transform3D};
11 use {Size2D, Rect, vec2, point2, vec3, point3};
12 use UnknownUnit;
13 use num::*;
14 use trig::Trig;
15 use core::ops::{Add, Sub, Neg, Mul, Div};
16 use core::marker::PhantomData;
17 use core::fmt;
18 use core::cmp::{Eq, PartialEq};
19 use core::hash::{Hash};
20 #[cfg(feature = "serde")]
21 use serde;
22 
23 /// A 2d transformation from a space to another that can only express translations.
24 ///
25 /// The main benefit of this type over a Vector2D is the ability to cast
26 /// between a source and a destination spaces.
27 ///
28 /// Example:
29 ///
30 /// ```
31 /// use euclid::{Translation2D, Point2D, point2};
32 /// struct ParentSpace;
33 /// struct ChildSpace;
34 /// type ScrollOffset = Translation2D<i32, ParentSpace, ChildSpace>;
35 /// type ParentPoint = Point2D<i32, ParentSpace>;
36 /// type ChildPoint = Point2D<i32, ChildSpace>;
37 ///
38 /// let scrolling = ScrollOffset::new(0, 100);
39 /// let p1: ParentPoint = point2(0, 0);
40 /// let p2: ChildPoint = scrolling.transform_point(p1);
41 /// ```
42 ///
43 #[repr(C)]
44 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
45 #[cfg_attr(feature = "serde", serde(bound(serialize = "T: serde::Serialize", deserialize = "T: serde::Deserialize<'de>")))]
46 pub struct Translation2D<T, Src, Dst> {
47     pub x: T,
48     pub y: T,
49     #[doc(hidden)]
50     pub _unit: PhantomData<(Src, Dst)>,
51 }
52 
53 impl<T: Copy, Src, Dst> Copy for Translation2D<T, Src, Dst> {}
54 
55 impl<T: Clone, Src, Dst> Clone for Translation2D<T, Src, Dst> {
clone(&self) -> Self56     fn clone(&self) -> Self {
57         Translation2D {
58             x: self.x.clone(),
59             y: self.y.clone(),
60             _unit: PhantomData,
61         }
62     }
63 }
64 
65 impl<T, Src, Dst> Eq for Translation2D<T, Src, Dst> where T: Eq {}
66 
67 impl<T, Src, Dst> PartialEq for Translation2D<T, Src, Dst>
68     where T: PartialEq
69 {
eq(&self, other: &Self) -> bool70     fn eq(&self, other: &Self) -> bool {
71         self.x == other.x && self.y == other.y
72     }
73 }
74 
75 impl<T, Src, Dst> Hash for Translation2D<T, Src, Dst>
76     where T: Hash
77 {
hash<H: ::core::hash::Hasher>(&self, h: &mut H)78     fn hash<H: ::core::hash::Hasher>(&self, h: &mut H) {
79         self.x.hash(h);
80         self.y.hash(h);
81     }
82 }
83 
84 impl<T, Src, Dst> Translation2D<T, Src, Dst> {
85     #[inline]
new(x: T, y: T) -> Self86     pub const fn new(x: T, y: T) -> Self {
87         Translation2D {
88             x,
89             y,
90             _unit: PhantomData,
91         }
92     }
93 
94     /// No-op, just cast the unit.
95     #[inline]
transform_size(&self, s: Size2D<T, Src>) -> Size2D<T, Dst>96     pub fn transform_size(&self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
97         Size2D::new(s.width, s.height)
98     }
99 }
100 
101 impl<T, Src, Dst> Translation2D<T, Src, Dst>
102 where
103     T : Copy
104 {
105     /// Cast into a 2D vector.
106     #[inline]
to_vector(&self) -> Vector2D<T, Src>107     pub fn to_vector(&self) -> Vector2D<T, Src> {
108         vec2(self.x, self.y)
109     }
110 
111     /// Cast into an array with x and y.
112     #[inline]
to_array(&self) -> [T; 2]113     pub fn to_array(&self) -> [T; 2] {
114         [self.x, self.y]
115     }
116 
117     /// Cast into a tuple with x and y.
118     #[inline]
to_tuple(&self) -> (T, T)119     pub fn to_tuple(&self) -> (T, T) {
120         (self.x, self.y)
121     }
122 
123     /// Drop the units, preserving only the numeric value.
124     #[inline]
to_untyped(&self) -> Translation2D<T, UnknownUnit, UnknownUnit>125     pub fn to_untyped(&self) -> Translation2D<T, UnknownUnit, UnknownUnit> {
126         Translation2D {
127             x: self.x,
128             y: self.y,
129             _unit: PhantomData,
130         }
131     }
132 
133     /// Tag a unitless value with units.
134     #[inline]
from_untyped(t: &Translation2D<T, UnknownUnit, UnknownUnit>) -> Self135     pub fn from_untyped(t: &Translation2D<T, UnknownUnit, UnknownUnit>) -> Self {
136         Translation2D {
137             x: t.x,
138             y: t.y,
139             _unit: PhantomData,
140         }
141     }
142 }
143 
144 impl<T, Src, Dst> Translation2D<T, Src, Dst>
145 where
146     T: Zero
147 {
148     #[inline]
identity() -> Self149     pub fn identity() -> Self {
150         Translation2D::new(T::zero(), T::zero())
151     }
152 }
153 
154 impl<T, Src, Dst> Translation2D<T, Src, Dst>
155 where
156     T: Zero + PartialEq
157 {
158     #[inline]
is_identity(&self) -> bool159     pub fn is_identity(&self) -> bool {
160         let _0 = T::zero();
161         self.x == _0 && self.y == _0
162     }
163 }
164 
165 impl<T, Src, Dst> Translation2D<T, Src, Dst>
166 where
167     T: Copy + Add<T, Output = T>
168 {
169     /// Translate a point and cast its unit.
170     #[inline]
transform_point(&self, p: Point2D<T, Src>) -> Point2D<T, Dst>171     pub fn transform_point(&self, p: Point2D<T, Src>) -> Point2D<T, Dst> {
172         point2(p.x + self.x, p.y + self.y)
173     }
174 
175     /// Translate a rectangle and cast its unit.
176     #[inline]
transform_rect(&self, r: &Rect<T, Src>) -> Rect<T, Dst>177     pub fn transform_rect(&self, r: &Rect<T, Src>) -> Rect<T, Dst> {
178         Rect {
179             origin: self.transform_point(r.origin),
180             size: self.transform_size(r.size),
181         }
182     }
183 }
184 
185 impl<T, Src, Dst> Translation2D<T, Src, Dst>
186 where
187     T: Copy + Neg<Output = T>
188 {
189     /// Return the inverse transformation.
190     #[inline]
inverse(&self) -> Translation2D<T, Dst, Src>191     pub fn inverse(&self) -> Translation2D<T, Dst, Src> {
192         Translation2D::new(-self.x, -self.y)
193     }
194 }
195 
196 impl<T, Src, Dst1, Dst2> Add<Translation2D<T, Dst1, Dst2>>
197 for Translation2D<T, Src, Dst1>
198 where
199     T: Add<T, Output = T>
200 {
201     type Output = Translation2D<T, Src, Dst2>;
add(self, other: Translation2D<T, Dst1, Dst2>) -> Translation2D<T, Src, Dst2>202     fn add(self, other: Translation2D<T, Dst1, Dst2>) -> Translation2D<T, Src, Dst2> {
203         Translation2D::new(
204             self.x + other.x,
205             self.y + other.y,
206         )
207     }
208 }
209 
210 impl<T, Src, Dst1, Dst2>
211     Sub<Translation2D<T, Dst1, Dst2>>
212     for Translation2D<T, Src, Dst2>
213 where
214     T: Sub<T, Output = T>
215 {
216     type Output = Translation2D<T, Src, Dst1>;
sub(self, other: Translation2D<T, Dst1, Dst2>) -> Translation2D<T, Src, Dst1>217     fn sub(self, other: Translation2D<T, Dst1, Dst2>) -> Translation2D<T, Src, Dst1> {
218         Translation2D::new(
219             self.x - other.x,
220             self.y - other.y,
221         )
222     }
223 }
224 
225 impl<T, Src, Dst> Translation2D<T, Src, Dst>
226 where
227     T: Copy
228         + Add<T, Output = T>
229         + Mul<T, Output = T>
230         + Div<T, Output = T>
231         + Sub<T, Output = T>
232         + Trig
233         + PartialOrd
234         + One
235         + Zero,
236 {
237     /// Returns the matrix representation of this translation.
238     #[inline]
to_transform(&self) -> Transform2D<T, Src, Dst>239     pub fn to_transform(&self) -> Transform2D<T, Src, Dst> {
240         Transform2D::create_translation(self.x, self.y)
241     }
242 }
243 
244 impl<T, Src, Dst> From<Vector2D<T, Src>> for Translation2D<T, Src, Dst>
245 {
from(v: Vector2D<T, Src>) -> Self246     fn from(v: Vector2D<T, Src>) -> Self {
247         Translation2D::new(v.x, v.y)
248     }
249 }
250 
251 impl<T, Src, Dst> Into<Vector2D<T, Src>> for Translation2D<T, Src, Dst>
252 {
into(self) -> Vector2D<T, Src>253     fn into(self) -> Vector2D<T, Src> {
254         vec2(self.x, self.y)
255     }
256 }
257 
258 impl<T, Src, Dst> Into<Transform2D<T, Src, Dst>> for Translation2D<T, Src, Dst>
259 where
260     T: Copy
261         + Add<T, Output = T>
262         + Mul<T, Output = T>
263         + Div<T, Output = T>
264         + Sub<T, Output = T>
265         + Trig
266         + PartialOrd
267         + One
268         + Zero,
269 {
into(self) -> Transform2D<T, Src, Dst>270     fn into(self) -> Transform2D<T, Src, Dst> {
271         self.to_transform()
272     }
273 }
274 
275 impl <T, Src, Dst> Default for Translation2D<T, Src, Dst>
276     where T: Zero
277 {
default() -> Self278     fn default() -> Self {
279         Self::identity()
280     }
281 }
282 
283 impl<T: fmt::Debug, Src, Dst> fmt::Debug for Translation2D<T, Src, Dst> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result284     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285         write!(f, "Translation({:?},{:?})", self.x, self.y)
286     }
287 }
288 
289 impl<T: fmt::Display, Src, Dst> fmt::Display for Translation2D<T, Src, Dst> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result290     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291         write!(f, "({},{})", self.x, self.y)
292     }
293 }
294 
295 
296 /// A 3d transformation from a space to another that can only express translations.
297 ///
298 /// The main benefit of this type over a Vector3D is the ability to cast
299 /// between a source and a destination spaces.
300 #[repr(C)]
301 pub struct Translation3D<T, Src, Dst> {
302     pub x: T,
303     pub y: T,
304     pub z: T,
305     #[doc(hidden)]
306     pub _unit: PhantomData<(Src, Dst)>,
307 }
308 
309 impl<T: Copy, Src, Dst> Copy for Translation3D<T, Src, Dst> {}
310 
311 impl<T: Clone, Src, Dst> Clone for Translation3D<T, Src, Dst> {
clone(&self) -> Self312     fn clone(&self) -> Self {
313         Translation3D {
314             x: self.x.clone(),
315             y: self.y.clone(),
316             z: self.z.clone(),
317             _unit: PhantomData,
318         }
319     }
320 }
321 
322 #[cfg(feature = "serde")]
323 impl<'de, T, Src, Dst> serde::Deserialize<'de> for Translation3D<T, Src, Dst>
324     where T: serde::Deserialize<'de>
325 {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de>326     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
327         where D: serde::Deserializer<'de>
328     {
329         let (x, y, z) = serde::Deserialize::deserialize(deserializer)?;
330         Ok(Translation3D { x, y, z, _unit: PhantomData })
331     }
332 }
333 
334 #[cfg(feature = "serde")]
335 impl<T, Src, Dst> serde::Serialize for Translation3D<T, Src, Dst>
336     where T: serde::Serialize
337 {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer338     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
339         where S: serde::Serializer
340     {
341         (&self.x, &self.y, &self.z).serialize(serializer)
342     }
343 }
344 
345 impl<T, Src, Dst> Eq for Translation3D<T, Src, Dst> where T: Eq {}
346 
347 impl<T, Src, Dst> PartialEq for Translation3D<T, Src, Dst>
348     where T: PartialEq
349 {
eq(&self, other: &Self) -> bool350     fn eq(&self, other: &Self) -> bool {
351         self.x == other.x && self.y == other.y && self.z == other.z
352     }
353 }
354 
355 impl<T, Src, Dst> Hash for Translation3D<T, Src, Dst>
356     where T: Hash
357 {
hash<H: ::core::hash::Hasher>(&self, h: &mut H)358     fn hash<H: ::core::hash::Hasher>(&self, h: &mut H) {
359         self.x.hash(h);
360         self.y.hash(h);
361         self.z.hash(h);
362     }
363 }
364 
365 impl<T, Src, Dst> Translation3D<T, Src, Dst> {
366     #[inline]
new(x: T, y: T, z: T) -> Self367     pub const fn new(x: T, y: T, z: T) -> Self {
368         Translation3D {
369             x,
370             y,
371             z,
372             _unit: PhantomData,
373         }
374     }
375 
376     /// No-op, just cast the unit.
377     #[inline]
transform_size(self, s: Size2D<T, Src>) -> Size2D<T, Dst>378     pub fn transform_size(self, s: Size2D<T, Src>) -> Size2D<T, Dst> {
379         Size2D::new(s.width, s.height)
380     }
381 }
382 
383 impl<T, Src, Dst> Translation3D<T, Src, Dst>
384 where
385     T: Copy
386 {
387     /// Cast into a 3D vector.
388     #[inline]
to_vector(&self) -> Vector3D<T, Src>389     pub fn to_vector(&self) -> Vector3D<T, Src> {
390         vec3(self.x, self.y, self.z)
391     }
392 
393     /// Cast into an array with x, y and z.
394     #[inline]
to_array(&self) -> [T; 3]395     pub fn to_array(&self) -> [T; 3] {
396         [self.x, self.y, self.z]
397     }
398 
399     /// Cast into a tuple with x, y and z.
400     #[inline]
to_tuple(&self) -> (T, T, T)401     pub fn to_tuple(&self) -> (T, T, T) {
402         (self.x, self.y, self.z)
403     }
404 
405     /// Drop the units, preserving only the numeric value.
406     #[inline]
to_untyped(&self) -> Translation3D<T, UnknownUnit, UnknownUnit>407     pub fn to_untyped(&self) -> Translation3D<T, UnknownUnit, UnknownUnit> {
408         Translation3D {
409             x: self.x,
410             y: self.y,
411             z: self.z,
412             _unit: PhantomData,
413         }
414     }
415 
416     /// Tag a unitless value with units.
417     #[inline]
from_untyped(t: &Translation3D<T, UnknownUnit, UnknownUnit>) -> Self418     pub fn from_untyped(t: &Translation3D<T, UnknownUnit, UnknownUnit>) -> Self {
419         Translation3D {
420             x: t.x,
421             y: t.y,
422             z: t.z,
423             _unit: PhantomData,
424         }
425     }
426 }
427 
428 impl<T, Src, Dst> Translation3D<T, Src, Dst>
429 where
430     T: Zero
431 {
432     #[inline]
identity() -> Self433     pub fn identity() -> Self {
434         Translation3D::new(T::zero(), T::zero(), T::zero())
435     }
436 }
437 
438 impl<T, Src, Dst> Translation3D<T, Src, Dst>
439 where
440     T: Zero + PartialEq
441 {
442     #[inline]
is_identity(&self) -> bool443     pub fn is_identity(&self) -> bool {
444         let _0 = T::zero();
445         self.x == _0 && self.y == _0 && self.z == _0
446     }
447 }
448 
449 impl<T, Src, Dst> Translation3D<T, Src, Dst>
450 where
451     T: Copy + Add<T, Output = T>
452 {
453     /// Translate a point and cast its unit.
454     #[inline]
transform_point3d(&self, p: &Point3D<T, Src>) -> Point3D<T, Dst>455     pub fn transform_point3d(&self, p: &Point3D<T, Src>) -> Point3D<T, Dst> {
456         point3(p.x + self.x, p.y + self.y, p.z + self.z)
457     }
458 
459     /// Translate a point and cast its unit.
460     #[inline]
transform_point2d(&self, p: &Point2D<T, Src>) -> Point2D<T, Dst>461     pub fn transform_point2d(&self, p: &Point2D<T, Src>) -> Point2D<T, Dst> {
462         point2(p.x + self.x, p.y + self.y)
463     }
464 
465     /// Translate a rectangle and cast its unit.
466     #[inline]
transform_rect(&self, r: &Rect<T, Src>) -> Rect<T, Dst>467     pub fn transform_rect(&self, r: &Rect<T, Src>) -> Rect<T, Dst> {
468         Rect {
469             origin: self.transform_point2d(&r.origin),
470             size: self.transform_size(r.size),
471         }
472     }
473 }
474 
475 impl<T, Src, Dst> Translation3D<T, Src, Dst>
476 where
477     T: Copy + Neg<Output = T>
478 {
479     /// Return the inverse transformation.
480     #[inline]
inverse(&self) -> Translation3D<T, Dst, Src>481     pub fn inverse(&self) -> Translation3D<T, Dst, Src> {
482         Translation3D::new(-self.x, -self.y, -self.z)
483     }
484 }
485 
486 impl<T, Src, Dst1, Dst2> Add<Translation3D<T, Dst1, Dst2>>
487 for Translation3D<T, Src, Dst1>
488 where
489     T: Add<T, Output = T>
490 {
491     type Output = Translation3D<T, Src, Dst2>;
add(self, other: Translation3D<T, Dst1, Dst2>) -> Translation3D<T, Src, Dst2>492     fn add(self, other: Translation3D<T, Dst1, Dst2>) -> Translation3D<T, Src, Dst2> {
493         Translation3D::new(
494             self.x + other.x,
495             self.y + other.y,
496             self.z + other.z,
497         )
498     }
499 }
500 
501 impl<T, Src, Dst1, Dst2>
502     Sub<Translation3D<T, Dst1, Dst2>>
503     for Translation3D<T, Src, Dst2>
504 where
505     T: Sub<T, Output = T>
506 {
507     type Output = Translation3D<T, Src, Dst1>;
sub(self, other: Translation3D<T, Dst1, Dst2>) -> Translation3D<T, Src, Dst1>508     fn sub(self, other: Translation3D<T, Dst1, Dst2>) -> Translation3D<T, Src, Dst1> {
509         Translation3D::new(
510             self.x - other.x,
511             self.y - other.y,
512             self.z - other.z,
513         )
514     }
515 }
516 
517 impl<T, Src, Dst> Translation3D<T, Src, Dst>
518 where
519     T: Copy +
520         Add<T, Output=T> +
521         Sub<T, Output=T> +
522         Mul<T, Output=T> +
523         Div<T, Output=T> +
524         Neg<Output=T> +
525         PartialOrd +
526         Trig +
527         One + Zero,
528 {
529     /// Returns the matrix representation of this translation.
530     #[inline]
to_transform(&self) -> Transform3D<T, Src, Dst>531     pub fn to_transform(&self) -> Transform3D<T, Src, Dst> {
532         Transform3D::create_translation(self.x, self.y, self.z)
533     }
534 }
535 
536 impl<T, Src, Dst> From<Vector3D<T, Src>> for Translation3D<T, Src, Dst>
537 {
from(v: Vector3D<T, Src>) -> Self538     fn from(v: Vector3D<T, Src>) -> Self {
539         Translation3D::new(v.x, v.y, v.z)
540     }
541 }
542 
543 impl<T, Src, Dst> Into<Vector3D<T, Src>> for Translation3D<T, Src, Dst>
544 {
into(self) -> Vector3D<T, Src>545     fn into(self) -> Vector3D<T, Src> {
546         vec3(self.x, self.y, self.z)
547     }
548 }
549 
550 impl<T, Src, Dst> Into<Transform3D<T, Src, Dst>> for Translation3D<T, Src, Dst>
551 where
552     T: Copy +
553         Add<T, Output=T> +
554         Sub<T, Output=T> +
555         Mul<T, Output=T> +
556         Div<T, Output=T> +
557         Neg<Output=T> +
558         PartialOrd +
559         Trig +
560         One + Zero,
561 {
into(self) -> Transform3D<T, Src, Dst>562     fn into(self) -> Transform3D<T, Src, Dst> {
563         self.to_transform()
564     }
565 }
566 
567 impl <T, Src, Dst> Default for Translation3D<T, Src, Dst>
568     where T: Zero
569 {
default() -> Self570     fn default() -> Self {
571         Self::identity()
572     }
573 }
574 
575 impl<T: fmt::Debug, Src, Dst> fmt::Debug for Translation3D<T, Src, Dst> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result576     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
577         write!(f, "Translation({:?},{:?},{:?})", self.x, self.y, self.z)
578     }
579 }
580 
581 impl<T: fmt::Display, Src, Dst> fmt::Display for Translation3D<T, Src, Dst> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result582     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
583         write!(f, "({},{},{})", self.x, self.y, self.z)
584     }
585 }
586 
587 #[test]
simple_translation2d()588 fn simple_translation2d() {
589     use rect;
590 
591     struct A;
592     struct B;
593 
594     type Translation = Translation2D<i32, A, B>;
595     type SrcRect = Rect<i32, A>;
596     type DstRect = Rect<i32, B>;
597 
598     let tx = Translation::new(10, -10);
599     let r1: SrcRect = rect(10, 20, 30, 40);
600     let r2: DstRect = tx.transform_rect(&r1);
601     assert_eq!(r2, rect(20, 10, 30, 40));
602 
603     let inv_tx = tx.inverse();
604     assert_eq!(inv_tx.transform_rect(&r2), r1);
605 
606     assert!((tx + inv_tx).is_identity());
607 }
608 
609 #[test]
simple_translation3d()610 fn simple_translation3d() {
611     struct A;
612     struct B;
613 
614     type Translation = Translation3D<i32, A, B>;
615     type SrcPoint = Point3D<i32, A>;
616     type DstPoint = Point3D<i32, B>;
617 
618     let tx = Translation::new(10, -10, 100);
619     let p1: SrcPoint = point3(10, 20, 30);
620     let p2: DstPoint = tx.transform_point3d(&p1);
621     assert_eq!(p2, point3(20, 10, 130));
622 
623     let inv_tx = tx.inverse();
624     assert_eq!(inv_tx.transform_point3d(&p2), p1);
625 
626     assert!((tx + inv_tx).is_identity());
627 }
628