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
25namespace 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
34        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
40        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]
48        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
54        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
243            iterator_x() {}
244            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        //--------------------------------------------------------------------
267        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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
424    inline trans_perspective::trans_perspective(const double* src,
425                                                const double* dst)
426    {
427        quad_to_quad(src, dst);
428    }
429
430    //------------------------------------------------------------------------
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&
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&
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&
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&
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&
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&
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&
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&
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&
542    trans_perspective::translate(double x, double y)
543    {
544        tx += x;
545        ty += y;
546        return *this;
547    }
548
549    //------------------------------------------------------------------------
550    inline const trans_perspective& trans_perspective::rotate(double a)
551    {
552        multiply(trans_affine_rotation(a));
553        return *this;
554    }
555
556    //------------------------------------------------------------------------
557    inline const trans_perspective& trans_perspective::scale(double s)
558    {
559        multiply(trans_affine_scaling(s));
560        return *this;
561    }
562
563    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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&
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
639    inline double trans_perspective::determinant_reciprocal() const
640    {
641        return 1.0 / determinant();
642    }
643
644    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
700    inline void trans_perspective::translation(double* dx, double* dy) const
701    {
702        *dx = tx;
703        *dy = ty;
704    }
705
706    //------------------------------------------------------------------------
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    //------------------------------------------------------------------------
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