xref: /haiku/src/apps/icon-o-matic/transformable/ChannelTransform.cpp (revision b55a57da7173b9af0432bd3e148d03f06161d036)
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
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
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
41 ChannelTransform::~ChannelTransform()
42 {
43 }
44 
45 
46 // SetTransformation
47 void
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
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
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
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
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
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
170 //ChannelTransform::ScaleBy(BPoint origin, double xScale, double yScale)
171 //{
172 //	if (xScale == 1.0 && yScale == 1.0)
173 //		return;
174 //
175 //	fXScale *= xScale;
176 //	fYScale *= yScale;
177 //
178 //	// scale fTranslation
179 //	double xOffset = fTranslation.x - origin.x;
180 //	double yOffset = fTranslation.y - origin.y;
181 //
182 //	fTranslation.x = origin.x + (xOffset * xScale);
183 //	fTranslation.y = origin.y + (yOffset * yScale);
184 //
185 //	_UpdateMatrix();
186 //}
187 
188 // ScaleBy
189 void
190 ChannelTransform::ScaleBy(double xScale, double yScale)
191 {
192 	if (xScale == 1.0 && yScale == 1.0)
193 		return;
194 
195 	fXScale *= xScale;
196 	fYScale *= yScale;
197 
198 	_UpdateMatrix();
199 }
200 
201 
202 // SetTranslationAndScale
203 void
204 ChannelTransform::SetTranslationAndScale(BPoint offset, double xScale,
205 	double yScale)
206 {
207 	if (fTranslation == offset && fXScale == xScale && fYScale == yScale)
208 		return;
209 
210 	fTranslation = offset;
211 
212 	fXScale = xScale;
213 	fYScale = yScale;
214 
215 	_UpdateMatrix();
216 }
217 
218 
219 // Reset
220 void
221 ChannelTransform::Reset()
222 {
223 	SetTransformation(B_ORIGIN, B_ORIGIN, 0.0, 1.0, 1.0);
224 }
225 
226 
227 // =
228 ChannelTransform&
229 ChannelTransform::operator=(const ChannelTransform& other)
230 {
231 	fTranslation = other.fTranslation;
232 	fRotation = other.fRotation;
233 	fXScale = other.fXScale;
234 	fYScale = other.fYScale;
235 
236 	Transformable::operator=(other);
237 
238 	return *this;
239 }
240 
241 
242 // _UpdateMatrix
243 void
244 ChannelTransform::_UpdateMatrix()
245 {
246 	// fix up scales in case any is zero
247 	double xScale = fXScale;
248 	if (xScale == 0.0)
249 		xScale = 0.000001;
250 	double yScale = fYScale;
251 	if (yScale == 0.0)
252 		yScale = 0.000001;
253 
254 	// start clean
255 	reset();
256 	// the "pivot" is like the offset from world to local
257 	// coordinate system and is the center for rotation and scale
258 	multiply(agg::trans_affine_translation(-fPivot.x, -fPivot.y));
259 	multiply(agg::trans_affine_scaling(xScale, yScale));
260 	multiply(agg::trans_affine_rotation(fRotation * M_PI / 180.0));
261 
262 	multiply(agg::trans_affine_translation(fPivot.x + fTranslation.x,
263 		fPivot.y + fTranslation.y));
264 
265 	// call hook function
266 	Update();
267 }
268 
269