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