HaikuDepot: notify work status from main window
[haiku.git] / src / kits / interface / AffineTransform.cpp
blob149435dda11e9f0038b9c577d2475871137d073d
1 /*
2 * Copyright 2008-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
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)
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.
18 //----------------------------------------------------------------------------
19 // Contact: mcseem@antigrain.com
20 // mcseemagg@yahoo.com
21 // http://www.antigrain.com
22 //----------------------------------------------------------------------------
24 #include <AffineTransform.h>
26 #include <TypeConstants.h>
29 const BAffineTransform B_AFFINE_IDENTITY_TRANSFORM;
32 BAffineTransform::BAffineTransform()
34 sx(1.0),
35 shy(0.0),
36 shx(0.0),
37 sy(1.0),
38 tx(0.0),
39 ty(0.0)
44 BAffineTransform::BAffineTransform(double sx, double shy, double shx,
45 double sy, double tx, double ty)
47 sx(sx),
48 shy(shy),
49 shx(shx),
50 sy(sy),
51 tx(tx),
52 ty(ty)
57 BAffineTransform::BAffineTransform(const BAffineTransform& other)
59 sx(other.sx),
60 shy(other.shy),
61 shx(other.shx),
62 sy(other.sy),
63 tx(other.tx),
64 ty(other.ty)
69 BAffineTransform::~BAffineTransform()
74 // #pragma mark -
77 bool
78 BAffineTransform::IsFixedSize() const
80 return true;
84 type_code
85 BAffineTransform::TypeCode() const
87 return B_AFFINE_TRANSFORM_TYPE;
91 ssize_t
92 BAffineTransform::FlattenedSize() const
94 return 6 * sizeof(double);
98 status_t
99 BAffineTransform::Flatten(void* _buffer, ssize_t size) const
101 if (_buffer == NULL || size < FlattenedSize())
102 return B_BAD_VALUE;
104 double* buffer = reinterpret_cast<double*>(_buffer);
106 buffer[0] = sx;
107 buffer[1] = shy;
108 buffer[2] = shx;
109 buffer[3] = sy;
110 buffer[4] = tx;
111 buffer[5] = ty;
113 return B_OK;
117 status_t
118 BAffineTransform::Unflatten(type_code code, const void* _buffer, ssize_t size)
120 if (_buffer == NULL || size < FlattenedSize() || code != TypeCode())
121 return B_BAD_VALUE;
123 const double* buffer = reinterpret_cast<const double*>(_buffer);
125 sx = buffer[0];
126 shy = buffer[1];
127 shx = buffer[2];
128 sy = buffer[3];
129 tx = buffer[4];
130 ty = buffer[5];
132 return B_OK;
136 // #pragma mark -
139 /*static*/ BAffineTransform
140 BAffineTransform::AffineTranslation(double x, double y)
142 return BAffineTransform(1.0, 0.0, 0.0, 1.0, x, y);
146 /*static*/ BAffineTransform
147 BAffineTransform::AffineRotation(double angle)
149 return BAffineTransform(cos(angle), sin(angle), -sin(angle), cos(angle),
150 0.0, 0.0);
154 /*static*/ BAffineTransform
155 BAffineTransform::AffineScaling(double x, double y)
157 return BAffineTransform(x, 0.0, 0.0, y, 0.0, 0.0);
161 /*static*/ BAffineTransform
162 BAffineTransform::AffineScaling(double scale)
164 return BAffineTransform(scale, 0.0, 0.0, scale, 0.0, 0.0);
168 /*static*/ BAffineTransform
169 BAffineTransform::AffineShearing(double x, double y)
171 return BAffineTransform(1.0, tan(y), tan(x), 1.0, 0.0, 0.0);
175 // #pragma mark -
178 BPoint
179 BAffineTransform::Apply(const BPoint& point) const
181 double x = point.x;
182 double y = point.y;
183 Apply(&x, &y);
184 return BPoint(x, y);
188 BPoint
189 BAffineTransform::ApplyInverse(const BPoint& point) const
191 double x = point.x;
192 double y = point.y;
193 ApplyInverse(&x, &y);
194 return BPoint(x, y);
198 void
199 BAffineTransform::Apply(BPoint* point) const
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;
211 void
212 BAffineTransform::ApplyInverse(BPoint* point) const
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;
224 void
225 BAffineTransform::Apply(BPoint* points, uint32 count) const
227 if (points != NULL) {
228 for (uint32 i = 0; i < count; ++i)
229 Apply(&points[i]);
234 void
235 BAffineTransform::ApplyInverse(BPoint* points, uint32 count) const
237 if (points != NULL) {
238 for (uint32 i = 0; i < count; ++i)
239 ApplyInverse(&points[i]);
244 // #pragma mark -
247 const BAffineTransform&
248 BAffineTransform::TranslateBy(const BPoint& delta)
250 return TranslateBy(delta.x, delta.y);
254 BAffineTransform
255 BAffineTransform::TranslateByCopy(double x, double y) const
257 BAffineTransform copy(*this);
258 copy.TranslateBy(x, y);
259 return copy;
263 BAffineTransform
264 BAffineTransform::TranslateByCopy(const BPoint& delta) const
266 return TranslateByCopy(delta.x, delta.y);
270 // #pragma mark -
273 const BAffineTransform&
274 BAffineTransform::RotateBy(const BPoint& center, double angle)
276 TranslateBy(-center.x, -center.y);
277 RotateBy(angle);
278 return TranslateBy(center.x, center.y);
282 BAffineTransform
283 BAffineTransform::RotateByCopy(double angle) const
285 BAffineTransform copy(*this);
286 copy.RotateBy(angle);
287 return copy;
291 BAffineTransform
292 BAffineTransform::RotateByCopy(const BPoint& center, double angle) const
294 BAffineTransform copy(*this);
295 copy.RotateBy(center, angle);
296 return copy;
300 // #pragma mark -
303 const BAffineTransform&
304 BAffineTransform::ScaleBy(const BPoint& center, double scale)
306 return ScaleBy(center, scale, scale);
310 const BAffineTransform&
311 BAffineTransform::ScaleBy(const BPoint& center, double x, double y)
313 TranslateBy(-center.x, -center.y);
314 ScaleBy(x, y);
315 return TranslateBy(center.x, center.y);
319 const BAffineTransform&
320 BAffineTransform::ScaleBy(const BPoint& scale)
322 return ScaleBy(scale.x, scale.y);
326 const BAffineTransform&
327 BAffineTransform::ScaleBy(const BPoint& center, const BPoint& scale)
329 return ScaleBy(center, scale.x, scale.y);
333 BAffineTransform
334 BAffineTransform::ScaleByCopy(double scale) const
336 return ScaleByCopy(scale, scale);
340 BAffineTransform
341 BAffineTransform::ScaleByCopy(const BPoint& center, double scale) const
343 return ScaleByCopy(center, scale, scale);
347 BAffineTransform
348 BAffineTransform::ScaleByCopy(double x, double y) const
350 BAffineTransform copy(*this);
351 copy.ScaleBy(x, y);
352 return copy;
356 BAffineTransform
357 BAffineTransform::ScaleByCopy(const BPoint& center, double x, double y) const
359 BAffineTransform copy(*this);
360 copy.ScaleBy(center, x, y);
361 return copy;
365 BAffineTransform
366 BAffineTransform::ScaleByCopy(const BPoint& scale) const
368 return ScaleByCopy(scale.x, scale.y);
372 BAffineTransform
373 BAffineTransform::ScaleByCopy(const BPoint& center, const BPoint& scale) const
375 return ScaleByCopy(center, scale.x, scale.y);
379 const BAffineTransform&
380 BAffineTransform::SetScale(double scale)
382 return SetScale(scale, scale);
386 const BAffineTransform&
387 BAffineTransform::SetScale(double x, double y)
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;
399 BAffineTransform result;
400 result.ShearBy(shearX, shearY);
401 result.ScaleBy(x, y);
402 result.RotateBy(rotation);
403 result.TranslateBy(tx, ty);
405 return *this = result;
409 // #pragma mark -
412 const BAffineTransform&
413 BAffineTransform::ShearBy(const BPoint& center, double x, double y)
415 TranslateBy(-center.x, -center.y);
416 ShearBy(x, y);
417 return TranslateBy(center.x, center.y);
421 const BAffineTransform&
422 BAffineTransform::ShearBy(const BPoint& shear)
424 return ShearBy(shear.x, shear.y);
428 const BAffineTransform&
429 BAffineTransform::ShearBy(const BPoint& center, const BPoint& shear)
431 return ShearBy(center, shear.x, shear.y);
435 BAffineTransform
436 BAffineTransform::ShearByCopy(double x, double y) const
438 BAffineTransform copy(*this);
439 copy.ShearBy(x, y);
440 return copy;
444 BAffineTransform
445 BAffineTransform::ShearByCopy(const BPoint& center, double x, double y) const
447 BAffineTransform copy(*this);
448 copy.ShearBy(center, x, y);
449 return copy;
453 BAffineTransform
454 BAffineTransform::ShearByCopy(const BPoint& shear) const
456 BAffineTransform copy(*this);
457 copy.ShearBy(shear);
458 return copy;
462 BAffineTransform
463 BAffineTransform::ShearByCopy(const BPoint& center, const BPoint& shear) const
465 BAffineTransform copy(*this);
466 copy.ShearBy(center, shear);
467 return copy;
471 // #pragma mark -
474 const BAffineTransform&
475 BAffineTransform::PreMultiply(const BAffineTransform& other)
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;
490 bool
491 BAffineTransform::IsValid(double epsilon) const
493 return fabs(sx) > epsilon && fabs(sy) > epsilon;
497 static inline bool
498 IsEqualEpsilon(double v1, double v2, double epsilon)
500 return fabs(v1 - v2) <= double(epsilon);
504 bool
505 BAffineTransform::IsIdentity(double epsilon) const
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);
516 bool
517 BAffineTransform::IsDilation(double epsilon) const
519 return IsEqualEpsilon(shy, 0.0, epsilon)
520 && IsEqualEpsilon(shx, 0.0, epsilon);
524 bool
525 BAffineTransform::IsEqual(const BAffineTransform& other, double epsilon) const
527 return IsEqualEpsilon(sx, other.sx, epsilon)
528 && IsEqualEpsilon(shy, other.shy, epsilon)
529 && IsEqualEpsilon(shx, other.shx, epsilon)
530 && IsEqualEpsilon(sy, other.sy, epsilon)
531 && IsEqualEpsilon(tx, other.tx, epsilon)
532 && IsEqualEpsilon(ty, other.ty, epsilon);
536 const BAffineTransform&
537 BAffineTransform::Invert()
539 double d = InverseDeterminant();
541 double t0 = sy * d;
542 sy = sx * d;
543 shy = -shy * d;
544 shx = -shx * d;
546 double t4 = -tx * t0 - ty * shx;
547 ty = -tx * shy - ty * sy;
549 sx = t0;
550 tx = t4;
552 return *this;
556 const BAffineTransform&
557 BAffineTransform::FlipX()
559 sx = -sx;
560 shy = -shy;
561 tx = -tx;
562 return *this;
566 const BAffineTransform&
567 BAffineTransform::FlipY()
569 shx = -shx;
570 sy = -sy;
571 ty = -ty;
572 return *this;
576 const BAffineTransform&
577 BAffineTransform::Reset()
579 sx = sy = 1.0;
580 shy = shx = tx = ty = 0.0;
581 return *this;
585 void
586 BAffineTransform::GetTranslation(double* _tx, double* _ty) const
588 if (_tx)
589 *_tx = tx;
590 if (_ty)
591 *_ty = ty;
595 double
596 BAffineTransform::Rotation() const
598 double x1 = 0.0;
599 double y1 = 0.0;
600 double x2 = 1.0;
601 double y2 = 0.0;
602 Apply(&x1, &y1);
603 Apply(&x2, &y2);
604 return atan2(y2 - y1, x2 - x1);
608 double
609 BAffineTransform::Scale() const
611 double x = 0.707106781 * sx + 0.707106781 * shx;
612 double y = 0.707106781 * shy + 0.707106781 * sy;
613 return sqrt(x * x + y * y);
617 void
618 BAffineTransform::GetScale(double* _sx, double* _sy) const
620 double x1 = 0.0;
621 double y1 = 0.0;
622 double x2 = 1.0;
623 double y2 = 1.0;
624 BAffineTransform t(*this);
625 t.PreMultiply(AffineRotation(-Rotation()));
626 t.Apply(&x1, &y1);
627 t.Apply(&x2, &y2);
628 if (_sx)
629 *_sx = x2 - x1;
630 if (_sy)
631 *_sy = y2 - y1;
635 void
636 BAffineTransform::GetScaleAbs(double* _sx, double* _sy) const
638 // When there is considerable shear this method gives us much
639 // better estimation than just sx, sy.
640 if (_sx)
641 *_sx = sqrt(sx * sx + shx * shx);
642 if (_sy)
643 *_sy = sqrt(shy * shy + sy * sy);
647 bool
648 BAffineTransform::GetAffineParameters(double* _translationX,
649 double* _translationY, double* _rotation, double* _scaleX, double* _scaleY,
650 double* _shearX, double* _shearY) const
652 GetTranslation(_translationX, _translationY);
654 double rotation = Rotation();
655 if (_rotation != NULL)
656 *_rotation = rotation;
658 // Calculate shear
659 double x1 = 0.0;
660 double y1 = 0.0;
661 double x2 = 1.0;
662 double y2 = 0.0;
663 double x3 = 0.0;
664 double y3 = 1.0;
666 // Reverse the effects of any rotation
667 BAffineTransform t(*this);
668 t.PreMultiply(AffineRotation(-rotation));
670 t.Apply(&x1, &y1);
671 t.Apply(&x2, &y2);
672 t.Apply(&x3, &y3);
674 double shearX = y2 - y1;
675 double shearY = x3 - x1;
677 // Calculate scale
678 x1 = 0.0;
679 y1 = 0.0;
680 x2 = 1.0;
681 y2 = 0.0;
682 x3 = 0.0;
683 y3 = 1.0;
685 // Reverse the effects of any shear
686 t.PreMultiplyInverse(AffineShearing(shearX, shearY));
688 t.Apply(&x1, &y1);
689 t.Apply(&x2, &y2);
690 t.Apply(&x3, &y3);
692 double scaleX = x2 - x1;
693 double scaleY = y3 - y1;
695 if (_scaleX != NULL)
696 *_scaleX = scaleX;
697 if (_scaleY != NULL)
698 *_scaleY = scaleY;
700 // Since scale was calculated last, the shear values are still scaled.
701 // We cannot get the affine parameters from a matrix with 0 scale.
702 if (scaleX == 0.0 && scaleY == 0.0)
703 return false;
705 if (_shearX != NULL)
706 *_shearX = shearX / scaleX;
707 if (_shearY != NULL)
708 *_shearY = shearY / scaleY;
710 return true;