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