xref: /haiku/src/apps/icon-o-matic/transformable/ChannelTransform.cpp (revision 14d604ddfa3cc7dc7a5a5c92e03e17956239f06b)
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