xref: /haiku/src/libs/icon/transformable/Transformable.cpp (revision 1564b19c80637a2ba13949db0056215699b7b418)
1 /*
2  * Copyright 2006, 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 	reset();
91 }
92 
93 // Invert
94 void
95 Transformable::Invert()
96 {
97 	invert();
98 }
99 
100 // IsIdentity
101 bool
102 Transformable::IsIdentity() const
103 {
104 	double m[matrix_size];
105 	store_to(m);
106 	if (m[0] == 1.0 &&
107 		m[1] == 0.0 &&
108 		m[2] == 0.0 &&
109 		m[3] == 1.0 &&
110 		m[4] == 0.0 &&
111 		m[5] == 0.0)
112 		return true;
113 	return false;
114 }
115 
116 // IsTranslationOnly
117 bool
118 Transformable::IsTranslationOnly() const
119 {
120 	double m[matrix_size];
121 	store_to(m);
122 	if (m[0] == 1.0 &&
123 		m[1] == 0.0 &&
124 		m[2] == 0.0 &&
125 		m[3] == 1.0)
126 		return true;
127 	return false;
128 }
129 
130 // IsNotDistorted
131 bool
132 Transformable::IsNotDistorted() const
133 {
134 	double m[matrix_size];
135 	store_to(m);
136 	return (m[0] == m[3]);
137 }
138 
139 // IsValid
140 bool
141 Transformable::IsValid() const
142 {
143 	double m[matrix_size];
144 	store_to(m);
145 	return ((m[0] * m[3] - m[1] * m[2]) != 0.0);
146 }
147 
148 // operator==
149 bool
150 Transformable::operator==(const Transformable& other) const
151 {
152 	double m1[matrix_size];
153 	other.store_to(m1);
154 	double m2[matrix_size];
155 	store_to(m2);
156 	return memcmp(m1, m2, sizeof(m1)) == 0;
157 }
158 
159 // operator!=
160 bool
161 Transformable::operator!=(const Transformable& other) const
162 {
163 	return !(*this == other);
164 }
165 
166 // Transform
167 void
168 Transformable::Transform(double* x, double* y) const
169 {
170 	transform(x, y);
171 }
172 
173 // Transform
174 void
175 Transformable::Transform(BPoint* point) const
176 {
177 	if (point) {
178 		double x = point->x;
179 		double y = point->y;
180 
181 		transform(&x, &y);
182 
183 		point->x = x;
184 		point->y = y;
185 	}
186 }
187 
188 // Transform
189 BPoint
190 Transformable::Transform(const BPoint& point) const
191 {
192 	BPoint p(point);
193 	Transform(&p);
194 	return p;
195 }
196 
197 // InverseTransform
198 void
199 Transformable::InverseTransform(double* x, double* y) const
200 {
201 	inverse_transform(x, y);
202 }
203 
204 // InverseTransform
205 void
206 Transformable::InverseTransform(BPoint* point) const
207 {
208 	if (point) {
209 		double x = point->x;
210 		double y = point->y;
211 
212 		inverse_transform(&x, &y);
213 
214 		point->x = x;
215 		point->y = y;
216 	}
217 }
218 
219 // InverseTransform
220 BPoint
221 Transformable::InverseTransform(const BPoint& point) const
222 {
223 	BPoint p(point);
224 	InverseTransform(&p);
225 	return p;
226 }
227 
228 inline float
229 min4(float a, float b, float c, float d)
230 {
231 	return min_c(a, min_c(b, min_c(c, d)));
232 }
233 
234 inline float
235 max4(float a, float b, float c, float d)
236 {
237 	return max_c(a, max_c(b, max_c(c, d)));
238 }
239 
240 // TransformBounds
241 BRect
242 Transformable::TransformBounds(BRect bounds) const
243 {
244 	if (bounds.IsValid()) {
245 		BPoint lt(bounds.left, bounds.top);
246 		BPoint rt(bounds.right, bounds.top);
247 		BPoint lb(bounds.left, bounds.bottom);
248 		BPoint rb(bounds.right, bounds.bottom);
249 
250 		Transform(&lt);
251 		Transform(&rt);
252 		Transform(&lb);
253 		Transform(&rb);
254 
255 		return BRect(floorf(min4(lt.x, rt.x, lb.x, rb.x)),
256 					 floorf(min4(lt.y, rt.y, lb.y, rb.y)),
257 					 ceilf(max4(lt.x, rt.x, lb.x, rb.x)),
258 					 ceilf(max4(lt.y, rt.y, lb.y, rb.y)));
259 	}
260 	return bounds;
261 }
262 
263 // TranslateBy
264 void
265 Transformable::TranslateBy(BPoint offset)
266 {
267 	if (offset.x != 0.0 || offset.y != 0.0) {
268 		multiply(agg::trans_affine_translation(offset.x, offset.y));
269 		TransformationChanged();
270 	}
271 }
272 
273 // RotateBy
274 void
275 Transformable::RotateBy(BPoint origin, double degrees)
276 {
277 	if (degrees != 0.0) {
278 		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
279 		multiply(agg::trans_affine_rotation(degrees * (PI / 180.0)));
280 		multiply(agg::trans_affine_translation(origin.x, origin.y));
281 		TransformationChanged();
282 	}
283 }
284 
285 // ScaleBy
286 void
287 Transformable::ScaleBy(BPoint origin, double xScale, double yScale)
288 {
289 	if (xScale != 1.0 || yScale != 1.0) {
290 		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
291 		multiply(agg::trans_affine_scaling(xScale, yScale));
292 		multiply(agg::trans_affine_translation(origin.x, origin.y));
293 		TransformationChanged();
294 	}
295 }
296 
297 // ShearBy
298 void
299 Transformable::ShearBy(BPoint origin, double xShear, double yShear)
300 {
301 	if (xShear != 0.0 || yShear != 0.0) {
302 		multiply(agg::trans_affine_translation(-origin.x, -origin.y));
303 		multiply(agg::trans_affine_skewing(xShear, yShear));
304 		multiply(agg::trans_affine_translation(origin.x, origin.y));
305 		TransformationChanged();
306 	}
307 }
308 
309 // TransformationChanged
310 void
311 Transformable::TransformationChanged()
312 {
313 	// default implementation doesn't care
314 }
315 
316