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