2 * Copyright 2008-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Stephen Deken, stephen.deken@gmail.com
7 * Stephan Aßmus <superstippi@gmx.de>
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()
44 BAffineTransform::BAffineTransform(double sx
, double shy
, double shx
,
45 double sy
, double tx
, double ty
)
57 BAffineTransform::BAffineTransform(const BAffineTransform
& other
)
69 BAffineTransform::~BAffineTransform()
78 BAffineTransform::IsFixedSize() const
85 BAffineTransform::TypeCode() const
87 return B_AFFINE_TRANSFORM_TYPE
;
92 BAffineTransform::FlattenedSize() const
94 return 6 * sizeof(double);
99 BAffineTransform::Flatten(void* _buffer
, ssize_t size
) const
101 if (_buffer
== NULL
|| size
< FlattenedSize())
104 double* buffer
= reinterpret_cast<double*>(_buffer
);
118 BAffineTransform::Unflatten(type_code code
, const void* _buffer
, ssize_t size
)
120 if (_buffer
== NULL
|| size
< FlattenedSize() || code
!= TypeCode())
123 const double* buffer
= reinterpret_cast<const double*>(_buffer
);
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
),
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);
179 BAffineTransform::Apply(const BPoint
& point
) const
189 BAffineTransform::ApplyInverse(const BPoint
& point
) const
193 ApplyInverse(&x
, &y
);
199 BAffineTransform::Apply(BPoint
* point
) const
212 BAffineTransform::ApplyInverse(BPoint
* point
) const
218 ApplyInverse(&x
, &y
);
225 BAffineTransform::Apply(BPoint
* points
, uint32 count
) const
227 if (points
!= NULL
) {
228 for (uint32 i
= 0; i
< count
; ++i
)
235 BAffineTransform::ApplyInverse(BPoint
* points
, uint32 count
) const
237 if (points
!= NULL
) {
238 for (uint32 i
= 0; i
< count
; ++i
)
239 ApplyInverse(&points
[i
]);
247 const BAffineTransform
&
248 BAffineTransform::TranslateBy(const BPoint
& delta
)
250 return TranslateBy(delta
.x
, delta
.y
);
255 BAffineTransform::TranslateByCopy(double x
, double y
) const
257 BAffineTransform
copy(*this);
258 copy
.TranslateBy(x
, y
);
264 BAffineTransform::TranslateByCopy(const BPoint
& delta
) const
266 return TranslateByCopy(delta
.x
, delta
.y
);
273 const BAffineTransform
&
274 BAffineTransform::RotateBy(const BPoint
& center
, double angle
)
276 TranslateBy(-center
.x
, -center
.y
);
278 return TranslateBy(center
.x
, center
.y
);
283 BAffineTransform::RotateByCopy(double angle
) const
285 BAffineTransform
copy(*this);
286 copy
.RotateBy(angle
);
292 BAffineTransform::RotateByCopy(const BPoint
& center
, double angle
) const
294 BAffineTransform
copy(*this);
295 copy
.RotateBy(center
, angle
);
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
);
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
);
334 BAffineTransform::ScaleByCopy(double scale
) const
336 return ScaleByCopy(scale
, scale
);
341 BAffineTransform::ScaleByCopy(const BPoint
& center
, double scale
) const
343 return ScaleByCopy(center
, scale
, scale
);
348 BAffineTransform::ScaleByCopy(double x
, double y
) const
350 BAffineTransform
copy(*this);
357 BAffineTransform::ScaleByCopy(const BPoint
& center
, double x
, double y
) const
359 BAffineTransform
copy(*this);
360 copy
.ScaleBy(center
, x
, y
);
366 BAffineTransform::ScaleByCopy(const BPoint
& scale
) const
368 return ScaleByCopy(scale
.x
, scale
.y
);
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
)
394 if (!GetAffineParameters(&tx
, &ty
, &rotation
, NULL
, NULL
,
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
;
412 const BAffineTransform
&
413 BAffineTransform::ShearBy(const BPoint
& center
, double x
, double y
)
415 TranslateBy(-center
.x
, -center
.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
);
436 BAffineTransform::ShearByCopy(double x
, double y
) const
438 BAffineTransform
copy(*this);
445 BAffineTransform::ShearByCopy(const BPoint
& center
, double x
, double y
) const
447 BAffineTransform
copy(*this);
448 copy
.ShearBy(center
, x
, y
);
454 BAffineTransform::ShearByCopy(const BPoint
& shear
) const
456 BAffineTransform
copy(*this);
463 BAffineTransform::ShearByCopy(const BPoint
& center
, const BPoint
& shear
) const
465 BAffineTransform
copy(*this);
466 copy
.ShearBy(center
, shear
);
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
;
491 BAffineTransform::IsValid(double epsilon
) const
493 return fabs(sx
) > epsilon
&& fabs(sy
) > epsilon
;
498 IsEqualEpsilon(double v1
, double v2
, double epsilon
)
500 return fabs(v1
- v2
) <= double(epsilon
);
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
);
517 BAffineTransform::IsEqual(const BAffineTransform
& other
, double epsilon
) const
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
);
528 const BAffineTransform
&
529 BAffineTransform::Invert()
531 double d
= InverseDeterminant();
538 double t4
= -tx
* t0
- ty
* shx
;
539 ty
= -tx
* shy
- ty
* sy
;
548 const BAffineTransform
&
549 BAffineTransform::FlipX()
558 const BAffineTransform
&
559 BAffineTransform::FlipY()
568 const BAffineTransform
&
569 BAffineTransform::Reset()
572 shy
= shx
= tx
= ty
= 0.0;
578 BAffineTransform::GetTranslation(double* _tx
, double* _ty
) const
588 BAffineTransform::Rotation() const
596 return atan2(y2
- y1
, x2
- x1
);
601 BAffineTransform::Scale() const
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
);
610 BAffineTransform::GetScale(double* _sx
, double* _sy
) const
616 BAffineTransform
t(*this);
617 t
.PreMultiply(AffineRotation(-Rotation()));
628 BAffineTransform::GetScaleAbs(double* _sx
, double* _sy
) const
630 // When there is considerable shear this method gives us much
631 // better estimation than just sx, sy.
633 *_sx
= sqrt(sx
* sx
+ shx
* shx
);
635 *_sy
= sqrt(shy
* shy
+ sy
* sy
);
640 BAffineTransform::GetAffineParameters(double* _translationX
,
641 double* _translationY
, double* _rotation
, double* _scaleX
, double* _scaleY
,
642 double* _shearX
, double* _shearY
) const
644 GetTranslation(_translationX
, _translationY
);
646 double rotation
= Rotation();
647 if (_rotation
!= NULL
)
648 *_rotation
= rotation
;
658 // Reverse the effects of any rotation
659 BAffineTransform
t(*this);
660 t
.PreMultiply(AffineRotation(-rotation
));
666 double shearX
= y2
- y1
;
667 double shearY
= x3
- x1
;
677 // Reverse the effects of any shear
678 t
.PreMultiplyInverse(AffineShearing(shearX
, shearY
));
684 double scaleX
= x2
- x1
;
685 double scaleY
= y3
- y1
;
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)
698 *_shearX
= shearX
/ scaleX
;
700 *_shearY
= shearY
/ scaleY
;