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