diff --git a/headers/os/interface/AffineTransform.h b/headers/os/interface/AffineTransform.h index cf226f7bad..34861ed6a8 100644 --- a/headers/os/interface/AffineTransform.h +++ b/headers/os/interface/AffineTransform.h @@ -4,126 +4,393 @@ * * Authors: * Stephen Deken, stephen.deken@gmail.com + * Stephan Aßmus */ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- #ifndef _AFFINE_TRANSFORM_H #define _AFFINE_TRANSFORM_H -#include -#include +#include +#include -class BPoint; +#include -namespace BPrivate { -class BAffineTransform { +class BAffineTransform : public BFlattenable { +public: + + static const double kDefaultEpsilon = 1e-14; + public: BAffineTransform(); + BAffineTransform(double sx, double shy, + double shx, double sy, double tx, + double ty); BAffineTransform( const BAffineTransform& copyFrom); - virtual ~BAffineTransform(); + virtual ~BAffineTransform(); - virtual BAffineTransform& operator=( - const BAffineTransform& copyFrom); + // BFlattenable interface + virtual bool IsFixedSize() const; + virtual type_code TypeCode() const; + virtual ssize_t FlattenedSize() const; + virtual status_t Flatten(void* buffer, + ssize_t size) const; + virtual status_t Unflatten(type_code code, + const void* buffer, ssize_t size); - virtual bool operator==( - const BAffineTransform& other) const; - virtual bool operator!=( - const BAffineTransform& other) const; - - // Callbacks - virtual void TransformationChanged() const; + // Construction + static BAffineTransform AffineTranslation(double x, double y); + static BAffineTransform AffineRotation(double angle); + static BAffineTransform AffineScaling(double x, double y); + static BAffineTransform AffineScaling(double scale); + static BAffineTransform AffineShearing(double x, double y); // Application - BPoint Apply(const BPoint& point) const; - void Apply(BPoint* point) const; - void Apply(BPoint* points, uint32 count) const; + inline void Apply(double* x, double* y) const; + inline void ApplyInverse(double* x, double* y) const; - // Rotation - void Rotate(float angle); - void Rotate(const BPoint& center, float angle); - BAffineTransform& RotateBySelf(float angle); - BAffineTransform& RotateBySelf(const BPoint& center, - float angle); - BAffineTransform RotateByCopy(float angle) const; - BAffineTransform RotateByCopy(const BPoint& center, - float angle) const; + BPoint Apply(const BPoint& point) const; + BPoint ApplyInverse(const BPoint& point) const; + + void Apply(BPoint* point) const; + void ApplyInverse(BPoint* point) const; + + void Apply(BPoint* points, uint32 count) const; + void ApplyInverse(BPoint* points, + uint32 count) const; // Translation - void Translate(float deltaX, float deltaY); - void Translate(const BPoint& delta); - BAffineTransform& TranslateBySelf(float deltaX, - float deltaY); - BAffineTransform& TranslateBySelf(const BPoint& delta); - BAffineTransform TranslateByCopy(float deltaX, - float deltaY) const; - BAffineTransform TranslateByCopy(const BPoint& delta) const; + inline const BAffineTransform& TranslateBy(double x, double y); + const BAffineTransform& TranslateBy(const BPoint& delta); + + BAffineTransform TranslateByCopy(double x, double y) const; + BAffineTransform TranslateByCopy(const BPoint& delta) const; + + // Rotation + inline const BAffineTransform& RotateBy(double angle); + const BAffineTransform& RotateBy(const BPoint& center, + double angle); + + BAffineTransform RotateByCopy(double angle) const; + BAffineTransform RotateByCopy(const BPoint& center, + double angle) const; // Scaling - void Scale(float scale); - void Scale(const BPoint& center, float scale); - void Scale(float scaleX, float scaleY); - void Scale(const BPoint& center, float scaleX, - float scaleY); - void Scale(const BPoint& scale); - void Scale(const BPoint& center, + inline const BAffineTransform& ScaleBy(double scale); + const BAffineTransform& ScaleBy(const BPoint& center, + double scale); + inline const BAffineTransform& ScaleBy(double x, double y); + const BAffineTransform& ScaleBy(const BPoint& center, double x, + double y); + const BAffineTransform& ScaleBy(const BPoint& scale); + const BAffineTransform& ScaleBy(const BPoint& center, const BPoint& scale); - BAffineTransform& ScaleBySelf(float scale); - BAffineTransform& ScaleBySelf(const BPoint& center, - float scale); - BAffineTransform& ScaleBySelf(float scaleX, float scaleY); - BAffineTransform& ScaleBySelf(const BPoint& center, - float scaleX, float scaleY); - BAffineTransform& ScaleBySelf(const BPoint& scale); - BAffineTransform& ScaleBySelf(const BPoint& center, - const BPoint& scale); - BAffineTransform ScaleByCopy(float scale) const; - BAffineTransform ScaleByCopy(const BPoint& center, - float scale) const; - BAffineTransform ScaleByCopy(float scaleX, - float scaleY) const; - BAffineTransform ScaleByCopy(const BPoint& center, - float scaleX, float scaleY) const; - BAffineTransform ScaleByCopy(const BPoint& scale) const; - BAffineTransform ScaleByCopy(const BPoint& center, + + BAffineTransform ScaleByCopy(double scale) const; + BAffineTransform ScaleByCopy(const BPoint& center, + double scale) const; + BAffineTransform ScaleByCopy(double x, double y) const; + BAffineTransform ScaleByCopy(const BPoint& center, + double x, double y) const; + BAffineTransform ScaleByCopy(const BPoint& scale) const; + BAffineTransform ScaleByCopy(const BPoint& center, const BPoint& scale) const; // Shearing - void Shear(float shearX, float shearY); - void Shear(const BPoint& center, float shearX, - float shearY); - void Shear(const BPoint& shear); - void Shear(const BPoint& center, + inline const BAffineTransform& ShearBy(double x, double y); + const BAffineTransform& ShearBy(const BPoint& center, double x, + double y); + const BAffineTransform& ShearBy(const BPoint& shear); + const BAffineTransform& ShearBy(const BPoint& center, const BPoint& shear); - BAffineTransform& ShearBySelf(float shearX, float shearY); - BAffineTransform& ShearBySelf(const BPoint& center, - float shearX, float shearY); - BAffineTransform& ShearBySelf(const BPoint& shear); - BAffineTransform& ShearBySelf(const BPoint& center, - const BPoint& shear); - BAffineTransform ShearByCopy(float shearX, - float shearY) const; - BAffineTransform ShearByCopy(const BPoint& center, - float shearX, float shearY) const; - BAffineTransform ShearByCopy(const BPoint& shear) const; - BAffineTransform ShearByCopy(const BPoint& center, + BAffineTransform ShearByCopy(double x, double y) const; + BAffineTransform ShearByCopy(const BPoint& center, + double x, double y) const; + BAffineTransform ShearByCopy(const BPoint& shear) const; + BAffineTransform ShearByCopy(const BPoint& center, const BPoint& shear) const; -private: - void _Rotate(float angle); - void _Scale(float scaleX, float scaleY); - void _Translate(float deltaX, float deltaY); - void _Shear(float shearX, float shearY); + // Multiplication + inline const BAffineTransform& Multiply(const BAffineTransform& other); + const BAffineTransform& PreMultiply(const BAffineTransform& other); + inline const BAffineTransform& MultiplyInverse( + const BAffineTransform& other); + inline const BAffineTransform& PreMultiplyInverse( + const BAffineTransform& other); - void _TransformPoint(BPoint& point) const; + // Operators + inline BAffineTransform& operator=( + const BAffineTransform& copyFrom); -private: - agg::trans_affine fTransformMatrix; + inline bool operator==( + const BAffineTransform& other) const; + inline bool operator!=( + const BAffineTransform& other) const; + + inline const BAffineTransform& operator*=(const BAffineTransform& other); + inline const BAffineTransform& operator/=(const BAffineTransform& other); + + inline BAffineTransform operator*( + const BAffineTransform& other) const; + inline BAffineTransform operator/( + const BAffineTransform& other) const; + + inline BAffineTransform operator~() const; + + // Utility + bool IsValid(double epsilon + = kDefaultEpsilon) const; + bool IsIdentity(double epsilon + = kDefaultEpsilon) const; + bool IsEqual(const BAffineTransform& other, + double epsilon + = kDefaultEpsilon) const; + + const BAffineTransform& Invert(); + const BAffineTransform& FlipX(); + const BAffineTransform& FlipY(); + const BAffineTransform& Reset(); + + inline double Determinant() const; + inline double InverseDeterminant() const; + void GetTranslation(double* tx, + double* ty) const; + double Rotation() const; + double Scale() const; + void GetScale(double* sx, double* sy) const; + void GetScaleAbs(double* sx, + double* sy) const; + bool GetAffineParameters(double* translationX, + double* translationY, double* rotation, + double* scaleX, double* scaleY, + double* shearX, double* shearY) const; + +public: + double sx; + double shy; + double shx; + double sy; + double tx; + double ty; }; -} // namespace BPrivate -using namespace BPrivate; +// #pragma mark - inline methods + + +inline void +BAffineTransform::Apply(double* x, double* y) const +{ + register double tmp = *x; + *x = tmp * sx + *y * shx + tx; + *y = tmp * shy + *y * sy + ty; +} + + +inline void +BAffineTransform::ApplyInverse(double* x, double* y) const +{ + register double d = InverseDeterminant(); + register double a = (*x - tx) * d; + register double b = (*y - ty) * d; + *x = a * sy - b * shx; + *y = b * sx - a * shy; +} + + +// #pragma mark - + + +inline const BAffineTransform& +BAffineTransform::TranslateBy(double x, double y) +{ + tx += x; + ty += y; + return *this; +} + + +inline const BAffineTransform& +BAffineTransform::RotateBy(double angle) +{ + double ca = cos(angle); + double sa = sin(angle); + double t0 = sx * ca - shy * sa; + double t2 = shx * ca - sy * sa; + double t4 = tx * ca - ty * sa; + shy = sx * sa + shy * ca; + sy = shx * sa + sy * ca; + ty = tx * sa + ty * ca; + sx = t0; + shx = t2; + tx = t4; + return *this; +} + + +inline const BAffineTransform& +BAffineTransform::ScaleBy(double x, double y) +{ + double mm0 = x; + // Possible hint for the optimizer + double mm3 = y; + sx *= mm0; + shx *= mm0; + tx *= mm0; + shy *= mm3; + sy *= mm3; + ty *= mm3; + return *this; +} + + +inline const BAffineTransform& +BAffineTransform::ScaleBy(double s) +{ + double m = s; + // Possible hint for the optimizer + sx *= m; + shx *= m; + tx *= m; + shy *= m; + sy *= m; + ty *= m; + return *this; +} + + +inline const BAffineTransform& +BAffineTransform::ShearBy(double x, double y) +{ + BAffineTransform shearTransform = AffineShearing(x, y); + return PreMultiply(shearTransform); +} + + +// #pragma mark - + + +inline const BAffineTransform& +BAffineTransform::Multiply(const BAffineTransform& other) +{ + BAffineTransform t(other); + return *this = t.PreMultiply(*this); +} + + +inline const BAffineTransform& +BAffineTransform::MultiplyInverse(const BAffineTransform& other) +{ + BAffineTransform t(other); + t.Invert(); + return Multiply(t); +} + + +inline const BAffineTransform& +BAffineTransform::PreMultiplyInverse(const BAffineTransform& other) +{ + BAffineTransform t(other); + t.Invert(); + return *this = t.Multiply(*this); +} + + +// #pragma mark - + + +inline BAffineTransform& +BAffineTransform::operator=(const BAffineTransform& other) +{ + sx = other.sx; + shy = other.shy; + shx = other.shx; + sy = other.sy; + tx = other.tx; + ty = other.ty; + return *this; +} + +inline bool +BAffineTransform::operator==(const BAffineTransform& other) const +{ + return IsEqual(other); +} + +inline bool +BAffineTransform::operator!=(const BAffineTransform& other) const +{ + return !IsEqual(other); +} + + +inline const BAffineTransform& +BAffineTransform::operator*=(const BAffineTransform& other) +{ + return Multiply(other); +} + + +inline const BAffineTransform& +BAffineTransform::operator/=(const BAffineTransform& other) +{ + return MultiplyInverse(other); +} + + +inline BAffineTransform +BAffineTransform::operator*(const BAffineTransform& other) const +{ + return BAffineTransform(*this).Multiply(other); +} + + +inline BAffineTransform +BAffineTransform::operator/(const BAffineTransform& other) const +{ + return BAffineTransform(*this).MultiplyInverse(other); +} + + +inline BAffineTransform +BAffineTransform::operator~() const +{ + BAffineTransform result(*this); + return result.Invert(); +} + + +// #pragma mark - + + +inline double +BAffineTransform::Determinant() const +{ + return sx * sy - shy * shx; +} + + +inline double +BAffineTransform::InverseDeterminant() const +{ + return 1.0 / (sx * sy - shy * shx); +} + #endif // _AFFINE_TRANSFORM_H diff --git a/headers/os/support/TypeConstants.h b/headers/os/support/TypeConstants.h index 45f7839a90..8f0a6e5123 100644 --- a/headers/os/support/TypeConstants.h +++ b/headers/os/support/TypeConstants.h @@ -13,6 +13,7 @@ enum { + B_AFFINE_TRANSFORM_TYPE = 'AMTX', B_ANY_TYPE = 'ANYT', B_ATOM_TYPE = 'ATOM', B_ATOMREF_TYPE = 'ATMR', @@ -64,7 +65,7 @@ enum { // System-wide MIME types for handling URL's extern const char *B_URL_HTTP; // application/x-vnd.Be.URL.http -extern const char *B_URL_HTTPS; // application/x-vnd.Be.URL.https +extern const char *B_URL_HTTPS; // application/x-vnd.Be.URL.https extern const char *B_URL_FTP; // application/x-vnd.Be.URL.ftp extern const char *B_URL_GOPHER; // application/x-vnd.Be.URL.gopher extern const char *B_URL_MAILTO; // application/x-vnd.Be.URL.mailto diff --git a/src/kits/interface/AffineTransform.cpp b/src/kits/interface/AffineTransform.cpp index f33a4233cc..96d9f17bf4 100644 --- a/src/kits/interface/AffineTransform.cpp +++ b/src/kits/interface/AffineTransform.cpp @@ -4,22 +4,61 @@ * * Authors: * Stephen Deken, stephen.deken@gmail.com + * Stephan Aßmus */ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- #include -#include + +#include BAffineTransform::BAffineTransform() : - fTransformMatrix() + sx(1.0), + shy(0.0), + shx(0.0), + sy(1.0), + tx(0.0), + ty(0.0) { } -BAffineTransform::BAffineTransform(const BAffineTransform& copyFrom) +BAffineTransform::BAffineTransform(double sx, double shy, double shx, + double sy, double tx, double ty) : - fTransformMatrix(copyFrom.fTransformMatrix) + sx(sx), + shy(shy), + shx(shx), + sy(sy), + tx(tx), + ty(ty) +{ +} + + +BAffineTransform::BAffineTransform(const BAffineTransform& other) + : + sx(other.sx), + shy(other.shy), + shx(other.shx), + sy(other.sy), + tx(other.tx), + ty(other.ty) { } @@ -29,153 +68,191 @@ BAffineTransform::~BAffineTransform() } -BAffineTransform& -BAffineTransform::operator=(const BAffineTransform& copyFrom) -{ - if (copyFrom != *this) { - fTransformMatrix.reset(); - fTransformMatrix.multiply(copyFrom.fTransformMatrix); - TransformationChanged(); - } - return *this; -} +// #pragma mark - bool -BAffineTransform::operator==(const BAffineTransform& other) const +BAffineTransform::IsFixedSize() const { - return fTransformMatrix == other.fTransformMatrix; + return true; } -bool -BAffineTransform::operator!=(const BAffineTransform& other) const +type_code +BAffineTransform::TypeCode() const { - return fTransformMatrix != other.fTransformMatrix; + return B_AFFINE_TRANSFORM_TYPE; } -void -BAffineTransform::TransformationChanged() const +ssize_t +BAffineTransform::FlattenedSize() const { - // default implementation does nothing + return 6 * sizeof(double); } +status_t +BAffineTransform::Flatten(void* _buffer, ssize_t size) const +{ + if (_buffer == NULL || size < FlattenedSize()) + return B_BAD_VALUE; + + double* buffer = reinterpret_cast(_buffer); + + buffer[0] = sx; + buffer[1] = shy; + buffer[2] = shx; + buffer[3] = sy; + buffer[4] = tx; + buffer[5] = ty; + + return B_OK; +} + + +status_t +BAffineTransform::Unflatten(type_code code, const void* _buffer, ssize_t size) +{ + if (_buffer == NULL || size < FlattenedSize() || code != TypeCode()) + return B_BAD_VALUE; + + const double* buffer = reinterpret_cast(_buffer); + + sx = buffer[0]; + shy = buffer[1]; + shx = buffer[2]; + sy = buffer[3]; + tx = buffer[4]; + ty = buffer[5]; + + return B_OK; +} + + +// #pragma mark - + + +/*static*/ BAffineTransform +BAffineTransform::AffineTranslation(double x, double y) +{ + return BAffineTransform(1.0, 0.0, 0.0, 1.0, x, y); +} + + +/*static*/ BAffineTransform +BAffineTransform::AffineRotation(double angle) +{ + return BAffineTransform(cos(angle), sin(angle), -sin(angle), cos(angle), + 0.0, 0.0); +} + + +/*static*/ BAffineTransform +BAffineTransform::AffineScaling(double x, double y) +{ + return BAffineTransform(x, 0.0, 0.0, y, 0.0, 0.0); +} + + +/*static*/ BAffineTransform +BAffineTransform::AffineScaling(double scale) +{ + return BAffineTransform(scale, 0.0, 0.0, scale, 0.0, 0.0); +} + + +/*static*/ BAffineTransform +BAffineTransform::AffineShearing(double x, double y) +{ + return BAffineTransform(1.0, tan(y), tan(x), 1.0, 0.0, 0.0); +} + + +// #pragma mark - + + BPoint BAffineTransform::Apply(const BPoint& point) const { - BPoint result(point); - _TransformPoint(result); - return result; + double x = point.x; + double y = point.y; + Apply(&x, &y); + return BPoint(x, y); +} + + +BPoint +BAffineTransform::ApplyInverse(const BPoint& point) const +{ + double x = point.x; + double y = point.y; + ApplyInverse(&x, &y); + return BPoint(x, y); } void BAffineTransform::Apply(BPoint* point) const { - if (point) - _TransformPoint(*point); + if (point == NULL) + return; + double x = point->x; + double y = point->y; + Apply(&x, &y); + point->x = x; + point->y = y; +} + + +void +BAffineTransform::ApplyInverse(BPoint* point) const +{ + if (point == NULL) + return; + double x = point->x; + double y = point->y; + ApplyInverse(&x, &y); + point->x = x; + point->y = y; } void BAffineTransform::Apply(BPoint* points, uint32 count) const { - if (points) { + if (points != NULL) { for (uint32 i = 0; i < count; ++i) - _TransformPoint(points[i]); + Apply(&points[i]); } } void -BAffineTransform::Rotate(float angle) +BAffineTransform::ApplyInverse(BPoint* points, uint32 count) const { - _Rotate(angle); - TransformationChanged(); + if (points != NULL) { + for (uint32 i = 0; i < count; ++i) + ApplyInverse(&points[i]); + } } -void -BAffineTransform::Rotate(const BPoint& center, float angle) +// #pragma mark - + + +const BAffineTransform& +BAffineTransform::TranslateBy(const BPoint& delta) { - _Translate(-center.x, -center.y); - _Rotate(angle); - _Translate(center.x, center.y); - TransformationChanged(); -} - - -BAffineTransform& -BAffineTransform::RotateBySelf(float angle) -{ - Rotate(angle); - return *this; -} - - -BAffineTransform& -BAffineTransform::RotateBySelf(const BPoint& center, float angle) -{ - Rotate(center, angle); - return *this; + return TranslateBy(delta.x, delta.y); } BAffineTransform -BAffineTransform::RotateByCopy(float angle) const +BAffineTransform::TranslateByCopy(double x, double y) const { BAffineTransform copy(*this); - copy.Rotate(angle); - return copy; -} - - -BAffineTransform -BAffineTransform::RotateByCopy(const BPoint& center, float angle) const -{ - BAffineTransform copy(*this); - copy.Rotate(center, angle); - return copy; -} - - -void -BAffineTransform::Translate(float deltaX, float deltaY) -{ - _Translate(deltaX, deltaY); - TransformationChanged(); -} - - -void -BAffineTransform::Translate(const BPoint& delta) -{ - Translate(delta.x, delta.y); -} - - -BAffineTransform& -BAffineTransform::TranslateBySelf(float deltaX, float deltaY) -{ - Translate(deltaX, deltaY); - return *this; -} - - -BAffineTransform& -BAffineTransform::TranslateBySelf(const BPoint& delta) -{ - return TranslateBySelf(delta.x, delta.y); -} - - -BAffineTransform -BAffineTransform::TranslateByCopy(float deltaX, float deltaY) const -{ - BAffineTransform copy(*this); - copy.Translate(deltaX, deltaY); + copy.TranslateBy(x, y); return copy; } @@ -187,125 +264,97 @@ BAffineTransform::TranslateByCopy(const BPoint& delta) const } -void -BAffineTransform::Scale(float scale) +// #pragma mark - + + +const BAffineTransform& +BAffineTransform::RotateBy(const BPoint& center, double angle) { - Scale(scale, scale); -} - - -void -BAffineTransform::Scale(const BPoint& center, float scale) -{ - Scale(center, scale, scale); -} - - -void -BAffineTransform::Scale(float scaleX, float scaleY) -{ - _Scale(scaleX, scaleY); - TransformationChanged(); -} - - -void -BAffineTransform::Scale(const BPoint& center, float scaleX, float scaleY) -{ - _Translate(-center.x, -center.y); - _Scale(scaleX, scaleY); - _Translate(center.x, center.y); - TransformationChanged(); -} - - -void -BAffineTransform::Scale(const BPoint& scale) -{ - Scale(scale.x, scale.y); -} - - -void -BAffineTransform::Scale(const BPoint& center, const BPoint& scale) -{ - Scale(center, scale.x, scale.y); -} - - -BAffineTransform& -BAffineTransform::ScaleBySelf(float scale) -{ - return ScaleBySelf(scale, scale); -} - - -BAffineTransform& -BAffineTransform::ScaleBySelf(const BPoint& center, float scale) -{ - return ScaleBySelf(center, scale, scale); -} - - -BAffineTransform& -BAffineTransform::ScaleBySelf(float scaleX, float scaleY) -{ - Scale(scaleX, scaleY); - return *this; -} - - -BAffineTransform& -BAffineTransform::ScaleBySelf(const BPoint& center, float scaleX, float scaleY) -{ - Scale(center, scaleX, scaleY); - return *this; -} - - -BAffineTransform& -BAffineTransform::ScaleBySelf(const BPoint& scale) -{ - return ScaleBySelf(scale.x, scale.y); -} - - -BAffineTransform& -BAffineTransform::ScaleBySelf(const BPoint& center, const BPoint& scale) -{ - return ScaleBySelf(center, scale.x, scale.y); + TranslateBy(-center.x, -center.y); + RotateBy(angle); + return TranslateBy(center.x, center.y); } BAffineTransform -BAffineTransform::ScaleByCopy(float scale) const +BAffineTransform::RotateByCopy(double angle) const +{ + BAffineTransform copy(*this); + copy.RotateBy(angle); + return copy; +} + + +BAffineTransform +BAffineTransform::RotateByCopy(const BPoint& center, double angle) const +{ + BAffineTransform copy(*this); + copy.RotateBy(center, angle); + return copy; +} + + +// #pragma mark - + + +const BAffineTransform& +BAffineTransform::ScaleBy(const BPoint& center, double scale) +{ + return ScaleBy(center, scale, scale); +} + + +const BAffineTransform& +BAffineTransform::ScaleBy(const BPoint& center, double x, double y) +{ + TranslateBy(-center.x, -center.y); + ScaleBy(x, y); + return TranslateBy(center.x, center.y); +} + + +const BAffineTransform& +BAffineTransform::ScaleBy(const BPoint& scale) +{ + return ScaleBy(scale.x, scale.y); +} + + +const BAffineTransform& +BAffineTransform::ScaleBy(const BPoint& center, const BPoint& scale) +{ + return ScaleBy(center, scale.x, scale.y); +} + + +BAffineTransform +BAffineTransform::ScaleByCopy(double scale) const { return ScaleByCopy(scale, scale); } BAffineTransform -BAffineTransform::ScaleByCopy(const BPoint& center, float scale) const +BAffineTransform::ScaleByCopy(const BPoint& center, double scale) const { return ScaleByCopy(center, scale, scale); } BAffineTransform -BAffineTransform::ScaleByCopy(float scaleX, float scaleY) const +BAffineTransform::ScaleByCopy(double x, double y) const { BAffineTransform copy(*this); - copy.Scale(scaleX, scaleY); + copy.ScaleBy(x, y); return copy; } BAffineTransform -BAffineTransform::ScaleByCopy(const BPoint& center, float scaleX, - float scaleY) const +BAffineTransform::ScaleByCopy(const BPoint& center, double x, double y) const { BAffineTransform copy(*this); - copy.Scale(center, scaleX, scaleY); + copy.ScaleBy(center, x, y); return copy; } @@ -324,85 +373,46 @@ BAffineTransform::ScaleByCopy(const BPoint& center, const BPoint& scale) const } -void -BAffineTransform::Shear(float shearX, float shearY) +// #pragma mark - + + +const BAffineTransform& +BAffineTransform::ShearBy(const BPoint& center, double x, double y) { - _Shear(shearX, shearY); - TransformationChanged(); + TranslateBy(-center.x, -center.y); + ShearBy(x, y); + return TranslateBy(center.x, center.y); } -void -BAffineTransform::Shear(const BPoint& center, float shearX, float shearY) +const BAffineTransform& +BAffineTransform::ShearBy(const BPoint& shear) { - _Translate(-center.x, -center.y); - _Shear(shearX, shearY); - _Translate(center.x, center.y); - TransformationChanged(); + return ShearBy(shear.x, shear.y); } -void -BAffineTransform::Shear(const BPoint& shear) +const BAffineTransform& +BAffineTransform::ShearBy(const BPoint& center, const BPoint& shear) { - Shear(shear.x, shear.y); -} - - -void -BAffineTransform::Shear(const BPoint& center, const BPoint& shear) -{ - Shear(center, shear.x, shear.y); -} - - -BAffineTransform& -BAffineTransform::ShearBySelf(float shearX, float shearY) -{ - Shear(shearX, shearY); - return *this; -} - - -BAffineTransform& -BAffineTransform::ShearBySelf(const BPoint& center, float shearX, float shearY) -{ - Shear(center, shearX, shearY); - return *this; -} - - -BAffineTransform& -BAffineTransform::ShearBySelf(const BPoint& shear) -{ - Shear(shear); - return *this; -} - - -BAffineTransform& -BAffineTransform::ShearBySelf(const BPoint& center, const BPoint& shear) -{ - Shear(center, shear); - return *this; + return ShearBy(center, shear.x, shear.y); } BAffineTransform -BAffineTransform::ShearByCopy(float shearX, float shearY) const +BAffineTransform::ShearByCopy(double x, double y) const { BAffineTransform copy(*this); - copy.Shear(shearX, shearY); + copy.ShearBy(x, y); return copy; } BAffineTransform -BAffineTransform::ShearByCopy(const BPoint& center, float shearX, - float shearY) const +BAffineTransform::ShearByCopy(const BPoint& center, double x, double y) const { BAffineTransform copy(*this); - copy.Shear(center, shearX, shearY); + copy.ShearBy(center, x, y); return copy; } @@ -411,7 +421,7 @@ BAffineTransform BAffineTransform::ShearByCopy(const BPoint& shear) const { BAffineTransform copy(*this); - copy.Shear(shear); + copy.ShearBy(shear); return copy; } @@ -420,7 +430,7 @@ BAffineTransform BAffineTransform::ShearByCopy(const BPoint& center, const BPoint& shear) const { BAffineTransform copy(*this); - copy.Shear(center, shear); + copy.ShearBy(center, shear); return copy; } @@ -428,46 +438,234 @@ BAffineTransform::ShearByCopy(const BPoint& center, const BPoint& shear) const // #pragma mark - -void -BAffineTransform::_Rotate(float angle) +const BAffineTransform& +BAffineTransform::PreMultiply(const BAffineTransform& other) { - if (angle != 0.0) - fTransformMatrix.multiply(agg::trans_affine_rotation(angle)); + double t0 = sx * other.sx + shy * other.shx; + double t2 = shx * other.sx + sy * other.shx; + double t4 = tx * other.sx + ty * other.shx + other.tx; + shy = sx * other.shy + shy * other.sy; + sy = shx * other.shy + sy * other.sy; + ty = tx * other.shy + ty * other.sy + other.ty; + sx = t0; + shx = t2; + tx = t4; + return *this; +} + + +bool +BAffineTransform::IsValid(double epsilon) const +{ + return fabs(sx) > epsilon && fabs(sy) > epsilon; +} + + +static inline bool +IsEqualEpsilon(double v1, double v2, double epsilon) +{ + return fabs(v1 - v2) <= double(epsilon); +} + + +bool +BAffineTransform::IsIdentity(double epsilon) const +{ + return IsEqualEpsilon(sx, 1.0, epsilon) + && IsEqualEpsilon(shy, 0.0, epsilon) + && IsEqualEpsilon(shx, 0.0, epsilon) + && IsEqualEpsilon(sy, 1.0, epsilon) + && IsEqualEpsilon(tx, 0.0, epsilon) + && IsEqualEpsilon(ty, 0.0, epsilon); +} + + +bool +BAffineTransform::IsEqual(const BAffineTransform& other, double epsilon) const +{ + return IsEqualEpsilon(sx, other.sx, epsilon) + && IsEqualEpsilon(shy, other.shy, epsilon) + && IsEqualEpsilon(shx, other.shx, epsilon) + && IsEqualEpsilon(sy, other.sy, epsilon) + && IsEqualEpsilon(tx, other.tx, epsilon) + && IsEqualEpsilon(ty, other.ty, epsilon); +} + + +const BAffineTransform& +BAffineTransform::Invert() +{ + double d = InverseDeterminant(); + + double t0 = sy * d; + sy = sx * d; + shy = -shy * d; + shx = -shx * d; + + double t4 = -tx * t0 - ty * shx; + ty = -tx * shy - ty * sy; + + sx = t0; + tx = t4; + + return *this; +} + + +const BAffineTransform& +BAffineTransform::FlipX() +{ + sx = -sx; + shy = -shy; + tx = -tx; + return *this; +} + + +const BAffineTransform& +BAffineTransform::FlipY() +{ + shx = -shx; + sy = -sy; + ty = -ty; + return *this; +} + + +const BAffineTransform& +BAffineTransform::Reset() +{ + sx = sy = 1.0; + shy = shx = tx = ty = 0.0; + return *this; } void -BAffineTransform::_Scale(float scaleX, float scaleY) +BAffineTransform::GetTranslation(double* _tx, double* _ty) const { - if (scaleX != 0.0 || scaleY != 0.0) - fTransformMatrix.multiply(agg::trans_affine_scaling(scaleX, scaleY)); + if (_tx) + *_tx = tx; + if (_ty) + *_ty = ty; +} + + +double +BAffineTransform::Rotation() const +{ + double x1 = 0.0; + double y1 = 0.0; + double x2 = 1.0; + double y2 = 0.0; + Apply(&x1, &y1); + Apply(&x2, &y2); + return atan2(y2 - y1, x2 - x1); +} + + +double +BAffineTransform::Scale() const +{ + double x = 0.707106781 * sx + 0.707106781 * shx; + double y = 0.707106781 * shy + 0.707106781 * sy; + return sqrt(x * x + y * y); } void -BAffineTransform::_Translate(float deltaX, float deltaY) +BAffineTransform::GetScale(double* _sx, double* _sy) const { - if (deltaX != 0.0 || deltaY != 0.0) { - fTransformMatrix.multiply( - agg::trans_affine_translation(deltaX, deltaY)); - } + double x1 = 0.0; + double y1 = 0.0; + double x2 = 1.0; + double y2 = 1.0; + BAffineTransform t(*this); + t.PreMultiply(AffineRotation(-Rotation())); + t.Apply(&x1, &y1); + t.Apply(&x2, &y2); + if (_sx) + *_sx = x2 - x1; + if (_sy) + *_sy = y2 - y1; } void -BAffineTransform::_Shear(float shearX, float shearY) +BAffineTransform::GetScaleAbs(double* _sx, double* _sy) const { - if (shearX != 0.0 || shearY != 0.0) - fTransformMatrix.multiply(agg::trans_affine_skewing(shearX, shearY)); + // When there is considerable shear this method gives us much + // better estimation than just sx, sy. + if (_sx) + *_sx = sqrt(sx * sx + shx * shx); + if (_sy) + *_sy = sqrt(shy * shy + sy * sy); } -void -BAffineTransform::_TransformPoint(BPoint& point) const +bool +BAffineTransform::GetAffineParameters(double* _translationX, + double* _translationY, double* _rotation, double* _scaleX, double* _scaleY, + double* _shearX, double* _shearY) const { - double x = point.x; - double y = point.y; - fTransformMatrix.transform(&x, &y); - point.x = x; - point.y = y; + GetTranslation(_translationX, _translationY); + + double rotation = Rotation(); + if (_rotation != NULL) + *_rotation = rotation; + + // Calculate shear + double x1 = 0.0; + double y1 = 0.0; + double x2 = 1.0; + double y2 = 0.0; + double x3 = 0.0; + double y3 = 1.0; + + // Reverse the effects of any rotation + BAffineTransform t(*this); + t.PreMultiply(AffineRotation(-rotation)); + + t.Apply(&x1, &y1); + t.Apply(&x2, &y2); + t.Apply(&x3, &y3); + + double shearX = y2 - y1; + double shearY = x3 - x1; + + // Calculate scale + x1 = 0.0; + y1 = 0.0; + x2 = 1.0; + y2 = 0.0; + x3 = 0.0; + y3 = 1.0; + + // Reverse the effects of any shear + t.PreMultiplyInverse(AffineShearing(shearX, shearY)); + + t.Apply(&x1, &y1); + t.Apply(&x2, &y2); + t.Apply(&x3, &y3); + + double scaleX = x2 - x1; + double scaleY = y3 - y1; + + if (_scaleX != NULL) + *_scaleX = scaleX; + if (_scaleY != NULL) + *_scaleY = scaleY; + + // Since scale was calculated last, the shear values are still scaled. + // We cannot get the affine parameters from a matrix with 0 scale. + if (scaleX == 0.0 && scaleY == 0.0) + return false; + + if (_shearX != NULL) + *_shearX = shearX / scaleX; + if (_shearY != NULL) + *_shearY = shearY / scaleY; + + return true; } +