euclid/
translation.rs

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
10use {TypedVector2D, TypedPoint2D, TypedVector3D, TypedPoint3D, TypedTransform2D, TypedTransform3D};
11use {TypedSize2D, TypedRect, vec2, point2, vec3, point3};
12use num::*;
13use trig::Trig;
14use core::ops::{Add, Sub, Neg, Mul, Div};
15use core::marker::PhantomData;
16use core::fmt;
17
18/// A 2d transformation from a space to another that can only express translations.
19///
20/// The main benefit of this type over a TypedVector2D is the ability to cast
21/// between a source and a destination spaces.
22///
23/// Example:
24///
25/// ```
26/// use euclid::{TypedTranslation2D, TypedPoint2D, point2};
27/// struct ParentSpace;
28/// struct ChildSpace;
29/// type ScrollOffset = TypedTranslation2D<i32, ParentSpace, ChildSpace>;
30/// type ParentPoint = TypedPoint2D<i32, ParentSpace>;
31/// type ChildPoint = TypedPoint2D<i32, ChildSpace>;
32///
33/// let scrolling = ScrollOffset::new(0, 100);
34/// let p1: ParentPoint = point2(0, 0);
35/// let p2: ChildPoint = scrolling.transform_point(&p1);
36/// ```
37///
38#[derive(EuclidMatrix)]
39#[repr(C)]
40pub struct TypedTranslation2D<T, Src, Dst> {
41    pub x: T,
42    pub y: T,
43    #[doc(hidden)]
44    pub _unit: PhantomData<(Src, Dst)>,
45}
46
47impl<T, Src, Dst> TypedTranslation2D<T, Src, Dst> {
48    #[inline]
49    pub fn new(x: T, y: T) -> Self {
50        TypedTranslation2D {
51            x,
52            y,
53            _unit: PhantomData,
54        }
55    }
56}
57
58impl<T, Src, Dst> TypedTranslation2D<T, Src, Dst>
59where
60    T : Copy
61{
62    #[inline]
63    pub fn to_array(&self) -> [T; 2] {
64        [self.x, self.y]
65    }
66
67    #[inline]
68    pub fn to_tuple(&self) -> (T, T) {
69        (self.x, self.y)
70    }
71}
72
73impl<T, Src, Dst> TypedTranslation2D<T, Src, Dst>
74where
75    T : Copy + Zero
76{
77    #[inline]
78    pub fn identity() -> Self {
79        let _0 = T::zero();
80        TypedTranslation2D::new(_0, _0)
81    }
82}
83
84impl<T, Src, Dst> TypedTranslation2D<T, Src, Dst>
85where
86    T: Zero + PartialEq
87{
88    #[inline]
89    pub fn is_identity(&self) -> bool {
90        self.x == T::zero() && self.y == T::zero()
91    }
92}
93
94impl<T, Src, Dst> TypedTranslation2D<T, Src, Dst>
95where
96    T: Copy + Add<T, Output = T>
97{
98    /// Translate a point and cast its unit.
99    #[inline]
100    pub fn transform_point(&self, p: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
101        point2(p.x + self.x, p.y + self.y)
102    }
103
104    /// Translate a rectangle and cast its unit.
105    #[inline]
106    pub fn transform_rect(&self, r: &TypedRect<T, Src>) -> TypedRect<T, Dst> {
107        TypedRect {
108            origin: self.transform_point(&r.origin),
109            size: self.transform_size(&r.size),
110        }
111    }
112
113    /// No-op, just cast the unit.
114    #[inline]
115    pub fn transform_size(&self, s: &TypedSize2D<T, Src>) -> TypedSize2D<T, Dst> {
116        TypedSize2D::new(s.width, s.height)
117    }
118
119    /// Cast into a 2D vector.
120    pub fn to_vector(&self) -> TypedVector2D<T, Src> {
121        vec2(self.x, self.y)
122    }
123}
124
125impl<T, Src, Dst> TypedTranslation2D<T, Src, Dst>
126where
127    T: Copy + Neg<Output = T>
128{
129    /// Return the inverse transformation.
130    #[inline]
131    pub fn inverse(&self) -> TypedTranslation2D<T, Dst, Src> {
132        TypedTranslation2D::new(-self.x, -self.y)
133    }
134}
135
136impl<T, Src, Dst1, Dst2> Add<TypedTranslation2D<T, Dst1, Dst2>>
137for TypedTranslation2D<T, Src, Dst1>
138where
139    T: Copy + Add<T, Output = T>
140{
141    type Output = TypedTranslation2D<T, Src, Dst2>;
142    fn add(self, other: TypedTranslation2D<T, Dst1, Dst2>) -> TypedTranslation2D<T, Src, Dst2> {
143        TypedTranslation2D::new(
144            self.x + other.x,
145            self.y + other.y,
146        )
147    }
148}
149
150impl<T, Src, Dst1, Dst2>
151    Sub<TypedTranslation2D<T, Dst1, Dst2>>
152    for TypedTranslation2D<T, Src, Dst2>
153where
154    T: Copy + Sub<T, Output = T>
155{
156    type Output = TypedTranslation2D<T, Src, Dst1>;
157    fn sub(self, other: TypedTranslation2D<T, Dst1, Dst2>) -> TypedTranslation2D<T, Src, Dst1> {
158        TypedTranslation2D::new(
159            self.x - other.x,
160            self.y - other.y,
161        )
162    }
163}
164
165impl<T, Src, Dst> TypedTranslation2D<T, Src, Dst>
166where
167    T: Copy
168        + Clone
169        + Add<T, Output = T>
170        + Mul<T, Output = T>
171        + Div<T, Output = T>
172        + Sub<T, Output = T>
173        + Trig
174        + PartialOrd
175        + One
176        + Zero,
177{
178    /// Returns the matrix representation of this translation.
179    #[inline]
180    pub fn to_transform(&self) -> TypedTransform2D<T, Src, Dst> {
181        TypedTransform2D::create_translation(self.x, self.y)
182    }
183}
184
185impl<T, Src, Dst> From<TypedVector2D<T, Src>> for TypedTranslation2D<T, Src, Dst>
186where
187    T: Copy
188{
189    fn from(v: TypedVector2D<T, Src>) -> Self {
190        TypedTranslation2D::new(v.x, v.y)
191    }
192}
193
194impl<T, Src, Dst> Into<TypedVector2D<T, Src>> for TypedTranslation2D<T, Src, Dst>
195where
196    T: Copy
197{
198    fn into(self) -> TypedVector2D<T, Src> {
199        vec2(self.x, self.y)
200    }
201}
202
203impl<T, Src, Dst> Into<TypedTransform2D<T, Src, Dst>> for TypedTranslation2D<T, Src, Dst>
204where
205    T: Copy
206        + Clone
207        + Add<T, Output = T>
208        + Mul<T, Output = T>
209        + Div<T, Output = T>
210        + Sub<T, Output = T>
211        + Trig
212        + PartialOrd
213        + One
214        + Zero,
215{
216    fn into(self) -> TypedTransform2D<T, Src, Dst> {
217        self.to_transform()
218    }
219}
220
221impl <T, Src, Dst> Default for TypedTranslation2D<T, Src, Dst>
222    where T: Copy + Zero
223{
224    fn default() -> Self {
225        Self::identity()
226    }
227}
228
229impl<T, Src, Dst> fmt::Debug for TypedTranslation2D<T, Src, Dst>
230where T: Copy + fmt::Debug {
231    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
232        self.to_array().fmt(f)
233    }
234}
235
236
237
238/// A 3d transformation from a space to another that can only express translations.
239///
240/// The main benefit of this type over a TypedVector3D is the ability to cast
241/// between a source and a destination spaces.
242#[derive(EuclidMatrix)]
243#[repr(C)]
244pub struct TypedTranslation3D<T, Src, Dst> {
245    pub x: T,
246    pub y: T,
247    pub z: T,
248    #[doc(hidden)]
249    pub _unit: PhantomData<(Src, Dst)>,
250}
251
252impl<T, Src, Dst> TypedTranslation3D<T, Src, Dst> {
253    #[inline]
254    pub fn new(x: T, y: T, z: T) -> Self {
255        TypedTranslation3D {
256            x,
257            y,
258            z,
259            _unit: PhantomData,
260        }
261    }
262}
263
264impl<T, Src, Dst> TypedTranslation3D<T, Src, Dst>
265where
266    T: Copy
267{
268    #[inline]
269    pub fn to_array(&self) -> [T; 3] {
270        [self.x, self.y, self.z]
271    }
272
273    #[inline]
274    pub fn to_tuple(&self) -> (T, T, T) {
275        (self.x, self.y, self.z)
276    }
277}
278
279impl<T, Src, Dst> TypedTranslation3D<T, Src, Dst>
280where
281    T: Copy + Zero
282{
283    #[inline]
284    pub fn identity() -> Self {
285        let _0 = T::zero();
286        TypedTranslation3D::new(_0, _0, _0)
287    }
288}
289
290impl<T, Src, Dst> TypedTranslation3D<T, Src, Dst>
291where
292    T: Zero + PartialEq
293{
294    #[inline]
295    pub fn is_identity(&self) -> bool {
296        self.x == T::zero() && self.y == T::zero() && self.z == T::zero()
297    }
298}
299
300impl<T, Src, Dst> TypedTranslation3D<T, Src, Dst>
301where
302    T: Copy + Add<T, Output = T>
303{
304    /// Translate a point and cast its unit.
305    #[inline]
306    pub fn transform_point3d(&self, p: &TypedPoint3D<T, Src>) -> TypedPoint3D<T, Dst> {
307        point3(p.x + self.x, p.y + self.y, p.z + self.z)
308    }
309
310    /// Translate a point and cast its unit.
311    #[inline]
312    pub fn transform_point2d(&self, p: &TypedPoint2D<T, Src>) -> TypedPoint2D<T, Dst> {
313        point2(p.x + self.x, p.y + self.y)
314    }
315
316    /// Translate a rectangle and cast its unit.
317    #[inline]
318    pub fn transform_rect(&self, r: &TypedRect<T, Src>) -> TypedRect<T, Dst> {
319        TypedRect {
320            origin: self.transform_point2d(&r.origin),
321            size: self.transform_size(&r.size),
322        }
323    }
324
325    /// No-op, just cast the unit.
326    #[inline]
327    pub fn transform_size(&self, s: &TypedSize2D<T, Src>) -> TypedSize2D<T, Dst> {
328        TypedSize2D::new(s.width, s.height)
329    }
330
331    /// Cast into a 3D vector.
332    pub fn to_vector(&self) -> TypedVector3D<T, Src> {
333        vec3(self.x, self.y, self.z)
334    }
335}
336
337impl<T, Src, Dst> TypedTranslation3D<T, Src, Dst>
338where
339    T: Copy + Neg<Output = T>
340{
341    /// Return the inverse transformation.
342    #[inline]
343    pub fn inverse(&self) -> TypedTranslation3D<T, Dst, Src> {
344        TypedTranslation3D::new(-self.x, -self.y, -self.z)
345    }
346}
347
348impl<T, Src, Dst1, Dst2> Add<TypedTranslation3D<T, Dst1, Dst2>>
349for TypedTranslation3D<T, Src, Dst1>
350where
351    T: Copy + Add<T, Output = T>
352{
353    type Output = TypedTranslation3D<T, Src, Dst2>;
354    fn add(self, other: TypedTranslation3D<T, Dst1, Dst2>) -> TypedTranslation3D<T, Src, Dst2> {
355        TypedTranslation3D::new(
356            self.x + other.x,
357            self.y + other.y,
358            self.z + other.z,
359        )
360    }
361}
362
363impl<T, Src, Dst1, Dst2>
364    Sub<TypedTranslation3D<T, Dst1, Dst2>>
365    for TypedTranslation3D<T, Src, Dst2>
366where
367    T: Copy + Sub<T, Output = T>
368{
369    type Output = TypedTranslation3D<T, Src, Dst1>;
370    fn sub(self, other: TypedTranslation3D<T, Dst1, Dst2>) -> TypedTranslation3D<T, Src, Dst1> {
371        TypedTranslation3D::new(
372            self.x - other.x,
373            self.y - other.y,
374            self.z - other.z,
375        )
376    }
377}
378
379impl<T, Src, Dst> TypedTranslation3D<T, Src, Dst>
380where
381    T: Copy + Clone +
382        Add<T, Output=T> +
383        Sub<T, Output=T> +
384        Mul<T, Output=T> +
385        Div<T, Output=T> +
386        Neg<Output=T> +
387        PartialOrd +
388        Trig +
389        One + Zero,
390{
391    /// Returns the matrix representation of this translation.
392    #[inline]
393    pub fn to_transform(&self) -> TypedTransform3D<T, Src, Dst> {
394        TypedTransform3D::create_translation(self.x, self.y, self.z)
395    }
396}
397
398impl<T, Src, Dst> From<TypedVector3D<T, Src>> for TypedTranslation3D<T, Src, Dst>
399where
400    T: Copy
401{
402    fn from(v: TypedVector3D<T, Src>) -> Self {
403        TypedTranslation3D::new(v.x, v.y, v.z)
404    }
405}
406
407impl<T, Src, Dst> Into<TypedVector3D<T, Src>> for TypedTranslation3D<T, Src, Dst>
408where
409    T: Copy
410{
411    fn into(self) -> TypedVector3D<T, Src> {
412        vec3(self.x, self.y, self.z)
413    }
414}
415
416impl<T, Src, Dst> Into<TypedTransform3D<T, Src, Dst>> for TypedTranslation3D<T, Src, Dst>
417where
418    T: Copy + Clone +
419        Add<T, Output=T> +
420        Sub<T, Output=T> +
421        Mul<T, Output=T> +
422        Div<T, Output=T> +
423        Neg<Output=T> +
424        PartialOrd +
425        Trig +
426        One + Zero,
427{
428    fn into(self) -> TypedTransform3D<T, Src, Dst> {
429        self.to_transform()
430    }
431}
432
433impl <T, Src, Dst> Default for TypedTranslation3D<T, Src, Dst>
434    where T: Copy + Zero
435{
436    fn default() -> Self {
437        Self::identity()
438    }
439}
440
441impl<T, Src, Dst> fmt::Debug for TypedTranslation3D<T, Src, Dst>
442where T: Copy + fmt::Debug {
443    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
444        self.to_array().fmt(f)
445    }
446}
447
448#[test]
449fn simple_translation2d() {
450    use rect;
451
452    struct A;
453    struct B;
454
455    type Translation = TypedTranslation2D<i32, A, B>;
456    type SrcRect = TypedRect<i32, A>;
457    type DstRect = TypedRect<i32, B>;
458
459    let tx = Translation::new(10, -10);
460    let r1: SrcRect = rect(10, 20, 30, 40);
461    let r2: DstRect = tx.transform_rect(&r1);
462    assert_eq!(r2, rect(20, 10, 30, 40));
463
464    let inv_tx = tx.inverse();
465    assert_eq!(inv_tx.transform_rect(&r2), r1);
466
467    assert!((tx + inv_tx).is_identity());
468}
469
470#[test]
471fn simple_translation3d() {
472    struct A;
473    struct B;
474
475    type Translation = TypedTranslation3D<i32, A, B>;
476    type SrcPoint = TypedPoint3D<i32, A>;
477    type DstPoint = TypedPoint3D<i32, B>;
478
479    let tx = Translation::new(10, -10, 100);
480    let p1: SrcPoint = point3(10, 20, 30);
481    let p2: DstPoint = tx.transform_point3d(&p1);
482    assert_eq!(p2, point3(20, 10, 130));
483
484    let inv_tx = tx.inverse();
485    assert_eq!(inv_tx.transform_point3d(&p2), p1);
486
487    assert!((tx + inv_tx).is_identity());
488}