10e684ccfSStephan Aßmus /*
27f5bbbdcSAxel Dörfler * Copyright 2006-2009, Haiku.
30e684ccfSStephan Aßmus * Distributed under the terms of the MIT License.
40e684ccfSStephan Aßmus *
50e684ccfSStephan Aßmus * Authors:
60e684ccfSStephan Aßmus * Stephan Aßmus <superstippi@gmx.de>
70e684ccfSStephan Aßmus */
80e684ccfSStephan Aßmus
90e684ccfSStephan Aßmus #include "ChannelTransform.h"
100e684ccfSStephan Aßmus
110e1ba39fSStephan Aßmus #include <math.h>
120e684ccfSStephan Aßmus #include <stdio.h>
130e684ccfSStephan Aßmus
147f5bbbdcSAxel Dörfler
150e684ccfSStephan Aßmus // constructor
ChannelTransform()160e684ccfSStephan Aßmus ChannelTransform::ChannelTransform()
177f5bbbdcSAxel Dörfler :
187f5bbbdcSAxel Dörfler Transformable(),
190e684ccfSStephan Aßmus fPivot(0.0, 0.0),
200e684ccfSStephan Aßmus fTranslation(0.0, 0.0),
210e684ccfSStephan Aßmus fRotation(0.0),
220e684ccfSStephan Aßmus fXScale(1.0),
230e684ccfSStephan Aßmus fYScale(1.0)
240e684ccfSStephan Aßmus {
250e684ccfSStephan Aßmus }
260e684ccfSStephan Aßmus
270e684ccfSStephan Aßmus // copy constructor
ChannelTransform(const ChannelTransform & other)280e684ccfSStephan Aßmus ChannelTransform::ChannelTransform(const ChannelTransform& other)
297f5bbbdcSAxel Dörfler :
307f5bbbdcSAxel Dörfler Transformable(other),
310e684ccfSStephan Aßmus fPivot(other.fPivot),
320e684ccfSStephan Aßmus fTranslation(other.fTranslation),
330e684ccfSStephan Aßmus fRotation(other.fRotation),
340e684ccfSStephan Aßmus fXScale(other.fXScale),
350e684ccfSStephan Aßmus fYScale(other.fYScale)
360e684ccfSStephan Aßmus {
370e684ccfSStephan Aßmus }
380e684ccfSStephan Aßmus
397f5bbbdcSAxel Dörfler
400e684ccfSStephan Aßmus // destructor
~ChannelTransform()410e684ccfSStephan Aßmus ChannelTransform::~ChannelTransform()
420e684ccfSStephan Aßmus {
430e684ccfSStephan Aßmus }
440e684ccfSStephan Aßmus
457f5bbbdcSAxel Dörfler
460e684ccfSStephan Aßmus // SetTransformation
470e684ccfSStephan Aßmus void
SetTransformation(const Transformable & other)480e1ba39fSStephan Aßmus ChannelTransform::SetTransformation(const Transformable& other)
490e1ba39fSStephan Aßmus {
500e1ba39fSStephan Aßmus // calc affine parameters
510e1ba39fSStephan Aßmus
520e1ba39fSStephan Aßmus // translation
530e1ba39fSStephan Aßmus double tx;
540e1ba39fSStephan Aßmus double ty;
550e1ba39fSStephan Aßmus other.translation(&tx, &ty);
560e1ba39fSStephan Aßmus
570e1ba39fSStephan Aßmus // rotation
580e1ba39fSStephan Aßmus double rotation = agg::rad2deg(other.rotation());
590e1ba39fSStephan Aßmus
600e1ba39fSStephan Aßmus // scale
610e1ba39fSStephan Aßmus double scaleX;
620e1ba39fSStephan Aßmus double scaleY;
630e1ba39fSStephan Aßmus other.scaling(&scaleX, &scaleY);
640e1ba39fSStephan Aßmus
650e1ba39fSStephan Aßmus if (isnanf(tx) || isnanf(ty) || isnanf(scaleX) || isnanf(scaleY))
660e1ba39fSStephan Aßmus return;
670e1ba39fSStephan Aßmus
680e1ba39fSStephan Aßmus SetTransformation(B_ORIGIN, BPoint(tx, ty), rotation, scaleX, scaleY);
690e1ba39fSStephan Aßmus }
700e1ba39fSStephan Aßmus
717f5bbbdcSAxel Dörfler
720e1ba39fSStephan Aßmus // SetTransformation
730e1ba39fSStephan Aßmus void
SetTransformation(BPoint pivot,BPoint translation,double rotation,double xScale,double yScale)747f5bbbdcSAxel Dörfler ChannelTransform::SetTransformation(BPoint pivot, BPoint translation,
757f5bbbdcSAxel Dörfler double rotation, double xScale, double yScale)
760e684ccfSStephan Aßmus {
770e1ba39fSStephan Aßmus //printf("SetTransformation(BPoint(%.1f, %.1f), BPoint(%.1f, %.1f), "
780e1ba39fSStephan Aßmus //"%.2f, %.2f, %.2f)\n", pivot.x, pivot.y, translation.x, translation.y,
790e1ba39fSStephan Aßmus //rotation, xScale, yScale);
800e1ba39fSStephan Aßmus
810e684ccfSStephan Aßmus if (fTranslation != translation ||
820e684ccfSStephan Aßmus fPivot != pivot ||
830e684ccfSStephan Aßmus fRotation != rotation ||
840e684ccfSStephan Aßmus fXScale != xScale ||
850e684ccfSStephan Aßmus fYScale != yScale) {
860e684ccfSStephan Aßmus
870e684ccfSStephan Aßmus fPivot = pivot;
880e684ccfSStephan Aßmus fTranslation = translation;
890e684ccfSStephan Aßmus fRotation = rotation;
900e684ccfSStephan Aßmus fXScale = xScale;
910e684ccfSStephan Aßmus fYScale = yScale;
920e684ccfSStephan Aßmus
930e684ccfSStephan Aßmus _UpdateMatrix();
940e684ccfSStephan Aßmus }
950e684ccfSStephan Aßmus }
960e684ccfSStephan Aßmus
977f5bbbdcSAxel Dörfler
980e684ccfSStephan Aßmus // SetPivot
990e684ccfSStephan Aßmus void
SetPivot(BPoint pivot)1000e684ccfSStephan Aßmus ChannelTransform::SetPivot(BPoint pivot)
1010e684ccfSStephan Aßmus {
1020e684ccfSStephan Aßmus if (pivot == fPivot)
1030e684ccfSStephan Aßmus return;
1040e684ccfSStephan Aßmus
1050e684ccfSStephan Aßmus fPivot = pivot;
1060e684ccfSStephan Aßmus
1070e684ccfSStephan Aßmus _UpdateMatrix();
1080e684ccfSStephan Aßmus }
1090e684ccfSStephan Aßmus
1107f5bbbdcSAxel Dörfler
1110e684ccfSStephan Aßmus // TranslateBy
1120e684ccfSStephan Aßmus void
TranslateBy(BPoint offset)1130e684ccfSStephan Aßmus ChannelTransform::TranslateBy(BPoint offset)
1140e684ccfSStephan Aßmus {
1150e684ccfSStephan Aßmus if (offset.x == 0.0 && offset.y == 0.0)
1160e684ccfSStephan Aßmus return;
1170e684ccfSStephan Aßmus
1180e684ccfSStephan Aßmus fTranslation += offset;
1190e684ccfSStephan Aßmus
1200e684ccfSStephan Aßmus _UpdateMatrix();
1210e684ccfSStephan Aßmus }
1220e684ccfSStephan Aßmus
1237f5bbbdcSAxel Dörfler
1240e684ccfSStephan Aßmus // RotateBy
1257f5bbbdcSAxel Dörfler /*! Converts a rotation in world coordinates into
1267f5bbbdcSAxel Dörfler a combined local rotation and a translation.
1277f5bbbdcSAxel Dörfler */
1280e684ccfSStephan Aßmus void
RotateBy(BPoint origin,double degrees)1290e684ccfSStephan Aßmus ChannelTransform::RotateBy(BPoint origin, double degrees)
1300e684ccfSStephan Aßmus {
1310e684ccfSStephan Aßmus if (degrees == 0.0)
1320e684ccfSStephan Aßmus return;
1330e684ccfSStephan Aßmus
1340e684ccfSStephan Aßmus origin -= fPivot;
1350e684ccfSStephan Aßmus
1360e684ccfSStephan Aßmus fRotation += degrees;
1370e684ccfSStephan Aßmus
1380e684ccfSStephan Aßmus // rotate fTranslation
1390e684ccfSStephan Aßmus double xOffset = fTranslation.x - origin.x;
1400e684ccfSStephan Aßmus double yOffset = fTranslation.y - origin.y;
1410e684ccfSStephan Aßmus
1427f5bbbdcSAxel Dörfler agg::trans_affine_rotation m(degrees * M_PI / 180.0);
1430e684ccfSStephan Aßmus m.transform(&xOffset, &yOffset);
1440e684ccfSStephan Aßmus
1450e684ccfSStephan Aßmus fTranslation.x = origin.x + xOffset;
1460e684ccfSStephan Aßmus fTranslation.y = origin.y + yOffset;
1470e684ccfSStephan Aßmus
1480e684ccfSStephan Aßmus _UpdateMatrix();
1490e684ccfSStephan Aßmus }
1500e684ccfSStephan Aßmus
1510e684ccfSStephan Aßmus
1520e684ccfSStephan Aßmus // RotateBy
1530e684ccfSStephan Aßmus void
RotateBy(double degrees)1540e684ccfSStephan Aßmus ChannelTransform::RotateBy(double degrees)
1550e684ccfSStephan Aßmus {
1560e684ccfSStephan Aßmus if (degrees == 0.0)
1570e684ccfSStephan Aßmus return;
1580e684ccfSStephan Aßmus
1590e684ccfSStephan Aßmus fRotation += degrees;
1600e684ccfSStephan Aßmus
1610e684ccfSStephan Aßmus _UpdateMatrix();
1620e684ccfSStephan Aßmus }
1630e684ccfSStephan Aßmus
1647f5bbbdcSAxel Dörfler
165*14d604ddSStephan Aßmus // ScaleBy
1660e684ccfSStephan Aßmus //
167*14d604ddSStephan Aßmus // converts a scalation in world coordinates into
168*14d604ddSStephan Aßmus // a combined local scalation and a translation
169*14d604ddSStephan Aßmus void
ScaleBy(BPoint origin,double xScale,double yScale)170*14d604ddSStephan Aßmus ChannelTransform::ScaleBy(BPoint origin, double xScale, double yScale)
171*14d604ddSStephan Aßmus {
172*14d604ddSStephan Aßmus // TODO: Untested?
173*14d604ddSStephan Aßmus if (xScale == 1.0 && yScale == 1.0)
174*14d604ddSStephan Aßmus return;
175*14d604ddSStephan Aßmus
176*14d604ddSStephan Aßmus fXScale *= xScale;
177*14d604ddSStephan Aßmus fYScale *= yScale;
178*14d604ddSStephan Aßmus
179*14d604ddSStephan Aßmus // scale fTranslation
180*14d604ddSStephan Aßmus double xOffset = fTranslation.x - origin.x;
181*14d604ddSStephan Aßmus double yOffset = fTranslation.y - origin.y;
182*14d604ddSStephan Aßmus
183*14d604ddSStephan Aßmus fTranslation.x = origin.x + (xOffset * xScale);
184*14d604ddSStephan Aßmus fTranslation.y = origin.y + (yOffset * yScale);
185*14d604ddSStephan Aßmus
186*14d604ddSStephan Aßmus _UpdateMatrix();
187*14d604ddSStephan Aßmus }
1880e684ccfSStephan Aßmus
1890e684ccfSStephan Aßmus // ScaleBy
1900e684ccfSStephan Aßmus void
ScaleBy(double xScale,double yScale)1910e684ccfSStephan Aßmus ChannelTransform::ScaleBy(double xScale, double yScale)
1920e684ccfSStephan Aßmus {
1930e684ccfSStephan Aßmus if (xScale == 1.0 && yScale == 1.0)
1940e684ccfSStephan Aßmus return;
1950e684ccfSStephan Aßmus
1960e684ccfSStephan Aßmus fXScale *= xScale;
1970e684ccfSStephan Aßmus fYScale *= yScale;
1980e684ccfSStephan Aßmus
1990e684ccfSStephan Aßmus _UpdateMatrix();
2000e684ccfSStephan Aßmus }
2010e684ccfSStephan Aßmus
2027f5bbbdcSAxel Dörfler
2030e684ccfSStephan Aßmus // SetTranslationAndScale
2040e684ccfSStephan Aßmus void
SetTranslationAndScale(BPoint offset,double xScale,double yScale)2057f5bbbdcSAxel Dörfler ChannelTransform::SetTranslationAndScale(BPoint offset, double xScale,
2067f5bbbdcSAxel Dörfler double yScale)
2070e684ccfSStephan Aßmus {
2080e684ccfSStephan Aßmus if (fTranslation == offset && fXScale == xScale && fYScale == yScale)
2090e684ccfSStephan Aßmus return;
2100e684ccfSStephan Aßmus
2110e684ccfSStephan Aßmus fTranslation = offset;
2120e684ccfSStephan Aßmus
2130e684ccfSStephan Aßmus fXScale = xScale;
2140e684ccfSStephan Aßmus fYScale = yScale;
2150e684ccfSStephan Aßmus
2160e684ccfSStephan Aßmus _UpdateMatrix();
2170e684ccfSStephan Aßmus }
2180e684ccfSStephan Aßmus
2197f5bbbdcSAxel Dörfler
2200e684ccfSStephan Aßmus // Reset
2210e684ccfSStephan Aßmus void
Reset()2220e684ccfSStephan Aßmus ChannelTransform::Reset()
2230e684ccfSStephan Aßmus {
2240e684ccfSStephan Aßmus SetTransformation(B_ORIGIN, B_ORIGIN, 0.0, 1.0, 1.0);
2250e684ccfSStephan Aßmus }
2260e684ccfSStephan Aßmus
2277f5bbbdcSAxel Dörfler
2280e684ccfSStephan Aßmus // =
2290e684ccfSStephan Aßmus ChannelTransform&
operator =(const ChannelTransform & other)2300e684ccfSStephan Aßmus ChannelTransform::operator=(const ChannelTransform& other)
2310e684ccfSStephan Aßmus {
2320e684ccfSStephan Aßmus fTranslation = other.fTranslation;
2330e684ccfSStephan Aßmus fRotation = other.fRotation;
2340e684ccfSStephan Aßmus fXScale = other.fXScale;
2350e684ccfSStephan Aßmus fYScale = other.fYScale;
2360e684ccfSStephan Aßmus
2370e684ccfSStephan Aßmus Transformable::operator=(other);
2380e684ccfSStephan Aßmus
2390e684ccfSStephan Aßmus return *this;
2400e684ccfSStephan Aßmus }
2410e684ccfSStephan Aßmus
2427f5bbbdcSAxel Dörfler
2430e684ccfSStephan Aßmus // _UpdateMatrix
2440e684ccfSStephan Aßmus void
_UpdateMatrix()2450e684ccfSStephan Aßmus ChannelTransform::_UpdateMatrix()
2460e684ccfSStephan Aßmus {
2470e684ccfSStephan Aßmus // fix up scales in case any is zero
2480e684ccfSStephan Aßmus double xScale = fXScale;
2490e684ccfSStephan Aßmus if (xScale == 0.0)
2500e684ccfSStephan Aßmus xScale = 0.000001;
2510e684ccfSStephan Aßmus double yScale = fYScale;
2520e684ccfSStephan Aßmus if (yScale == 0.0)
2530e684ccfSStephan Aßmus yScale = 0.000001;
2540e684ccfSStephan Aßmus
2550e684ccfSStephan Aßmus // start clean
2560e684ccfSStephan Aßmus reset();
2570e684ccfSStephan Aßmus // the "pivot" is like the offset from world to local
2580e684ccfSStephan Aßmus // coordinate system and is the center for rotation and scale
2590e684ccfSStephan Aßmus multiply(agg::trans_affine_translation(-fPivot.x, -fPivot.y));
2600e684ccfSStephan Aßmus multiply(agg::trans_affine_scaling(xScale, yScale));
2617f5bbbdcSAxel Dörfler multiply(agg::trans_affine_rotation(fRotation * M_PI / 180.0));
2620e684ccfSStephan Aßmus
2630e684ccfSStephan Aßmus multiply(agg::trans_affine_translation(fPivot.x + fTranslation.x,
2640e684ccfSStephan Aßmus fPivot.y + fTranslation.y));
2650e684ccfSStephan Aßmus
2660e684ccfSStephan Aßmus // call hook function
2670e684ccfSStephan Aßmus Update();
2680e684ccfSStephan Aßmus }
2690e684ccfSStephan Aßmus
270