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