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 < 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 < FlattenedSize() || code != TypeCode()) 121 return B_BAD_VALUE; 122 123 const double* buffer = reinterpret_cast<const double*>(_buffer); 124 125 sx = buffer[0]; 126 shy = buffer[1]; 127 shx = buffer[2]; 128 sy = buffer[3]; 129 tx = buffer[4]; 130 ty = buffer[5]; 131 132 return B_OK; 133 } 134 135 136 // #pragma mark - 137 138 139 /*static*/ BAffineTransform 140 BAffineTransform::AffineTranslation(double x, double y) 141 { 142 return BAffineTransform(1.0, 0.0, 0.0, 1.0, x, y); 143 } 144 145 146 /*static*/ BAffineTransform 147 BAffineTransform::AffineRotation(double angle) 148 { 149 return BAffineTransform(cos(angle), sin(angle), -sin(angle), cos(angle), 150 0.0, 0.0); 151 } 152 153 154 /*static*/ BAffineTransform 155 BAffineTransform::AffineScaling(double x, double y) 156 { 157 return BAffineTransform(x, 0.0, 0.0, y, 0.0, 0.0); 158 } 159 160 161 /*static*/ BAffineTransform 162 BAffineTransform::AffineScaling(double scale) 163 { 164 return BAffineTransform(scale, 0.0, 0.0, scale, 0.0, 0.0); 165 } 166 167 168 /*static*/ BAffineTransform 169 BAffineTransform::AffineShearing(double x, double y) 170 { 171 return BAffineTransform(1.0, tan(y), tan(x), 1.0, 0.0, 0.0); 172 } 173 174 175 // #pragma mark - 176 177 178 BPoint 179 BAffineTransform::Apply(const BPoint& point) const 180 { 181 double x = point.x; 182 double y = point.y; 183 Apply(&x, &y); 184 return BPoint(x, y); 185 } 186 187 188 BPoint 189 BAffineTransform::ApplyInverse(const BPoint& point) const 190 { 191 double x = point.x; 192 double y = point.y; 193 ApplyInverse(&x, &y); 194 return BPoint(x, y); 195 } 196 197 198 void 199 BAffineTransform::Apply(BPoint* point) const 200 { 201 if (point == NULL) 202 return; 203 double x = point->x; 204 double y = point->y; 205 Apply(&x, &y); 206 point->x = x; 207 point->y = y; 208 } 209 210 211 void 212 BAffineTransform::ApplyInverse(BPoint* point) const 213 { 214 if (point == NULL) 215 return; 216 double x = point->x; 217 double y = point->y; 218 ApplyInverse(&x, &y); 219 point->x = x; 220 point->y = y; 221 } 222 223 224 void 225 BAffineTransform::Apply(BPoint* points, uint32 count) const 226 { 227 if (points != NULL) { 228 for (uint32 i = 0; i < count; ++i) 229 Apply(&points[i]); 230 } 231 } 232 233 234 void 235 BAffineTransform::ApplyInverse(BPoint* points, uint32 count) const 236 { 237 if (points != NULL) { 238 for (uint32 i = 0; i < count; ++i) 239 ApplyInverse(&points[i]); 240 } 241 } 242 243 244 // #pragma mark - 245 246 247 const BAffineTransform& 248 BAffineTransform::TranslateBy(const BPoint& delta) 249 { 250 return TranslateBy(delta.x, delta.y); 251 } 252 253 254 BAffineTransform 255 BAffineTransform::TranslateByCopy(double x, double y) const 256 { 257 BAffineTransform copy(*this); 258 copy.TranslateBy(x, y); 259 return copy; 260 } 261 262 263 BAffineTransform 264 BAffineTransform::TranslateByCopy(const BPoint& delta) const 265 { 266 return TranslateByCopy(delta.x, delta.y); 267 } 268 269 270 // #pragma mark - 271 272 273 const BAffineTransform& 274 BAffineTransform::RotateBy(const BPoint& center, double angle) 275 { 276 TranslateBy(-center.x, -center.y); 277 RotateBy(angle); 278 return TranslateBy(center.x, center.y); 279 } 280 281 282 BAffineTransform 283 BAffineTransform::RotateByCopy(double angle) const 284 { 285 BAffineTransform copy(*this); 286 copy.RotateBy(angle); 287 return copy; 288 } 289 290 291 BAffineTransform 292 BAffineTransform::RotateByCopy(const BPoint& center, double angle) const 293 { 294 BAffineTransform copy(*this); 295 copy.RotateBy(center, angle); 296 return copy; 297 } 298 299 300 // #pragma mark - 301 302 303 const BAffineTransform& 304 BAffineTransform::ScaleBy(const BPoint& center, double scale) 305 { 306 return ScaleBy(center, scale, scale); 307 } 308 309 310 const BAffineTransform& 311 BAffineTransform::ScaleBy(const BPoint& center, double x, double y) 312 { 313 TranslateBy(-center.x, -center.y); 314 ScaleBy(x, y); 315 return TranslateBy(center.x, center.y); 316 } 317 318 319 const BAffineTransform& 320 BAffineTransform::ScaleBy(const BPoint& scale) 321 { 322 return ScaleBy(scale.x, scale.y); 323 } 324 325 326 const BAffineTransform& 327 BAffineTransform::ScaleBy(const BPoint& center, const BPoint& scale) 328 { 329 return ScaleBy(center, scale.x, scale.y); 330 } 331 332 333 BAffineTransform 334 BAffineTransform::ScaleByCopy(double scale) const 335 { 336 return ScaleByCopy(scale, scale); 337 } 338 339 340 BAffineTransform 341 BAffineTransform::ScaleByCopy(const BPoint& center, double scale) const 342 { 343 return ScaleByCopy(center, scale, scale); 344 } 345 346 347 BAffineTransform 348 BAffineTransform::ScaleByCopy(double x, double y) const 349 { 350 BAffineTransform copy(*this); 351 copy.ScaleBy(x, y); 352 return copy; 353 } 354 355 356 BAffineTransform 357 BAffineTransform::ScaleByCopy(const BPoint& center, double x, double y) const 358 { 359 BAffineTransform copy(*this); 360 copy.ScaleBy(center, x, y); 361 return copy; 362 } 363 364 365 BAffineTransform 366 BAffineTransform::ScaleByCopy(const BPoint& scale) const 367 { 368 return ScaleByCopy(scale.x, scale.y); 369 } 370 371 372 BAffineTransform 373 BAffineTransform::ScaleByCopy(const BPoint& center, const BPoint& scale) const 374 { 375 return ScaleByCopy(center, scale.x, scale.y); 376 } 377 378 379 const BAffineTransform& 380 BAffineTransform::SetScale(double scale) 381 { 382 return SetScale(scale, scale); 383 } 384 385 386 const BAffineTransform& 387 BAffineTransform::SetScale(double x, double y) 388 { 389 double tx; 390 double ty; 391 double rotation; 392 double shearX; 393 double shearY; 394 if (!GetAffineParameters(&tx, &ty, &rotation, NULL, NULL, 395 &shearX, &shearY)) { 396 return *this; 397 } 398 399 BAffineTransform result; 400 result.ShearBy(shearX, shearY); 401 result.ScaleBy(x, y); 402 result.RotateBy(rotation); 403 result.TranslateBy(tx, ty); 404 405 return *this = result; 406 } 407 408 409 // #pragma mark - 410 411 412 const BAffineTransform& 413 BAffineTransform::ShearBy(const BPoint& center, double x, double y) 414 { 415 TranslateBy(-center.x, -center.y); 416 ShearBy(x, y); 417 return TranslateBy(center.x, center.y); 418 } 419 420 421 const BAffineTransform& 422 BAffineTransform::ShearBy(const BPoint& shear) 423 { 424 return ShearBy(shear.x, shear.y); 425 } 426 427 428 const BAffineTransform& 429 BAffineTransform::ShearBy(const BPoint& center, const BPoint& shear) 430 { 431 return ShearBy(center, shear.x, shear.y); 432 } 433 434 435 BAffineTransform 436 BAffineTransform::ShearByCopy(double x, double y) const 437 { 438 BAffineTransform copy(*this); 439 copy.ShearBy(x, y); 440 return copy; 441 } 442 443 444 BAffineTransform 445 BAffineTransform::ShearByCopy(const BPoint& center, double x, double y) const 446 { 447 BAffineTransform copy(*this); 448 copy.ShearBy(center, x, y); 449 return copy; 450 } 451 452 453 BAffineTransform 454 BAffineTransform::ShearByCopy(const BPoint& shear) const 455 { 456 BAffineTransform copy(*this); 457 copy.ShearBy(shear); 458 return copy; 459 } 460 461 462 BAffineTransform 463 BAffineTransform::ShearByCopy(const BPoint& center, const BPoint& shear) const 464 { 465 BAffineTransform copy(*this); 466 copy.ShearBy(center, shear); 467 return copy; 468 } 469 470 471 // #pragma mark - 472 473 474 const BAffineTransform& 475 BAffineTransform::PreMultiply(const BAffineTransform& other) 476 { 477 double t0 = sx * other.sx + shy * other.shx; 478 double t2 = shx * other.sx + sy * other.shx; 479 double t4 = tx * other.sx + ty * other.shx + other.tx; 480 shy = sx * other.shy + shy * other.sy; 481 sy = shx * other.shy + sy * other.sy; 482 ty = tx * other.shy + ty * other.sy + other.ty; 483 sx = t0; 484 shx = t2; 485 tx = t4; 486 return *this; 487 } 488 489 490 bool 491 BAffineTransform::IsValid(double epsilon) const 492 { 493 return fabs(sx) > epsilon && fabs(sy) > epsilon; 494 } 495 496 497 static inline bool 498 IsEqualEpsilon(double v1, double v2, double epsilon) 499 { 500 return fabs(v1 - v2) <= double(epsilon); 501 } 502 503 504 bool 505 BAffineTransform::IsIdentity(double epsilon) const 506 { 507 return IsEqualEpsilon(sx, 1.0, epsilon) 508 && IsEqualEpsilon(shy, 0.0, epsilon) 509 && IsEqualEpsilon(shx, 0.0, epsilon) 510 && IsEqualEpsilon(sy, 1.0, epsilon) 511 && IsEqualEpsilon(tx, 0.0, epsilon) 512 && IsEqualEpsilon(ty, 0.0, epsilon); 513 } 514 515 516 bool 517 BAffineTransform::IsEqual(const BAffineTransform& other, double epsilon) const 518 { 519 return IsEqualEpsilon(sx, other.sx, epsilon) 520 && IsEqualEpsilon(shy, other.shy, epsilon) 521 && IsEqualEpsilon(shx, other.shx, epsilon) 522 && IsEqualEpsilon(sy, other.sy, epsilon) 523 && IsEqualEpsilon(tx, other.tx, epsilon) 524 && IsEqualEpsilon(ty, other.ty, epsilon); 525 } 526 527 528 const BAffineTransform& 529 BAffineTransform::Invert() 530 { 531 double d = InverseDeterminant(); 532 533 double t0 = sy * d; 534 sy = sx * d; 535 shy = -shy * d; 536 shx = -shx * d; 537 538 double t4 = -tx * t0 - ty * shx; 539 ty = -tx * shy - ty * sy; 540 541 sx = t0; 542 tx = t4; 543 544 return *this; 545 } 546 547 548 const BAffineTransform& 549 BAffineTransform::FlipX() 550 { 551 sx = -sx; 552 shy = -shy; 553 tx = -tx; 554 return *this; 555 } 556 557 558 const BAffineTransform& 559 BAffineTransform::FlipY() 560 { 561 shx = -shx; 562 sy = -sy; 563 ty = -ty; 564 return *this; 565 } 566 567 568 const BAffineTransform& 569 BAffineTransform::Reset() 570 { 571 sx = sy = 1.0; 572 shy = shx = tx = ty = 0.0; 573 return *this; 574 } 575 576 577 void 578 BAffineTransform::GetTranslation(double* _tx, double* _ty) const 579 { 580 if (_tx) 581 *_tx = tx; 582 if (_ty) 583 *_ty = ty; 584 } 585 586 587 double 588 BAffineTransform::Rotation() const 589 { 590 double x1 = 0.0; 591 double y1 = 0.0; 592 double x2 = 1.0; 593 double y2 = 0.0; 594 Apply(&x1, &y1); 595 Apply(&x2, &y2); 596 return atan2(y2 - y1, x2 - x1); 597 } 598 599 600 double 601 BAffineTransform::Scale() const 602 { 603 double x = 0.707106781 * sx + 0.707106781 * shx; 604 double y = 0.707106781 * shy + 0.707106781 * sy; 605 return sqrt(x * x + y * y); 606 } 607 608 609 void 610 BAffineTransform::GetScale(double* _sx, double* _sy) const 611 { 612 double x1 = 0.0; 613 double y1 = 0.0; 614 double x2 = 1.0; 615 double y2 = 1.0; 616 BAffineTransform t(*this); 617 t.PreMultiply(AffineRotation(-Rotation())); 618 t.Apply(&x1, &y1); 619 t.Apply(&x2, &y2); 620 if (_sx) 621 *_sx = x2 - x1; 622 if (_sy) 623 *_sy = y2 - y1; 624 } 625 626 627 void 628 BAffineTransform::GetScaleAbs(double* _sx, double* _sy) const 629 { 630 // When there is considerable shear this method gives us much 631 // better estimation than just sx, sy. 632 if (_sx) 633 *_sx = sqrt(sx * sx + shx * shx); 634 if (_sy) 635 *_sy = sqrt(shy * shy + sy * sy); 636 } 637 638 639 bool 640 BAffineTransform::GetAffineParameters(double* _translationX, 641 double* _translationY, double* _rotation, double* _scaleX, double* _scaleY, 642 double* _shearX, double* _shearY) const 643 { 644 GetTranslation(_translationX, _translationY); 645 646 double rotation = Rotation(); 647 if (_rotation != NULL) 648 *_rotation = rotation; 649 650 // Calculate shear 651 double x1 = 0.0; 652 double y1 = 0.0; 653 double x2 = 1.0; 654 double y2 = 0.0; 655 double x3 = 0.0; 656 double y3 = 1.0; 657 658 // Reverse the effects of any rotation 659 BAffineTransform t(*this); 660 t.PreMultiply(AffineRotation(-rotation)); 661 662 t.Apply(&x1, &y1); 663 t.Apply(&x2, &y2); 664 t.Apply(&x3, &y3); 665 666 double shearX = y2 - y1; 667 double shearY = x3 - x1; 668 669 // Calculate scale 670 x1 = 0.0; 671 y1 = 0.0; 672 x2 = 1.0; 673 y2 = 0.0; 674 x3 = 0.0; 675 y3 = 1.0; 676 677 // Reverse the effects of any shear 678 t.PreMultiplyInverse(AffineShearing(shearX, shearY)); 679 680 t.Apply(&x1, &y1); 681 t.Apply(&x2, &y2); 682 t.Apply(&x3, &y3); 683 684 double scaleX = x2 - x1; 685 double scaleY = y3 - y1; 686 687 if (_scaleX != NULL) 688 *_scaleX = scaleX; 689 if (_scaleY != NULL) 690 *_scaleY = scaleY; 691 692 // Since scale was calculated last, the shear values are still scaled. 693 // We cannot get the affine parameters from a matrix with 0 scale. 694 if (scaleX == 0.0 && scaleY == 0.0) 695 return false; 696 697 if (_shearX != NULL) 698 *_shearX = shearX / scaleX; 699 if (_shearY != NULL) 700 *_shearY = shearY / scaleY; 701 702 return true; 703 } 704 705