1 /*
2 * Copyright 2006-2009, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Stephan Aßmus <superstippi@gmx.de>
7 */
8
9 #include "ChannelTransform.h"
10
11 #include <math.h>
12 #include <stdio.h>
13
14
15 // constructor
ChannelTransform()16 ChannelTransform::ChannelTransform()
17 :
18 Transformable(),
19 fPivot(0.0, 0.0),
20 fTranslation(0.0, 0.0),
21 fRotation(0.0),
22 fXScale(1.0),
23 fYScale(1.0)
24 {
25 }
26
27 // copy constructor
ChannelTransform(const ChannelTransform & other)28 ChannelTransform::ChannelTransform(const ChannelTransform& other)
29 :
30 Transformable(other),
31 fPivot(other.fPivot),
32 fTranslation(other.fTranslation),
33 fRotation(other.fRotation),
34 fXScale(other.fXScale),
35 fYScale(other.fYScale)
36 {
37 }
38
39
40 // destructor
~ChannelTransform()41 ChannelTransform::~ChannelTransform()
42 {
43 }
44
45
46 // SetTransformation
47 void
SetTransformation(const Transformable & other)48 ChannelTransform::SetTransformation(const Transformable& other)
49 {
50 // calc affine parameters
51
52 // translation
53 double tx;
54 double ty;
55 other.translation(&tx, &ty);
56
57 // rotation
58 double rotation = agg::rad2deg(other.rotation());
59
60 // scale
61 double scaleX;
62 double scaleY;
63 other.scaling(&scaleX, &scaleY);
64
65 if (isnanf(tx) || isnanf(ty) || isnanf(scaleX) || isnanf(scaleY))
66 return;
67
68 SetTransformation(B_ORIGIN, BPoint(tx, ty), rotation, scaleX, scaleY);
69 }
70
71
72 // SetTransformation
73 void
SetTransformation(BPoint pivot,BPoint translation,double rotation,double xScale,double yScale)74 ChannelTransform::SetTransformation(BPoint pivot, BPoint translation,
75 double rotation, double xScale, double yScale)
76 {
77 //printf("SetTransformation(BPoint(%.1f, %.1f), BPoint(%.1f, %.1f), "
78 //"%.2f, %.2f, %.2f)\n", pivot.x, pivot.y, translation.x, translation.y,
79 //rotation, xScale, yScale);
80
81 if (fTranslation != translation ||
82 fPivot != pivot ||
83 fRotation != rotation ||
84 fXScale != xScale ||
85 fYScale != yScale) {
86
87 fPivot = pivot;
88 fTranslation = translation;
89 fRotation = rotation;
90 fXScale = xScale;
91 fYScale = yScale;
92
93 _UpdateMatrix();
94 }
95 }
96
97
98 // SetPivot
99 void
SetPivot(BPoint pivot)100 ChannelTransform::SetPivot(BPoint pivot)
101 {
102 if (pivot == fPivot)
103 return;
104
105 fPivot = pivot;
106
107 _UpdateMatrix();
108 }
109
110
111 // TranslateBy
112 void
TranslateBy(BPoint offset)113 ChannelTransform::TranslateBy(BPoint offset)
114 {
115 if (offset.x == 0.0 && offset.y == 0.0)
116 return;
117
118 fTranslation += offset;
119
120 _UpdateMatrix();
121 }
122
123
124 // RotateBy
125 /*! Converts a rotation in world coordinates into
126 a combined local rotation and a translation.
127 */
128 void
RotateBy(BPoint origin,double degrees)129 ChannelTransform::RotateBy(BPoint origin, double degrees)
130 {
131 if (degrees == 0.0)
132 return;
133
134 origin -= fPivot;
135
136 fRotation += degrees;
137
138 // rotate fTranslation
139 double xOffset = fTranslation.x - origin.x;
140 double yOffset = fTranslation.y - origin.y;
141
142 agg::trans_affine_rotation m(degrees * M_PI / 180.0);
143 m.transform(&xOffset, &yOffset);
144
145 fTranslation.x = origin.x + xOffset;
146 fTranslation.y = origin.y + yOffset;
147
148 _UpdateMatrix();
149 }
150
151
152 // RotateBy
153 void
RotateBy(double degrees)154 ChannelTransform::RotateBy(double degrees)
155 {
156 if (degrees == 0.0)
157 return;
158
159 fRotation += degrees;
160
161 _UpdateMatrix();
162 }
163
164
165 // ScaleBy
166 //
167 // converts a scalation in world coordinates into
168 // a combined local scalation and a translation
169 void
ScaleBy(BPoint origin,double xScale,double yScale)170 ChannelTransform::ScaleBy(BPoint origin, double xScale, double yScale)
171 {
172 // TODO: Untested?
173 if (xScale == 1.0 && yScale == 1.0)
174 return;
175
176 fXScale *= xScale;
177 fYScale *= yScale;
178
179 // scale fTranslation
180 double xOffset = fTranslation.x - origin.x;
181 double yOffset = fTranslation.y - origin.y;
182
183 fTranslation.x = origin.x + (xOffset * xScale);
184 fTranslation.y = origin.y + (yOffset * yScale);
185
186 _UpdateMatrix();
187 }
188
189 // ScaleBy
190 void
ScaleBy(double xScale,double yScale)191 ChannelTransform::ScaleBy(double xScale, double yScale)
192 {
193 if (xScale == 1.0 && yScale == 1.0)
194 return;
195
196 fXScale *= xScale;
197 fYScale *= yScale;
198
199 _UpdateMatrix();
200 }
201
202
203 // SetTranslationAndScale
204 void
SetTranslationAndScale(BPoint offset,double xScale,double yScale)205 ChannelTransform::SetTranslationAndScale(BPoint offset, double xScale,
206 double yScale)
207 {
208 if (fTranslation == offset && fXScale == xScale && fYScale == yScale)
209 return;
210
211 fTranslation = offset;
212
213 fXScale = xScale;
214 fYScale = yScale;
215
216 _UpdateMatrix();
217 }
218
219
220 // Reset
221 void
Reset()222 ChannelTransform::Reset()
223 {
224 SetTransformation(B_ORIGIN, B_ORIGIN, 0.0, 1.0, 1.0);
225 }
226
227
228 // =
229 ChannelTransform&
operator =(const ChannelTransform & other)230 ChannelTransform::operator=(const ChannelTransform& other)
231 {
232 fTranslation = other.fTranslation;
233 fRotation = other.fRotation;
234 fXScale = other.fXScale;
235 fYScale = other.fYScale;
236
237 Transformable::operator=(other);
238
239 return *this;
240 }
241
242
243 // _UpdateMatrix
244 void
_UpdateMatrix()245 ChannelTransform::_UpdateMatrix()
246 {
247 // fix up scales in case any is zero
248 double xScale = fXScale;
249 if (xScale == 0.0)
250 xScale = 0.000001;
251 double yScale = fYScale;
252 if (yScale == 0.0)
253 yScale = 0.000001;
254
255 // start clean
256 reset();
257 // the "pivot" is like the offset from world to local
258 // coordinate system and is the center for rotation and scale
259 multiply(agg::trans_affine_translation(-fPivot.x, -fPivot.y));
260 multiply(agg::trans_affine_scaling(xScale, yScale));
261 multiply(agg::trans_affine_rotation(fRotation * M_PI / 180.0));
262
263 multiply(agg::trans_affine_translation(fPivot.x + fTranslation.x,
264 fPivot.y + fTranslation.y));
265
266 // call hook function
267 Update();
268 }
269
270