xref: /haiku/headers/libs/agg/agg_trans_perspective.h (revision c6c2c0428420c1a7a9b16a843b41ab26903bc5fb)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.4
3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 //
16 // Perspective 2D transformations
17 //
18 //----------------------------------------------------------------------------
19 #ifndef AGG_TRANS_PERSPECTIVE_INCLUDED
20 #define AGG_TRANS_PERSPECTIVE_INCLUDED
21 
22 #include <cmath>
23 #include "agg_trans_affine.h"
24 
25 namespace agg
26 {
27     //=======================================================trans_perspective
28     struct trans_perspective
29     {
30         double sx, shy, w0, shx, sy, w1, tx, ty, w2;
31 
32         //------------------------------------------------------- Construction
33         // Identity matrix
trans_perspectivetrans_perspective34         trans_perspective() :
35             sx (1), shy(0), w0(0),
36             shx(0), sy (1), w1(0),
37             tx (0), ty (0), w2(1) {}
38 
39         // Custom matrix
trans_perspectivetrans_perspective40         trans_perspective(double v0, double v1, double v2,
41                           double v3, double v4, double v5,
42                           double v6, double v7, double v8) :
43            sx (v0), shy(v1), w0(v2),
44            shx(v3), sy (v4), w1(v5),
45            tx (v6), ty (v7), w2(v8) {}
46 
47         // Custom matrix from m[9]
trans_perspectivetrans_perspective48         explicit trans_perspective(const double* m) :
49            sx (m[0]), shy(m[1]), w0(m[2]),
50            shx(m[3]), sy (m[4]), w1(m[5]),
51            tx (m[6]), ty (m[7]), w2(m[8]) {}
52 
53         // From affine
trans_perspectivetrans_perspective54         explicit trans_perspective(const trans_affine& a) :
55            sx (a.sx ), shy(a.shy), w0(0),
56            shx(a.shx), sy (a.sy ), w1(0),
57            tx (a.tx ), ty (a.ty ), w2(1) {}
58 
59         // Rectangle to quadrilateral
60         trans_perspective(double x1, double y1, double x2, double y2,
61                           const double* quad);
62 
63         // Quadrilateral to rectangle
64         trans_perspective(const double* quad,
65                           double x1, double y1, double x2, double y2);
66 
67         // Arbitrary quadrilateral transformations
68         trans_perspective(const double* src, const double* dst);
69 
70         //-------------------------------------- Quadrilateral transformations
71         // The arguments are double[8] that are mapped to quadrilaterals:
72         // x1,y1, x2,y2, x3,y3, x4,y4
73         bool quad_to_quad(const double* qs, const double* qd);
74 
75         bool rect_to_quad(double x1, double y1,
76                           double x2, double y2,
77                           const double* q);
78 
79         bool quad_to_rect(const double* q,
80                           double x1, double y1,
81                           double x2, double y2);
82 
83         // Map square (0,0,1,1) to the quadrilateral and vice versa
84         bool square_to_quad(const double* q);
85         bool quad_to_square(const double* q);
86 
87 
88         //--------------------------------------------------------- Operations
89         // Reset - load an identity matrix
90         const trans_perspective& reset();
91 
92         // Invert matrix. Returns false in degenerate case
93         bool invert();
94 
95         // Direct transformations operations
96         const trans_perspective& translate(double x, double y);
97         const trans_perspective& rotate(double a);
98         const trans_perspective& scale(double s);
99         const trans_perspective& scale(double x, double y);
100 
101         // Multiply the matrix by another one
102         const trans_perspective& multiply(const trans_perspective& m);
103 
104         // Multiply "m" by "this" and assign the result to "this"
105         const trans_perspective& premultiply(const trans_perspective& m);
106 
107         // Multiply matrix to inverse of another one
108         const trans_perspective& multiply_inv(const trans_perspective& m);
109 
110         // Multiply inverse of "m" by "this" and assign the result to "this"
111         const trans_perspective& premultiply_inv(const trans_perspective& m);
112 
113         // Multiply the matrix by another one
114         const trans_perspective& multiply(const trans_affine& m);
115 
116         // Multiply "m" by "this" and assign the result to "this"
117         const trans_perspective& premultiply(const trans_affine& m);
118 
119         // Multiply the matrix by inverse of another one
120         const trans_perspective& multiply_inv(const trans_affine& m);
121 
122         // Multiply inverse of "m" by "this" and assign the result to "this"
123         const trans_perspective& premultiply_inv(const trans_affine& m);
124 
125         //--------------------------------------------------------- Load/Store
126         void store_to(double* m) const;
127         const trans_perspective& load_from(const double* m);
128 
129         //---------------------------------------------------------- Operators
130         // Multiply the matrix by another one
131         const trans_perspective& operator *= (const trans_perspective& m)
132         {
133             return multiply(m);
134         }
135         const trans_perspective& operator *= (const trans_affine& m)
136         {
137             return multiply(m);
138         }
139 
140         // Multiply the matrix by inverse of another one
141         const trans_perspective& operator /= (const trans_perspective& m)
142         {
143             return multiply_inv(m);
144         }
145         const trans_perspective& operator /= (const trans_affine& m)
146         {
147             return multiply_inv(m);
148         }
149 
150         // Multiply the matrix by another one and return
151         // the result in a separete matrix.
152         trans_perspective operator * (const trans_perspective& m) const
153         {
154             return trans_perspective(*this).multiply(m);
155         }
156         trans_perspective operator * (const trans_affine& m) const
157         {
158             return trans_perspective(*this).multiply(m);
159         }
160 
161         // Multiply the matrix by inverse of another one
162         // and return the result in a separete matrix.
163         trans_perspective operator / (const trans_perspective& m) const
164         {
165             return trans_perspective(*this).multiply_inv(m);
166         }
167         trans_perspective operator / (const trans_affine& m) const
168         {
169             return trans_perspective(*this).multiply_inv(m);
170         }
171 
172         // Calculate and return the inverse matrix
173         trans_perspective operator ~ () const
174         {
175             trans_perspective ret = *this;
176             ret.invert();
177             return ret;
178         }
179 
180         // Equal operator with default epsilon
181         bool operator == (const trans_perspective& m) const
182         {
183             return is_equal(m, affine_epsilon);
184         }
185 
186         // Not Equal operator with default epsilon
187         bool operator != (const trans_perspective& m) const
188         {
189             return !is_equal(m, affine_epsilon);
190         }
191 
192         //---------------------------------------------------- Transformations
193         // Direct transformation of x and y
194         void transform(double* x, double* y) const;
195 
196         // Direct transformation of x and y, affine part only
197         void transform_affine(double* x, double* y) const;
198 
199         // Direct transformation of x and y, 2x2 matrix only, no translation
200         void transform_2x2(double* x, double* y) const;
201 
202         // Inverse transformation of x and y. It works slow because
203         // it explicitly inverts the matrix on every call. For massive
204         // operations it's better to invert() the matrix and then use
205         // direct transformations.
206         void inverse_transform(double* x, double* y) const;
207 
208 
209         //---------------------------------------------------------- Auxiliary
210         const trans_perspective& from_affine(const trans_affine& a);
211         double determinant() const;
212         double determinant_reciprocal() const;
213 
214         bool is_valid(double epsilon = affine_epsilon) const;
215         bool is_identity(double epsilon = affine_epsilon) const;
216         bool is_equal(const trans_perspective& m,
217                       double epsilon = affine_epsilon) const;
218 
219         // Determine the major affine parameters. Use with caution
220         // considering possible degenerate cases.
221         double scale() const;
222         double rotation() const;
223         void   translation(double* dx, double* dy) const;
224         void   scaling(double* x, double* y) const;
225         void   scaling_abs(double* x, double* y) const;
226 
227 
228 
229         //--------------------------------------------------------------------
230         class iterator_x
231         {
232             double den;
233             double den_step;
234             double nom_x;
235             double nom_x_step;
236             double nom_y;
237             double nom_y_step;
238 
239         public:
240             double x;
241             double y;
242 
iterator_xtrans_perspective243             iterator_x() {}
iterator_xtrans_perspective244             iterator_x(double px, double py, double step, const trans_perspective& m) :
245                 den(px * m.w0 + py * m.w1 + m.w2),
246                 den_step(m.w0 * step),
247                 nom_x(px * m.sx + py * m.shx + m.tx),
248                 nom_x_step(step * m.sx),
249                 nom_y(px * m.shy + py * m.sy + m.ty),
250                 nom_y_step(step * m.shy),
251                 x(nom_x / den),
252                 y(nom_y / den)
253             {}
254 
255             void operator ++ ()
256             {
257                 den   += den_step;
258                 nom_x += nom_x_step;
259                 nom_y += nom_y_step;
260                 double d = 1.0 / den;
261                 x = nom_x * d;
262                 y = nom_y * d;
263             }
264         };
265 
266         //--------------------------------------------------------------------
begintrans_perspective267         iterator_x begin(double x, double y, double step) const
268         {
269             return iterator_x(x, y, step, *this);
270         }
271     };
272 
273 
274 
275 
276 
277 
278 
279 
280 
281 
282 
283 
284 
285 
286     //------------------------------------------------------------------------
square_to_quad(const double * q)287     inline bool trans_perspective::square_to_quad(const double* q)
288     {
289         double dx = q[0] - q[2] + q[4] - q[6];
290         double dy = q[1] - q[3] + q[5] - q[7];
291         if(dx == 0.0 && dy == 0.0)
292         {
293             // Affine case (parallelogram)
294             //---------------
295             sx  = q[2] - q[0];
296             shy = q[3] - q[1];
297             w0  = 0.0;
298             shx = q[4] - q[2];
299             sy  = q[5] - q[3];
300             w1  = 0.0;
301             tx  = q[0];
302             ty  = q[1];
303             w2  = 1.0;
304         }
305         else
306         {
307             double dx1 = q[2] - q[4];
308             double dy1 = q[3] - q[5];
309             double dx2 = q[6] - q[4];
310             double dy2 = q[7] - q[5];
311             double den = dx1 * dy2 - dx2 * dy1;
312             if(den == 0.0)
313             {
314                 // Singular case
315                 //---------------
316                 sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0;
317                 return false;
318             }
319             // General case
320             //---------------
321             double u = (dx * dy2 - dy * dx2) / den;
322             double v = (dy * dx1 - dx * dy1) / den;
323             sx  = q[2] - q[0] + u * q[2];
324             shy = q[3] - q[1] + u * q[3];
325             w0  = u;
326             shx = q[6] - q[0] + v * q[6];
327             sy  = q[7] - q[1] + v * q[7];
328             w1  = v;
329             tx  = q[0];
330             ty  = q[1];
331             w2  = 1.0;
332         }
333         return true;
334     }
335 
336     //------------------------------------------------------------------------
invert()337     inline bool trans_perspective::invert()
338     {
339         double d0 = sy  * w2 - w1  * ty;
340         double d1 = w0  * ty - shy * w2;
341         double d2 = shy * w1 - w0  * sy;
342         double d  = sx  * d0 + shx * d1 + tx * d2;
343         if(d == 0.0)
344         {
345             sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0;
346             return false;
347         }
348         d = 1.0 / d;
349         trans_perspective a = *this;
350         sx  = d * d0;
351         shy = d * d1;
352         w0  = d * d2;
353         shx = d * (a.w1 *a.tx  - a.shx*a.w2);
354         sy  = d * (a.sx *a.w2  - a.w0 *a.tx);
355         w1  = d * (a.w0 *a.shx - a.sx *a.w1);
356         tx  = d * (a.shx*a.ty  - a.sy *a.tx);
357         ty  = d * (a.shy*a.tx  - a.sx *a.ty);
358         w2  = d * (a.sx *a.sy  - a.shy*a.shx);
359         return true;
360     }
361 
362     //------------------------------------------------------------------------
quad_to_square(const double * q)363     inline bool trans_perspective::quad_to_square(const double* q)
364     {
365         if(!square_to_quad(q)) return false;
366         invert();
367         return true;
368     }
369 
370     //------------------------------------------------------------------------
quad_to_quad(const double * qs,const double * qd)371     inline bool trans_perspective::quad_to_quad(const double* qs,
372                                                 const double* qd)
373     {
374         trans_perspective p;
375         if(!  quad_to_square(qs)) return false;
376         if(!p.square_to_quad(qd)) return false;
377         multiply(p);
378         return true;
379     }
380 
381     //------------------------------------------------------------------------
rect_to_quad(double x1,double y1,double x2,double y2,const double * q)382     inline bool trans_perspective::rect_to_quad(double x1, double y1,
383                                                 double x2, double y2,
384                                                 const double* q)
385     {
386         double r[8];
387         r[0] = r[6] = x1;
388         r[2] = r[4] = x2;
389         r[1] = r[3] = y1;
390         r[5] = r[7] = y2;
391         return quad_to_quad(r, q);
392     }
393 
394     //------------------------------------------------------------------------
quad_to_rect(const double * q,double x1,double y1,double x2,double y2)395     inline bool trans_perspective::quad_to_rect(const double* q,
396                                                 double x1, double y1,
397                                                 double x2, double y2)
398     {
399         double r[8];
400         r[0] = r[6] = x1;
401         r[2] = r[4] = x2;
402         r[1] = r[3] = y1;
403         r[5] = r[7] = y2;
404         return quad_to_quad(q, r);
405     }
406 
407     //------------------------------------------------------------------------
trans_perspective(double x1,double y1,double x2,double y2,const double * quad)408     inline trans_perspective::trans_perspective(double x1, double y1,
409                                                 double x2, double y2,
410                                                 const double* quad)
411     {
412         rect_to_quad(x1, y1, x2, y2, quad);
413     }
414 
415     //------------------------------------------------------------------------
trans_perspective(const double * quad,double x1,double y1,double x2,double y2)416     inline trans_perspective::trans_perspective(const double* quad,
417                                                 double x1, double y1,
418                                                 double x2, double y2)
419     {
420         quad_to_rect(quad, x1, y1, x2, y2);
421     }
422 
423     //------------------------------------------------------------------------
trans_perspective(const double * src,const double * dst)424     inline trans_perspective::trans_perspective(const double* src,
425                                                 const double* dst)
426     {
427         quad_to_quad(src, dst);
428     }
429 
430     //------------------------------------------------------------------------
reset()431     inline const trans_perspective& trans_perspective::reset()
432     {
433         sx  = 1; shy = 0; w0 = 0;
434         shx = 0; sy  = 1; w1 = 0;
435         tx  = 0; ty  = 0; w2 = 1;
436         return *this;
437     }
438 
439     //------------------------------------------------------------------------
440     inline const trans_perspective&
multiply(const trans_perspective & a)441     trans_perspective::multiply(const trans_perspective& a)
442     {
443         trans_perspective b = *this;
444         sx  = a.sx *b.sx  + a.shx*b.shy + a.tx*b.w0;
445         shx = a.sx *b.shx + a.shx*b.sy  + a.tx*b.w1;
446         tx  = a.sx *b.tx  + a.shx*b.ty  + a.tx*b.w2;
447         shy = a.shy*b.sx  + a.sy *b.shy + a.ty*b.w0;
448         sy  = a.shy*b.shx + a.sy *b.sy  + a.ty*b.w1;
449         ty  = a.shy*b.tx  + a.sy *b.ty  + a.ty*b.w2;
450         w0  = a.w0 *b.sx  + a.w1 *b.shy + a.w2*b.w0;
451         w1  = a.w0 *b.shx + a.w1 *b.sy  + a.w2*b.w1;
452         w2  = a.w0 *b.tx  + a.w1 *b.ty  + a.w2*b.w2;
453         return *this;
454     }
455 
456     //------------------------------------------------------------------------
457     inline const trans_perspective&
multiply(const trans_affine & a)458     trans_perspective::multiply(const trans_affine& a)
459     {
460         trans_perspective b = *this;
461         sx  = a.sx *b.sx  + a.shx*b.shy + a.tx*b.w0;
462         shx = a.sx *b.shx + a.shx*b.sy  + a.tx*b.w1;
463         tx  = a.sx *b.tx  + a.shx*b.ty  + a.tx*b.w2;
464         shy = a.shy*b.sx  + a.sy *b.shy + a.ty*b.w0;
465         sy  = a.shy*b.shx + a.sy *b.sy  + a.ty*b.w1;
466         ty  = a.shy*b.tx  + a.sy *b.ty  + a.ty*b.w2;
467         return *this;
468     }
469 
470     //------------------------------------------------------------------------
471     inline const trans_perspective&
premultiply(const trans_perspective & b)472     trans_perspective::premultiply(const trans_perspective& b)
473     {
474         trans_perspective a = *this;
475         sx  = a.sx *b.sx  + a.shx*b.shy + a.tx*b.w0;
476         shx = a.sx *b.shx + a.shx*b.sy  + a.tx*b.w1;
477         tx  = a.sx *b.tx  + a.shx*b.ty  + a.tx*b.w2;
478         shy = a.shy*b.sx  + a.sy *b.shy + a.ty*b.w0;
479         sy  = a.shy*b.shx + a.sy *b.sy  + a.ty*b.w1;
480         ty  = a.shy*b.tx  + a.sy *b.ty  + a.ty*b.w2;
481         w0  = a.w0 *b.sx  + a.w1 *b.shy + a.w2*b.w0;
482         w1  = a.w0 *b.shx + a.w1 *b.sy  + a.w2*b.w1;
483         w2  = a.w0 *b.tx  + a.w1 *b.ty  + a.w2*b.w2;
484         return *this;
485     }
486 
487     //------------------------------------------------------------------------
488     inline const trans_perspective&
premultiply(const trans_affine & b)489     trans_perspective::premultiply(const trans_affine& b)
490     {
491         trans_perspective a = *this;
492         sx  = a.sx *b.sx  + a.shx*b.shy;
493         shx = a.sx *b.shx + a.shx*b.sy;
494         tx  = a.sx *b.tx  + a.shx*b.ty  + a.tx;
495         shy = a.shy*b.sx  + a.sy *b.shy;
496         sy  = a.shy*b.shx + a.sy *b.sy;
497         ty  = a.shy*b.tx  + a.sy *b.ty  + a.ty;
498         w0  = a.w0 *b.sx  + a.w1 *b.shy;
499         w1  = a.w0 *b.shx + a.w1 *b.sy;
500         w2  = a.w0 *b.tx  + a.w1 *b.ty  + a.w2;
501         return *this;
502     }
503 
504     //------------------------------------------------------------------------
505     inline const trans_perspective&
multiply_inv(const trans_perspective & m)506     trans_perspective::multiply_inv(const trans_perspective& m)
507     {
508         trans_perspective t = m;
509         t.invert();
510         return multiply(t);
511     }
512 
513     //------------------------------------------------------------------------
514     inline const trans_perspective&
multiply_inv(const trans_affine & m)515     trans_perspective::multiply_inv(const trans_affine& m)
516     {
517         trans_affine t = m;
518         t.invert();
519         return multiply(t);
520     }
521 
522     //------------------------------------------------------------------------
523     inline const trans_perspective&
premultiply_inv(const trans_perspective & m)524     trans_perspective::premultiply_inv(const trans_perspective& m)
525     {
526         trans_perspective t = m;
527         t.invert();
528         return *this = t.multiply(*this);
529     }
530 
531     //------------------------------------------------------------------------
532     inline const trans_perspective&
premultiply_inv(const trans_affine & m)533     trans_perspective::premultiply_inv(const trans_affine& m)
534     {
535         trans_perspective t(m);
536         t.invert();
537         return *this = t.multiply(*this);
538     }
539 
540     //------------------------------------------------------------------------
541     inline const trans_perspective&
translate(double x,double y)542     trans_perspective::translate(double x, double y)
543     {
544         tx += x;
545         ty += y;
546         return *this;
547     }
548 
549     //------------------------------------------------------------------------
rotate(double a)550     inline const trans_perspective& trans_perspective::rotate(double a)
551     {
552         multiply(trans_affine_rotation(a));
553         return *this;
554     }
555 
556     //------------------------------------------------------------------------
scale(double s)557     inline const trans_perspective& trans_perspective::scale(double s)
558     {
559         multiply(trans_affine_scaling(s));
560         return *this;
561     }
562 
563     //------------------------------------------------------------------------
scale(double x,double y)564     inline const trans_perspective& trans_perspective::scale(double x, double y)
565     {
566         multiply(trans_affine_scaling(x, y));
567         return *this;
568     }
569 
570     //------------------------------------------------------------------------
transform(double * px,double * py)571     inline void trans_perspective::transform(double* px, double* py) const
572     {
573         double x = *px;
574         double y = *py;
575         double m = 1.0 / (x*w0 + y*w1 + w2);
576         *px = m * (x*sx  + y*shx + tx);
577         *py = m * (x*shy + y*sy  + ty);
578     }
579 
580     //------------------------------------------------------------------------
transform_affine(double * x,double * y)581     inline void trans_perspective::transform_affine(double* x, double* y) const
582     {
583         double tmp = *x;
584         *x = tmp * sx  + *y * shx + tx;
585         *y = tmp * shy + *y * sy  + ty;
586     }
587 
588     //------------------------------------------------------------------------
transform_2x2(double * x,double * y)589     inline void trans_perspective::transform_2x2(double* x, double* y) const
590     {
591         double tmp = *x;
592         *x = tmp * sx  + *y * shx;
593         *y = tmp * shy + *y * sy;
594     }
595 
596     //------------------------------------------------------------------------
inverse_transform(double * x,double * y)597     inline void trans_perspective::inverse_transform(double* x, double* y) const
598     {
599         trans_perspective t(*this);
600         if(t.invert()) t.transform(x, y);
601     }
602 
603     //------------------------------------------------------------------------
store_to(double * m)604     inline void trans_perspective::store_to(double* m) const
605     {
606         *m++ = sx;  *m++ = shy; *m++ = w0;
607         *m++ = shx; *m++ = sy;  *m++ = w1;
608         *m++ = tx;  *m++ = ty;  *m++ = w2;
609     }
610 
611     //------------------------------------------------------------------------
load_from(const double * m)612     inline const trans_perspective& trans_perspective::load_from(const double* m)
613     {
614         sx  = *m++; shy = *m++; w0 = *m++;
615         shx = *m++; sy  = *m++; w1 = *m++;
616         tx  = *m++; ty  = *m++; w2 = *m++;
617         return *this;
618     }
619 
620     //------------------------------------------------------------------------
621     inline const trans_perspective&
from_affine(const trans_affine & a)622     trans_perspective::from_affine(const trans_affine& a)
623     {
624         sx  = a.sx;  shy = a.shy; w0 = 0;
625         shx = a.shx; sy  = a.sy;  w1 = 0;
626         tx  = a.tx;  ty  = a.ty;  w2 = 1;
627         return *this;
628     }
629 
630     //------------------------------------------------------------------------
determinant()631     inline double trans_perspective::determinant() const
632     {
633         return sx  * (sy  * w2 - ty  * w1) +
634                shx * (ty  * w0 - shy * w2) +
635                tx  * (shy * w1 - sy  * w0);
636     }
637 
638     //------------------------------------------------------------------------
determinant_reciprocal()639     inline double trans_perspective::determinant_reciprocal() const
640     {
641         return 1.0 / determinant();
642     }
643 
644     //------------------------------------------------------------------------
is_valid(double epsilon)645     inline bool trans_perspective::is_valid(double epsilon) const
646     {
647         return std::fabs(sx) > epsilon && std::fabs(sy) > epsilon && std::fabs(w2) > epsilon;
648     }
649 
650     //------------------------------------------------------------------------
is_identity(double epsilon)651     inline bool trans_perspective::is_identity(double epsilon) const
652     {
653         return is_equal_eps(sx,  1.0, epsilon) &&
654                is_equal_eps(shy, 0.0, epsilon) &&
655                is_equal_eps(w0,  0.0, epsilon) &&
656                is_equal_eps(shx, 0.0, epsilon) &&
657                is_equal_eps(sy,  1.0, epsilon) &&
658                is_equal_eps(w1,  0.0, epsilon) &&
659                is_equal_eps(tx,  0.0, epsilon) &&
660                is_equal_eps(ty,  0.0, epsilon) &&
661                is_equal_eps(w2,  1.0, epsilon);
662     }
663 
664     //------------------------------------------------------------------------
is_equal(const trans_perspective & m,double epsilon)665     inline bool trans_perspective::is_equal(const trans_perspective& m,
666                                             double epsilon) const
667     {
668         return is_equal_eps(sx,  m.sx,  epsilon) &&
669                is_equal_eps(shy, m.shy, epsilon) &&
670                is_equal_eps(w0,  m.w0,  epsilon) &&
671                is_equal_eps(shx, m.shx, epsilon) &&
672                is_equal_eps(sy,  m.sy,  epsilon) &&
673                is_equal_eps(w1,  m.w1,  epsilon) &&
674                is_equal_eps(tx,  m.tx,  epsilon) &&
675                is_equal_eps(ty,  m.ty,  epsilon) &&
676                is_equal_eps(w2,  m.w2,  epsilon);
677     }
678 
679     //------------------------------------------------------------------------
scale()680     inline double trans_perspective::scale() const
681     {
682         double x = 0.707106781 * sx  + 0.707106781 * shx;
683         double y = 0.707106781 * shy + 0.707106781 * sy;
684         return std::sqrt(x*x + y*y);
685     }
686 
687     //------------------------------------------------------------------------
rotation()688     inline double trans_perspective::rotation() const
689     {
690         double x1 = 0.0;
691         double y1 = 0.0;
692         double x2 = 1.0;
693         double y2 = 0.0;
694         transform(&x1, &y1);
695         transform(&x2, &y2);
696         return std::atan2(y2-y1, x2-x1);
697     }
698 
699     //------------------------------------------------------------------------
translation(double * dx,double * dy)700     inline void trans_perspective::translation(double* dx, double* dy) const
701     {
702         *dx = tx;
703         *dy = ty;
704     }
705 
706     //------------------------------------------------------------------------
scaling(double * x,double * y)707     inline void trans_perspective::scaling(double* x, double* y) const
708     {
709         double x1 = 0.0;
710         double y1 = 0.0;
711         double x2 = 1.0;
712         double y2 = 1.0;
713         trans_perspective t(*this);
714         t *= trans_affine_rotation(-rotation());
715         t.transform(&x1, &y1);
716         t.transform(&x2, &y2);
717         *x = x2 - x1;
718         *y = y2 - y1;
719     }
720 
721     //------------------------------------------------------------------------
scaling_abs(double * x,double * y)722     inline void trans_perspective::scaling_abs(double* x, double* y) const
723     {
724         *x = std::sqrt(sx  * sx  + shx * shx);
725         *y = std::sqrt(shy * shy + sy  * sy);
726     }
727 
728 
729 }
730 
731 #endif
732 
733