1 /* 2 * Copyright 2008-2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Stephen Deken, stephen.deken@gmail.com 7 * Stephan Aßmus <superstippi@gmx.de> 8 */ 9 //---------------------------------------------------------------------------- 10 // Anti-Grain Geometry - Version 2.4 11 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) 12 // 13 // Permission to copy, use, modify, sell and distribute this software 14 // is granted provided this copyright notice appears in all copies. 15 // This software is provided "as is" without express or implied 16 // warranty, and with no claim as to its suitability for any purpose. 17 // 18 //---------------------------------------------------------------------------- 19 // Contact: mcseem@antigrain.com 20 // mcseemagg@yahoo.com 21 // http://www.antigrain.com 22 //---------------------------------------------------------------------------- 23 24 #include <AffineTransform.h> 25 26 #include <TypeConstants.h> 27 28 29 const BAffineTransform B_AFFINE_IDENTITY_TRANSFORM; 30 31 32 BAffineTransform::BAffineTransform() 33 : 34 sx(1.0), 35 shy(0.0), 36 shx(0.0), 37 sy(1.0), 38 tx(0.0), 39 ty(0.0) 40 { 41 } 42 43 44 BAffineTransform::BAffineTransform(double sx, double shy, double shx, 45 double sy, double tx, double ty) 46 : 47 sx(sx), 48 shy(shy), 49 shx(shx), 50 sy(sy), 51 tx(tx), 52 ty(ty) 53 { 54 } 55 56 57 BAffineTransform::BAffineTransform(const BAffineTransform& other) 58 : 59 sx(other.sx), 60 shy(other.shy), 61 shx(other.shx), 62 sy(other.sy), 63 tx(other.tx), 64 ty(other.ty) 65 { 66 } 67 68 69 BAffineTransform::~BAffineTransform() 70 { 71 } 72 73 74 // #pragma mark - 75 76 77 bool 78 BAffineTransform::IsFixedSize() const 79 { 80 return true; 81 } 82 83 84 type_code 85 BAffineTransform::TypeCode() const 86 { 87 return B_AFFINE_TRANSFORM_TYPE; 88 } 89 90 91 ssize_t 92 BAffineTransform::FlattenedSize() const 93 { 94 return 6 * sizeof(double); 95 } 96 97 98 status_t 99 BAffineTransform::Flatten(void* _buffer, ssize_t size) const 100 { 101 if (_buffer == NULL || size < BAffineTransform::FlattenedSize()) 102 return B_BAD_VALUE; 103 104 double* buffer = reinterpret_cast<double*>(_buffer); 105 106 buffer[0] = sx; 107 buffer[1] = shy; 108 buffer[2] = shx; 109 buffer[3] = sy; 110 buffer[4] = tx; 111 buffer[5] = ty; 112 113 return B_OK; 114 } 115 116 117 status_t 118 BAffineTransform::Unflatten(type_code code, const void* _buffer, ssize_t size) 119 { 120 if (_buffer == NULL || size < BAffineTransform::FlattenedSize() 121 || code != BAffineTransform::TypeCode()) { 122 return B_BAD_VALUE; 123 } 124 125 const double* buffer = reinterpret_cast<const double*>(_buffer); 126 127 sx = buffer[0]; 128 shy = buffer[1]; 129 shx = buffer[2]; 130 sy = buffer[3]; 131 tx = buffer[4]; 132 ty = buffer[5]; 133 134 return B_OK; 135 } 136 137 138 // #pragma mark - 139 140 141 /*static*/ BAffineTransform 142 BAffineTransform::AffineTranslation(double x, double y) 143 { 144 return BAffineTransform(1.0, 0.0, 0.0, 1.0, x, y); 145 } 146 147 148 /*static*/ BAffineTransform 149 BAffineTransform::AffineRotation(double angle) 150 { 151 return BAffineTransform(cos(angle), sin(angle), -sin(angle), cos(angle), 152 0.0, 0.0); 153 } 154 155 156 /*static*/ BAffineTransform 157 BAffineTransform::AffineScaling(double x, double y) 158 { 159 return BAffineTransform(x, 0.0, 0.0, y, 0.0, 0.0); 160 } 161 162 163 /*static*/ BAffineTransform 164 BAffineTransform::AffineScaling(double scale) 165 { 166 return BAffineTransform(scale, 0.0, 0.0, scale, 0.0, 0.0); 167 } 168 169 170 /*static*/ BAffineTransform 171 BAffineTransform::AffineShearing(double x, double y) 172 { 173 return BAffineTransform(1.0, tan(y), tan(x), 1.0, 0.0, 0.0); 174 } 175 176 177 // #pragma mark - 178 179 180 BPoint 181 BAffineTransform::Apply(const BPoint& point) const 182 { 183 double x = point.x; 184 double y = point.y; 185 Apply(&x, &y); 186 return BPoint(x, y); 187 } 188 189 190 BPoint 191 BAffineTransform::ApplyInverse(const BPoint& point) const 192 { 193 double x = point.x; 194 double y = point.y; 195 ApplyInverse(&x, &y); 196 return BPoint(x, y); 197 } 198 199 200 void 201 BAffineTransform::Apply(BPoint* point) const 202 { 203 if (point == NULL) 204 return; 205 double x = point->x; 206 double y = point->y; 207 Apply(&x, &y); 208 point->x = x; 209 point->y = y; 210 } 211 212 213 void 214 BAffineTransform::ApplyInverse(BPoint* point) const 215 { 216 if (point == NULL) 217 return; 218 double x = point->x; 219 double y = point->y; 220 ApplyInverse(&x, &y); 221 point->x = x; 222 point->y = y; 223 } 224 225 226 void 227 BAffineTransform::Apply(BPoint* points, uint32 count) const 228 { 229 if (points != NULL) { 230 for (uint32 i = 0; i < count; ++i) 231 Apply(&points[i]); 232 } 233 } 234 235 236 void 237 BAffineTransform::ApplyInverse(BPoint* points, uint32 count) const 238 { 239 if (points != NULL) { 240 for (uint32 i = 0; i < count; ++i) 241 ApplyInverse(&points[i]); 242 } 243 } 244 245 246 // #pragma mark - 247 248 249 const BAffineTransform& 250 BAffineTransform::TranslateBy(const BPoint& delta) 251 { 252 return TranslateBy(delta.x, delta.y); 253 } 254 255 256 BAffineTransform 257 BAffineTransform::TranslateByCopy(double x, double y) const 258 { 259 BAffineTransform copy(*this); 260 copy.TranslateBy(x, y); 261 return copy; 262 } 263 264 265 BAffineTransform 266 BAffineTransform::TranslateByCopy(const BPoint& delta) const 267 { 268 return TranslateByCopy(delta.x, delta.y); 269 } 270 271 272 // #pragma mark - 273 274 275 const BAffineTransform& 276 BAffineTransform::RotateBy(const BPoint& center, double angle) 277 { 278 TranslateBy(-center.x, -center.y); 279 RotateBy(angle); 280 return TranslateBy(center.x, center.y); 281 } 282 283 284 BAffineTransform 285 BAffineTransform::RotateByCopy(double angle) const 286 { 287 BAffineTransform copy(*this); 288 copy.RotateBy(angle); 289 return copy; 290 } 291 292 293 BAffineTransform 294 BAffineTransform::RotateByCopy(const BPoint& center, double angle) const 295 { 296 BAffineTransform copy(*this); 297 copy.RotateBy(center, angle); 298 return copy; 299 } 300 301 302 // #pragma mark - 303 304 305 const BAffineTransform& 306 BAffineTransform::ScaleBy(const BPoint& center, double scale) 307 { 308 return ScaleBy(center, scale, scale); 309 } 310 311 312 const BAffineTransform& 313 BAffineTransform::ScaleBy(const BPoint& center, double x, double y) 314 { 315 TranslateBy(-center.x, -center.y); 316 ScaleBy(x, y); 317 return TranslateBy(center.x, center.y); 318 } 319 320 321 const BAffineTransform& 322 BAffineTransform::ScaleBy(const BPoint& scale) 323 { 324 return ScaleBy(scale.x, scale.y); 325 } 326 327 328 const BAffineTransform& 329 BAffineTransform::ScaleBy(const BPoint& center, const BPoint& scale) 330 { 331 return ScaleBy(center, scale.x, scale.y); 332 } 333 334 335 BAffineTransform 336 BAffineTransform::ScaleByCopy(double scale) const 337 { 338 return ScaleByCopy(scale, scale); 339 } 340 341 342 BAffineTransform 343 BAffineTransform::ScaleByCopy(const BPoint& center, double scale) const 344 { 345 return ScaleByCopy(center, scale, scale); 346 } 347 348 349 BAffineTransform 350 BAffineTransform::ScaleByCopy(double x, double y) const 351 { 352 BAffineTransform copy(*this); 353 copy.ScaleBy(x, y); 354 return copy; 355 } 356 357 358 BAffineTransform 359 BAffineTransform::ScaleByCopy(const BPoint& center, double x, double y) const 360 { 361 BAffineTransform copy(*this); 362 copy.ScaleBy(center, x, y); 363 return copy; 364 } 365 366 367 BAffineTransform 368 BAffineTransform::ScaleByCopy(const BPoint& scale) const 369 { 370 return ScaleByCopy(scale.x, scale.y); 371 } 372 373 374 BAffineTransform 375 BAffineTransform::ScaleByCopy(const BPoint& center, const BPoint& scale) const 376 { 377 return ScaleByCopy(center, scale.x, scale.y); 378 } 379 380 381 const BAffineTransform& 382 BAffineTransform::SetScale(double scale) 383 { 384 return SetScale(scale, scale); 385 } 386 387 388 const BAffineTransform& 389 BAffineTransform::SetScale(double x, double y) 390 { 391 double tx; 392 double ty; 393 double rotation; 394 double shearX; 395 double shearY; 396 if (!GetAffineParameters(&tx, &ty, &rotation, NULL, NULL, 397 &shearX, &shearY)) { 398 return *this; 399 } 400 401 BAffineTransform result; 402 result.ShearBy(shearX, shearY); 403 result.ScaleBy(x, y); 404 result.RotateBy(rotation); 405 result.TranslateBy(tx, ty); 406 407 return *this = result; 408 } 409 410 411 // #pragma mark - 412 413 414 const BAffineTransform& 415 BAffineTransform::ShearBy(const BPoint& center, double x, double y) 416 { 417 TranslateBy(-center.x, -center.y); 418 ShearBy(x, y); 419 return TranslateBy(center.x, center.y); 420 } 421 422 423 const BAffineTransform& 424 BAffineTransform::ShearBy(const BPoint& shear) 425 { 426 return ShearBy(shear.x, shear.y); 427 } 428 429 430 const BAffineTransform& 431 BAffineTransform::ShearBy(const BPoint& center, const BPoint& shear) 432 { 433 return ShearBy(center, shear.x, shear.y); 434 } 435 436 437 BAffineTransform 438 BAffineTransform::ShearByCopy(double x, double y) const 439 { 440 BAffineTransform copy(*this); 441 copy.ShearBy(x, y); 442 return copy; 443 } 444 445 446 BAffineTransform 447 BAffineTransform::ShearByCopy(const BPoint& center, double x, double y) const 448 { 449 BAffineTransform copy(*this); 450 copy.ShearBy(center, x, y); 451 return copy; 452 } 453 454 455 BAffineTransform 456 BAffineTransform::ShearByCopy(const BPoint& shear) const 457 { 458 BAffineTransform copy(*this); 459 copy.ShearBy(shear); 460 return copy; 461 } 462 463 464 BAffineTransform 465 BAffineTransform::ShearByCopy(const BPoint& center, const BPoint& shear) const 466 { 467 BAffineTransform copy(*this); 468 copy.ShearBy(center, shear); 469 return copy; 470 } 471 472 473 // #pragma mark - 474 475 476 const BAffineTransform& 477 BAffineTransform::PreMultiply(const BAffineTransform& other) 478 { 479 double t0 = sx * other.sx + shy * other.shx; 480 double t2 = shx * other.sx + sy * other.shx; 481 double t4 = tx * other.sx + ty * other.shx + other.tx; 482 shy = sx * other.shy + shy * other.sy; 483 sy = shx * other.shy + sy * other.sy; 484 ty = tx * other.shy + ty * other.sy + other.ty; 485 sx = t0; 486 shx = t2; 487 tx = t4; 488 return *this; 489 } 490 491 492 bool 493 BAffineTransform::IsValid(double epsilon) const 494 { 495 return fabs(sx) > epsilon && fabs(sy) > epsilon; 496 } 497 498 499 static inline bool 500 IsEqualEpsilon(double v1, double v2, double epsilon) 501 { 502 return fabs(v1 - v2) <= double(epsilon); 503 } 504 505 506 bool 507 BAffineTransform::IsIdentity(double epsilon) const 508 { 509 return IsEqualEpsilon(sx, 1.0, epsilon) 510 && IsEqualEpsilon(shy, 0.0, epsilon) 511 && IsEqualEpsilon(shx, 0.0, epsilon) 512 && IsEqualEpsilon(sy, 1.0, epsilon) 513 && IsEqualEpsilon(tx, 0.0, epsilon) 514 && IsEqualEpsilon(ty, 0.0, epsilon); 515 } 516 517 518 bool 519 BAffineTransform::IsDilation(double epsilon) const 520 { 521 return IsEqualEpsilon(shy, 0.0, epsilon) 522 && IsEqualEpsilon(shx, 0.0, epsilon); 523 } 524 525 526 bool 527 BAffineTransform::IsEqual(const BAffineTransform& other, double epsilon) const 528 { 529 return IsEqualEpsilon(sx, other.sx, epsilon) 530 && IsEqualEpsilon(shy, other.shy, epsilon) 531 && IsEqualEpsilon(shx, other.shx, epsilon) 532 && IsEqualEpsilon(sy, other.sy, epsilon) 533 && IsEqualEpsilon(tx, other.tx, epsilon) 534 && IsEqualEpsilon(ty, other.ty, epsilon); 535 } 536 537 538 const BAffineTransform& 539 BAffineTransform::Invert() 540 { 541 double d = InverseDeterminant(); 542 543 double t0 = sy * d; 544 sy = sx * d; 545 shy = -shy * d; 546 shx = -shx * d; 547 548 double t4 = -tx * t0 - ty * shx; 549 ty = -tx * shy - ty * sy; 550 551 sx = t0; 552 tx = t4; 553 554 return *this; 555 } 556 557 558 const BAffineTransform& 559 BAffineTransform::FlipX() 560 { 561 sx = -sx; 562 shy = -shy; 563 tx = -tx; 564 return *this; 565 } 566 567 568 const BAffineTransform& 569 BAffineTransform::FlipY() 570 { 571 shx = -shx; 572 sy = -sy; 573 ty = -ty; 574 return *this; 575 } 576 577 578 const BAffineTransform& 579 BAffineTransform::Reset() 580 { 581 sx = sy = 1.0; 582 shy = shx = tx = ty = 0.0; 583 return *this; 584 } 585 586 587 void 588 BAffineTransform::GetTranslation(double* _tx, double* _ty) const 589 { 590 if (_tx) 591 *_tx = tx; 592 if (_ty) 593 *_ty = ty; 594 } 595 596 597 double 598 BAffineTransform::Rotation() const 599 { 600 double x1 = 0.0; 601 double y1 = 0.0; 602 double x2 = 1.0; 603 double y2 = 0.0; 604 Apply(&x1, &y1); 605 Apply(&x2, &y2); 606 return atan2(y2 - y1, x2 - x1); 607 } 608 609 610 double 611 BAffineTransform::Scale() const 612 { 613 double x = 0.707106781 * sx + 0.707106781 * shx; 614 double y = 0.707106781 * shy + 0.707106781 * sy; 615 return sqrt(x * x + y * y); 616 } 617 618 619 void 620 BAffineTransform::GetScale(double* _sx, double* _sy) const 621 { 622 double x1 = 0.0; 623 double y1 = 0.0; 624 double x2 = 1.0; 625 double y2 = 1.0; 626 BAffineTransform t(*this); 627 t.PreMultiply(AffineRotation(-Rotation())); 628 t.Apply(&x1, &y1); 629 t.Apply(&x2, &y2); 630 if (_sx) 631 *_sx = x2 - x1; 632 if (_sy) 633 *_sy = y2 - y1; 634 } 635 636 637 void 638 BAffineTransform::GetScaleAbs(double* _sx, double* _sy) const 639 { 640 // When there is considerable shear this method gives us much 641 // better estimation than just sx, sy. 642 if (_sx) 643 *_sx = sqrt(sx * sx + shx * shx); 644 if (_sy) 645 *_sy = sqrt(shy * shy + sy * sy); 646 } 647 648 649 bool 650 BAffineTransform::GetAffineParameters(double* _translationX, 651 double* _translationY, double* _rotation, double* _scaleX, double* _scaleY, 652 double* _shearX, double* _shearY) const 653 { 654 GetTranslation(_translationX, _translationY); 655 656 double rotation = Rotation(); 657 if (_rotation != NULL) 658 *_rotation = rotation; 659 660 // Calculate shear 661 double x1 = 0.0; 662 double y1 = 0.0; 663 double x2 = 1.0; 664 double y2 = 0.0; 665 double x3 = 0.0; 666 double y3 = 1.0; 667 668 // Reverse the effects of any rotation 669 BAffineTransform t(*this); 670 t.PreMultiply(AffineRotation(-rotation)); 671 672 t.Apply(&x1, &y1); 673 t.Apply(&x2, &y2); 674 t.Apply(&x3, &y3); 675 676 double shearX = y2 - y1; 677 double shearY = x3 - x1; 678 679 // Calculate scale 680 x1 = 0.0; 681 y1 = 0.0; 682 x2 = 1.0; 683 y2 = 0.0; 684 x3 = 0.0; 685 y3 = 1.0; 686 687 // Reverse the effects of any shear 688 t.PreMultiplyInverse(AffineShearing(shearX, shearY)); 689 690 t.Apply(&x1, &y1); 691 t.Apply(&x2, &y2); 692 t.Apply(&x3, &y3); 693 694 double scaleX = x2 - x1; 695 double scaleY = y3 - y1; 696 697 if (_scaleX != NULL) 698 *_scaleX = scaleX; 699 if (_scaleY != NULL) 700 *_scaleY = scaleY; 701 702 // Since scale was calculated last, the shear values are still scaled. 703 // We cannot get the affine parameters from a matrix with 0 scale. 704 if (scaleX == 0.0 && scaleY == 0.0) 705 return false; 706 707 if (_shearX != NULL) 708 *_shearX = shearX / scaleX; 709 if (_shearY != NULL) 710 *_shearY = shearY / scaleY; 711 712 return true; 713 } 714 715