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