xref: /haiku/src/libs/icon/transformable/Transformable.cpp (revision 508f54795f39c3e7552d87c95aae9dd8ec6f505b)
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 "Transformable.h"
10 
11 #include <stdio.h>
12 #include <string.h>
13 
14 // constructor
15 Transformable::Transformable()
16 	: agg::trans_affine()
17 {
18 }
19 
20 // copy constructor
21 Transformable::Transformable(const Transformable& other)
22 	: agg::trans_affine(other)
23 {
24 }
25 
26 // destructor
27 Transformable::~Transformable()
28 {
29 }
30 
31 // StoreTo
32 void
33 Transformable::StoreTo(double matrix[matrix_size]) const
34 {
35 	store_to(matrix);
36 }
37 
38 // LoadFrom
39 void
40 Transformable::LoadFrom(const double matrix[matrix_size])
41 {
42 	// before calling the potentially heavy TransformationChanged()
43 	// hook function, make sure that the transformation
44 	// really changed
45 	Transformable t;
46 	t.load_from(matrix);
47 	if (*this != t) {
48 		load_from(matrix);
49 		TransformationChanged();
50 	}
51 }
52 
53 // SetTransform
54 void
55 Transformable::SetTransform(const Transformable& other)
56 {
57 	if (*this != other) {
58 		*this = other;
59 		TransformationChanged();
60 	}
61 }
62 
63 // operator=
64 Transformable&
65 Transformable::operator=(const Transformable& other)
66 {
67 	if (other != *this) {
68 		reset();
69 		multiply(other);
70 		TransformationChanged();
71 	}
72 	return *this;
73 }
74 
75 // Multiply
76 Transformable&
77 Transformable::Multiply(const Transformable& other)
78 {
79 	if (!other.IsIdentity()) {
80 		multiply(other);
81 		TransformationChanged();
82 	}
83 	return *this;
84 }
85 
86 // Reset
87 void
88 Transformable::Reset()
89 {
90 	if (!IsIdentity()) {
91 		reset();
92 		TransformationChanged();
93 	}
94 }
95 
96 // Invert
97 void
98 Transformable::Invert()
99 {
100 	if (!IsIdentity()) {
101 		invert();
102 		TransformationChanged();
103 	}
104 }
105 
106 // IsIdentity
107 bool
108 Transformable::IsIdentity() const
109 {
110 	double m[matrix_size];
111 	store_to(m);
112 	if (m[0] == 1.0 &&
113 		m[1] == 0.0 &&
114 		m[2] == 0.0 &&
115 		m[3] == 1.0 &&
116 		m[4] == 0.0 &&
117 		m[5] == 0.0)
118 		return true;
119 	return false;
120 }
121 
122 // IsTranslationOnly
123 bool
124 Transformable::IsTranslationOnly() const
125 {
126 	double m[matrix_size];
127 	store_to(m);
128 	if (m[0] == 1.0 &&
129 		m[1] == 0.0 &&
130 		m[2] == 0.0 &&
131 		m[3] == 1.0)
132 		return true;
133 	return false;
134 }
135 
136 // IsNotDistorted
137 bool
138 Transformable::IsNotDistorted() const
139 {
140 	double m[matrix_size];
141 	store_to(m);
142 	return (m[0] == m[3]);
143 }
144 
145 // IsValid
146 bool
147 Transformable::IsValid() const
148 {
149 	double m[matrix_size];
150 	store_to(m);
151 	return ((m[0] * m[3] - m[1] * m[2]) != 0.0);
152 }
153 
154 // operator==
155 bool
156 Transformable::operator==(const Transformable& other) const
157 {
158 	double m1[matrix_size];
159 	other.store_to(m1);
160 	double m2[matrix_size];
161 	store_to(m2);
162 	return memcmp(m1, m2, sizeof(m1)) == 0;
163 }
164 
165 // operator!=
166 bool
167 Transformable::operator!=(const Transformable& other) const
168 {
169 	return !(*this == other);
170 }
171 
172 // Transform
173 void
174 Transformable::Transform(double* x, double* y) const
175 {
176 	transform(x, y);
177 }
178 
179 // Transform
180 void
181 Transformable::Transform(BPoint* point) const
182 {
183 	if (point) {
184 		double x = point->x;
185 		double y = point->y;
186 
187 		transform(&x, &y);
188 
189 		point->x = x;
190 		point->y = y;
191 	}
192 }
193 
194 // Transform
195 BPoint
196 Transformable::Transform(const BPoint& point) const
197 {
198 	BPoint p(point);
199 	Transform(&p);
200 	return p;
201 }
202 
203 // InverseTransform
204 void
205 Transformable::InverseTransform(double* x, double* y) const
206 {
207 	inverse_transform(x, y);
208 }
209 
210 // InverseTransform
211 void
212 Transformable::InverseTransform(BPoint* point) const
213 {
214 	if (point) {
215 		double x = point->x;
216 		double y = point->y;
217 
218 		inverse_transform(&x, &y);
219 
220 		point->x = x;
221 		point->y = y;
222 	}
223 }
224 
225 // InverseTransform
226 BPoint
227 Transformable::InverseTransform(const BPoint& point) const
228 {
229 	BPoint p(point);
230 	InverseTransform(&p);
231 	return p;
232 }
233 
234 inline float
235 min4(float a, float b, float c, float d)
236 {
237 	return min_c(a, min_c(b, min_c(c, d)));
238 }
239 
240 inline float
241 max4(float a, float b, float c, float d)
242 {
243 	return max_c(a, max_c(b, max_c(c, d)));
244 }
245 
246 // TransformBounds
247 BRect
248 Transformable::TransformBounds(BRect bounds) const
249 {
250 	if (bounds.IsValid()) {
251 		BPoint lt(bounds.left, bounds.top);
252 		BPoint rt(bounds.right, bounds.top);
253 		BPoint lb(bounds.left, bounds.bottom);
254 		BPoint rb(bounds.right, bounds.bottom);
255 
256 		Transform(&lt);
257 		Transform(&rt);
258 		Transform(&lb);
259 		Transform(&rb);
260 
261 		return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)),
262 					 floorf(min4(lt.y, rt.y, lb.y, rb.y)),
263 					 ceilf(max4(lt.x, rt.x, lb.x, rb.x)),
264 					 ceilf(max4(lt.y, rt.y, lb.y, rb.y)));
265 	}
266 	return bounds;
267 }
268 
269 // TranslateBy
270 void
271 Transformable::TranslateBy(BPoint offset)
272 {
273 	if (offset.x != 0.0 || offset.y != 0.0) {
274 		multiply(agg::trans_affine_translation(offset.x, offset.y));
275 		TransformationChanged();
276 	}
277 }
278 
279 // RotateBy
280 void
281 Transformable::RotateBy(BPoint origin, double degrees)
282 {
283 	if (degrees != 0.0) {
284 		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
285 		multiply(agg::trans_affine_rotation(degrees * (M_PI / 180.0)));
286 		multiply(agg::trans_affine_translation(origin.x, origin.y));
287 		TransformationChanged();
288 	}
289 }
290 
291 // ScaleBy
292 void
293 Transformable::ScaleBy(BPoint origin, double xScale, double yScale)
294 {
295 	if (xScale != 1.0 || yScale != 1.0) {
296 		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
297 		multiply(agg::trans_affine_scaling(xScale, yScale));
298 		multiply(agg::trans_affine_translation(origin.x, origin.y));
299 		TransformationChanged();
300 	}
301 }
302 
303 // ShearBy
304 void
305 Transformable::ShearBy(BPoint origin, double xShear, double yShear)
306 {
307 	if (xShear != 0.0 || yShear != 0.0) {
308 		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
309 		multiply(agg::trans_affine_skewing(xShear, yShear));
310 		multiply(agg::trans_affine_translation(origin.x, origin.y));
311 		TransformationChanged();
312 	}
313 }
314 
315 // TransformationChanged
316 void
317 Transformable::TransformationChanged()
318 {
319 	// default implementation doesn't care
320 }
321 
322