1 /*
2 * Copyright 2008-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Stephen Deken, stephen.deken@gmail.com
7 * Stephan Aßmus <superstippi@gmx.de>
8 */
9 //----------------------------------------------------------------------------
10 // Anti-Grain Geometry - Version 2.4
11 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
12 //
13 // Permission to copy, use, modify, sell and distribute this software
14 // is granted provided this copyright notice appears in all copies.
15 // This software is provided "as is" without express or implied
16 // warranty, and with no claim as to its suitability for any purpose.
17 //
18 //----------------------------------------------------------------------------
19 // Contact: mcseem@antigrain.com
20 // mcseemagg@yahoo.com
21 // http://www.antigrain.com
22 //----------------------------------------------------------------------------
23 #ifndef _AFFINE_TRANSFORM_H
24 #define _AFFINE_TRANSFORM_H
25
26
27 #include <Flattenable.h>
28 #include <Point.h>
29
30 #include <math.h>
31
32
33 class BAffineTransform : public BFlattenable {
34 public:
35
36 #if __cplusplus < 201103L
37 static const double kDefaultEpsilon = 1e-14;
38 #else
39 static constexpr double kDefaultEpsilon = 1e-14;
40 #endif
41
42 public:
43 BAffineTransform();
44 BAffineTransform(double sx, double shy,
45 double shx, double sy, double tx,
46 double ty);
47 BAffineTransform(
48 const BAffineTransform& copyFrom);
49 virtual ~BAffineTransform();
50
51 // BFlattenable interface
52 virtual bool IsFixedSize() const;
53 virtual type_code TypeCode() const;
54 virtual ssize_t FlattenedSize() const;
55 virtual status_t Flatten(void* buffer,
56 ssize_t size) const;
57 virtual status_t Unflatten(type_code code,
58 const void* buffer, ssize_t size);
59
60 // Construction
61 static BAffineTransform AffineTranslation(double x, double y);
62 static BAffineTransform AffineRotation(double angle);
63 static BAffineTransform AffineScaling(double x, double y);
64 static BAffineTransform AffineScaling(double scale);
65 static BAffineTransform AffineShearing(double x, double y);
66
67 // Application
68 inline void Apply(double* x, double* y) const;
69 inline void ApplyInverse(double* x, double* y) const;
70
71 BPoint Apply(const BPoint& point) const;
72 BPoint ApplyInverse(const BPoint& point) const;
73
74 void Apply(BPoint* point) const;
75 void ApplyInverse(BPoint* point) const;
76
77 void Apply(BPoint* points, uint32 count) const;
78 void ApplyInverse(BPoint* points,
79 uint32 count) const;
80
81 // Translation
82 inline const BAffineTransform& TranslateBy(double x, double y);
83 const BAffineTransform& TranslateBy(const BPoint& delta);
84
85 inline const BAffineTransform& PreTranslateBy(double x, double y);
86
87 BAffineTransform TranslateByCopy(double x, double y) const;
88 BAffineTransform TranslateByCopy(const BPoint& delta) const;
89
90 // const BAffineTransform& SetTranslation(double x, double y);
91
92 // Rotation
93 inline const BAffineTransform& RotateBy(double angle);
94 const BAffineTransform& RotateBy(const BPoint& center,
95 double angle);
96
97 inline const BAffineTransform& PreRotateBy(double angleRadians);
98
99 BAffineTransform RotateByCopy(double angle) const;
100 BAffineTransform RotateByCopy(const BPoint& center,
101 double angle) const;
102
103 // const BAffineTransform& SetRotation(double angle);
104
105 // Scaling
106 inline const BAffineTransform& ScaleBy(double scale);
107 const BAffineTransform& ScaleBy(const BPoint& center,
108 double scale);
109 inline const BAffineTransform& ScaleBy(double x, double y);
110 const BAffineTransform& ScaleBy(const BPoint& center, double x,
111 double y);
112 const BAffineTransform& ScaleBy(const BPoint& scale);
113 const BAffineTransform& ScaleBy(const BPoint& center,
114 const BPoint& scale);
115
116 inline const BAffineTransform& PreScaleBy(double x, double y);
117
118 BAffineTransform ScaleByCopy(double scale) const;
119 BAffineTransform ScaleByCopy(const BPoint& center,
120 double scale) const;
121 BAffineTransform ScaleByCopy(double x, double y) const;
122 BAffineTransform ScaleByCopy(const BPoint& center,
123 double x, double y) const;
124 BAffineTransform ScaleByCopy(const BPoint& scale) const;
125 BAffineTransform ScaleByCopy(const BPoint& center,
126 const BPoint& scale) const;
127
128 const BAffineTransform& SetScale(double scale);
129 const BAffineTransform& SetScale(double x, double y);
130
131 // Shearing
132 inline const BAffineTransform& ShearBy(double x, double y);
133 const BAffineTransform& ShearBy(const BPoint& center, double x,
134 double y);
135 const BAffineTransform& ShearBy(const BPoint& shear);
136 const BAffineTransform& ShearBy(const BPoint& center,
137 const BPoint& shear);
138
139 BAffineTransform ShearByCopy(double x, double y) const;
140 BAffineTransform ShearByCopy(const BPoint& center,
141 double x, double y) const;
142 BAffineTransform ShearByCopy(const BPoint& shear) const;
143 BAffineTransform ShearByCopy(const BPoint& center,
144 const BPoint& shear) const;
145
146 // const BAffineTransform& SetShear(double x, double y);
147
148 // Multiplication
149 inline const BAffineTransform& Multiply(const BAffineTransform& other);
150 const BAffineTransform& PreMultiply(const BAffineTransform& other);
151 inline const BAffineTransform& MultiplyInverse(
152 const BAffineTransform& other);
153 inline const BAffineTransform& PreMultiplyInverse(
154 const BAffineTransform& other);
155
156 // Operators
157 inline BAffineTransform& operator=(
158 const BAffineTransform& copyFrom);
159
160 inline bool operator==(
161 const BAffineTransform& other) const;
162 inline bool operator!=(
163 const BAffineTransform& other) const;
164
165 inline const BAffineTransform& operator*=(const BAffineTransform& other);
166 inline const BAffineTransform& operator/=(const BAffineTransform& other);
167
168 inline BAffineTransform operator*(
169 const BAffineTransform& other) const;
170 inline BAffineTransform operator/(
171 const BAffineTransform& other) const;
172
173 inline BAffineTransform operator~() const;
174
175 // Utility
176 bool IsValid(double epsilon
177 = kDefaultEpsilon) const;
178 bool IsIdentity(double epsilon
179 = kDefaultEpsilon) const;
180 bool IsDilation(double epsilon
181 = kDefaultEpsilon) const;
182 bool IsEqual(const BAffineTransform& other,
183 double epsilon
184 = kDefaultEpsilon) const;
185
186 const BAffineTransform& Invert();
187 const BAffineTransform& FlipX();
188 const BAffineTransform& FlipY();
189 const BAffineTransform& Reset();
190
191 inline double Determinant() const;
192 inline double InverseDeterminant() const;
193 void GetTranslation(double* tx,
194 double* ty) const;
195 double Rotation() const;
196 double Scale() const;
197 void GetScale(double* sx, double* sy) const;
198 void GetScaleAbs(double* sx,
199 double* sy) const;
200 bool GetAffineParameters(double* translationX,
201 double* translationY, double* rotation,
202 double* scaleX, double* scaleY,
203 double* shearX, double* shearY) const;
204
205 public:
206 double sx;
207 double shy;
208 double shx;
209 double sy;
210 double tx;
211 double ty;
212 };
213
214
215 extern const BAffineTransform B_AFFINE_IDENTITY_TRANSFORM;
216
217
218 // #pragma mark - inline methods
219
220
221 inline void
Apply(double * x,double * y)222 BAffineTransform::Apply(double* x, double* y) const
223 {
224 double tmp = *x;
225 *x = tmp * sx + *y * shx + tx;
226 *y = tmp * shy + *y * sy + ty;
227 }
228
229
230 inline void
ApplyInverse(double * x,double * y)231 BAffineTransform::ApplyInverse(double* x, double* y) const
232 {
233 double d = InverseDeterminant();
234 double a = (*x - tx) * d;
235 double b = (*y - ty) * d;
236 *x = a * sy - b * shx;
237 *y = b * sx - a * shy;
238 }
239
240
241 // #pragma mark -
242
243
244 inline const BAffineTransform&
TranslateBy(double x,double y)245 BAffineTransform::TranslateBy(double x, double y)
246 {
247 tx += x;
248 ty += y;
249 return *this;
250 }
251
252
253 inline const BAffineTransform&
PreTranslateBy(double x,double y)254 BAffineTransform::PreTranslateBy(double x, double y)
255 {
256 tx += x * sx + y * shx;
257 ty += x * shy + y * sy;
258 return *this;
259 }
260
261
262 inline const BAffineTransform&
RotateBy(double angle)263 BAffineTransform::RotateBy(double angle)
264 {
265 double ca = cos(angle);
266 double sa = sin(angle);
267 double t0 = sx * ca - shy * sa;
268 double t2 = shx * ca - sy * sa;
269 double t4 = tx * ca - ty * sa;
270 shy = sx * sa + shy * ca;
271 sy = shx * sa + sy * ca;
272 ty = tx * sa + ty * ca;
273 sx = t0;
274 shx = t2;
275 tx = t4;
276 return *this;
277 }
278
279
280 inline const BAffineTransform&
PreRotateBy(double angle)281 BAffineTransform::PreRotateBy(double angle)
282 {
283 double ca = cos(angle);
284 double sa = sin(angle);
285 double newSx = sx * ca + shx * sa;
286 double newSy = -shy * sa + sy * ca;
287 shy = shy * ca + sy * sa;
288 shx = -sx * sa + shx * ca;
289 sx = newSx;
290 sy = newSy;
291 return *this;
292 }
293
294
295 inline const BAffineTransform&
ScaleBy(double x,double y)296 BAffineTransform::ScaleBy(double x, double y)
297 {
298 double mm0 = x;
299 // Possible hint for the optimizer
300 double mm3 = y;
301 sx *= mm0;
302 shx *= mm0;
303 tx *= mm0;
304 shy *= mm3;
305 sy *= mm3;
306 ty *= mm3;
307 return *this;
308 }
309
310
311 inline const BAffineTransform&
ScaleBy(double s)312 BAffineTransform::ScaleBy(double s)
313 {
314 double m = s;
315 // Possible hint for the optimizer
316 sx *= m;
317 shx *= m;
318 tx *= m;
319 shy *= m;
320 sy *= m;
321 ty *= m;
322 return *this;
323 }
324
325
326 inline const BAffineTransform&
PreScaleBy(double x,double y)327 BAffineTransform::PreScaleBy(double x, double y)
328 {
329 sx *= x;
330 shx *= y;
331 shy *= x;
332 sy *= y;
333 return *this;
334 }
335
336
337 inline const BAffineTransform&
ShearBy(double x,double y)338 BAffineTransform::ShearBy(double x, double y)
339 {
340 BAffineTransform shearTransform = AffineShearing(x, y);
341 return PreMultiply(shearTransform);
342 }
343
344
345 // #pragma mark -
346
347
348 inline const BAffineTransform&
Multiply(const BAffineTransform & other)349 BAffineTransform::Multiply(const BAffineTransform& other)
350 {
351 BAffineTransform t(other);
352 return *this = t.PreMultiply(*this);
353 }
354
355
356 inline const BAffineTransform&
MultiplyInverse(const BAffineTransform & other)357 BAffineTransform::MultiplyInverse(const BAffineTransform& other)
358 {
359 BAffineTransform t(other);
360 t.Invert();
361 return Multiply(t);
362 }
363
364
365 inline const BAffineTransform&
PreMultiplyInverse(const BAffineTransform & other)366 BAffineTransform::PreMultiplyInverse(const BAffineTransform& other)
367 {
368 BAffineTransform t(other);
369 t.Invert();
370 return *this = t.Multiply(*this);
371 }
372
373
374 // #pragma mark -
375
376
377 inline BAffineTransform&
378 BAffineTransform::operator=(const BAffineTransform& other)
379 {
380 sx = other.sx;
381 shy = other.shy;
382 shx = other.shx;
383 sy = other.sy;
384 tx = other.tx;
385 ty = other.ty;
386 return *this;
387 }
388
389 inline bool
390 BAffineTransform::operator==(const BAffineTransform& other) const
391 {
392 return IsEqual(other);
393 }
394
395 inline bool
396 BAffineTransform::operator!=(const BAffineTransform& other) const
397 {
398 return !IsEqual(other);
399 }
400
401
402 inline const BAffineTransform&
403 BAffineTransform::operator*=(const BAffineTransform& other)
404 {
405 return Multiply(other);
406 }
407
408
409 inline const BAffineTransform&
410 BAffineTransform::operator/=(const BAffineTransform& other)
411 {
412 return MultiplyInverse(other);
413 }
414
415
416 inline BAffineTransform
417 BAffineTransform::operator*(const BAffineTransform& other) const
418 {
419 return BAffineTransform(*this).Multiply(other);
420 }
421
422
423 inline BAffineTransform
424 BAffineTransform::operator/(const BAffineTransform& other) const
425 {
426 return BAffineTransform(*this).MultiplyInverse(other);
427 }
428
429
430 inline BAffineTransform
431 BAffineTransform::operator~() const
432 {
433 BAffineTransform result(*this);
434 return result.Invert();
435 }
436
437
438 // #pragma mark -
439
440
441 inline double
Determinant()442 BAffineTransform::Determinant() const
443 {
444 return sx * sy - shy * shx;
445 }
446
447
448 inline double
InverseDeterminant()449 BAffineTransform::InverseDeterminant() const
450 {
451 return 1.0 / (sx * sy - shy * shx);
452 }
453
454
455 #endif // _AFFINE_TRANSFORM_H
456