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
24 #include <AffineTransform.h>
25
26 #include <TypeConstants.h>
27
28
29 const BAffineTransform B_AFFINE_IDENTITY_TRANSFORM;
30
31
BAffineTransform()32 BAffineTransform::BAffineTransform()
33 :
34 sx(1.0),
35 shy(0.0),
36 shx(0.0),
37 sy(1.0),
38 tx(0.0),
39 ty(0.0)
40 {
41 }
42
43
BAffineTransform(double sx,double shy,double shx,double sy,double tx,double ty)44 BAffineTransform::BAffineTransform(double sx, double shy, double shx,
45 double sy, double tx, double ty)
46 :
47 sx(sx),
48 shy(shy),
49 shx(shx),
50 sy(sy),
51 tx(tx),
52 ty(ty)
53 {
54 }
55
56
BAffineTransform(const BAffineTransform & other)57 BAffineTransform::BAffineTransform(const BAffineTransform& other)
58 :
59 sx(other.sx),
60 shy(other.shy),
61 shx(other.shx),
62 sy(other.sy),
63 tx(other.tx),
64 ty(other.ty)
65 {
66 }
67
68
~BAffineTransform()69 BAffineTransform::~BAffineTransform()
70 {
71 }
72
73
74 // #pragma mark -
75
76
77 bool
IsFixedSize() const78 BAffineTransform::IsFixedSize() const
79 {
80 return true;
81 }
82
83
84 type_code
TypeCode() const85 BAffineTransform::TypeCode() const
86 {
87 return B_AFFINE_TRANSFORM_TYPE;
88 }
89
90
91 ssize_t
FlattenedSize() const92 BAffineTransform::FlattenedSize() const
93 {
94 return 6 * sizeof(double);
95 }
96
97
98 status_t
Flatten(void * _buffer,ssize_t size) const99 BAffineTransform::Flatten(void* _buffer, ssize_t size) const
100 {
101 if (_buffer == NULL || size < BAffineTransform::FlattenedSize())
102 return B_BAD_VALUE;
103
104 double* buffer = reinterpret_cast<double*>(_buffer);
105
106 buffer[0] = sx;
107 buffer[1] = shy;
108 buffer[2] = shx;
109 buffer[3] = sy;
110 buffer[4] = tx;
111 buffer[5] = ty;
112
113 return B_OK;
114 }
115
116
117 status_t
Unflatten(type_code code,const void * _buffer,ssize_t size)118 BAffineTransform::Unflatten(type_code code, const void* _buffer, ssize_t size)
119 {
120 if (_buffer == NULL || size < BAffineTransform::FlattenedSize()
121 || code != BAffineTransform::TypeCode()) {
122 return B_BAD_VALUE;
123 }
124
125 const double* buffer = reinterpret_cast<const double*>(_buffer);
126
127 sx = buffer[0];
128 shy = buffer[1];
129 shx = buffer[2];
130 sy = buffer[3];
131 tx = buffer[4];
132 ty = buffer[5];
133
134 return B_OK;
135 }
136
137
138 // #pragma mark -
139
140
141 /*static*/ BAffineTransform
AffineTranslation(double x,double y)142 BAffineTransform::AffineTranslation(double x, double y)
143 {
144 return BAffineTransform(1.0, 0.0, 0.0, 1.0, x, y);
145 }
146
147
148 /*static*/ BAffineTransform
AffineRotation(double angle)149 BAffineTransform::AffineRotation(double angle)
150 {
151 return BAffineTransform(cos(angle), sin(angle), -sin(angle), cos(angle),
152 0.0, 0.0);
153 }
154
155
156 /*static*/ BAffineTransform
AffineScaling(double x,double y)157 BAffineTransform::AffineScaling(double x, double y)
158 {
159 return BAffineTransform(x, 0.0, 0.0, y, 0.0, 0.0);
160 }
161
162
163 /*static*/ BAffineTransform
AffineScaling(double scale)164 BAffineTransform::AffineScaling(double scale)
165 {
166 return BAffineTransform(scale, 0.0, 0.0, scale, 0.0, 0.0);
167 }
168
169
170 /*static*/ BAffineTransform
AffineShearing(double x,double y)171 BAffineTransform::AffineShearing(double x, double y)
172 {
173 return BAffineTransform(1.0, tan(y), tan(x), 1.0, 0.0, 0.0);
174 }
175
176
177 // #pragma mark -
178
179
180 BPoint
Apply(const BPoint & point) const181 BAffineTransform::Apply(const BPoint& point) const
182 {
183 double x = point.x;
184 double y = point.y;
185 Apply(&x, &y);
186 return BPoint(x, y);
187 }
188
189
190 BPoint
ApplyInverse(const BPoint & point) const191 BAffineTransform::ApplyInverse(const BPoint& point) const
192 {
193 double x = point.x;
194 double y = point.y;
195 ApplyInverse(&x, &y);
196 return BPoint(x, y);
197 }
198
199
200 void
Apply(BPoint * point) const201 BAffineTransform::Apply(BPoint* point) const
202 {
203 if (point == NULL)
204 return;
205 double x = point->x;
206 double y = point->y;
207 Apply(&x, &y);
208 point->x = x;
209 point->y = y;
210 }
211
212
213 void
ApplyInverse(BPoint * point) const214 BAffineTransform::ApplyInverse(BPoint* point) const
215 {
216 if (point == NULL)
217 return;
218 double x = point->x;
219 double y = point->y;
220 ApplyInverse(&x, &y);
221 point->x = x;
222 point->y = y;
223 }
224
225
226 void
Apply(BPoint * points,uint32 count) const227 BAffineTransform::Apply(BPoint* points, uint32 count) const
228 {
229 if (points != NULL) {
230 for (uint32 i = 0; i < count; ++i)
231 Apply(&points[i]);
232 }
233 }
234
235
236 void
ApplyInverse(BPoint * points,uint32 count) const237 BAffineTransform::ApplyInverse(BPoint* points, uint32 count) const
238 {
239 if (points != NULL) {
240 for (uint32 i = 0; i < count; ++i)
241 ApplyInverse(&points[i]);
242 }
243 }
244
245
246 // #pragma mark -
247
248
249 const BAffineTransform&
TranslateBy(const BPoint & delta)250 BAffineTransform::TranslateBy(const BPoint& delta)
251 {
252 return TranslateBy(delta.x, delta.y);
253 }
254
255
256 BAffineTransform
TranslateByCopy(double x,double y) const257 BAffineTransform::TranslateByCopy(double x, double y) const
258 {
259 BAffineTransform copy(*this);
260 copy.TranslateBy(x, y);
261 return copy;
262 }
263
264
265 BAffineTransform
TranslateByCopy(const BPoint & delta) const266 BAffineTransform::TranslateByCopy(const BPoint& delta) const
267 {
268 return TranslateByCopy(delta.x, delta.y);
269 }
270
271
272 // #pragma mark -
273
274
275 const BAffineTransform&
RotateBy(const BPoint & center,double angle)276 BAffineTransform::RotateBy(const BPoint& center, double angle)
277 {
278 TranslateBy(-center.x, -center.y);
279 RotateBy(angle);
280 return TranslateBy(center.x, center.y);
281 }
282
283
284 BAffineTransform
RotateByCopy(double angle) const285 BAffineTransform::RotateByCopy(double angle) const
286 {
287 BAffineTransform copy(*this);
288 copy.RotateBy(angle);
289 return copy;
290 }
291
292
293 BAffineTransform
RotateByCopy(const BPoint & center,double angle) const294 BAffineTransform::RotateByCopy(const BPoint& center, double angle) const
295 {
296 BAffineTransform copy(*this);
297 copy.RotateBy(center, angle);
298 return copy;
299 }
300
301
302 // #pragma mark -
303
304
305 const BAffineTransform&
ScaleBy(const BPoint & center,double scale)306 BAffineTransform::ScaleBy(const BPoint& center, double scale)
307 {
308 return ScaleBy(center, scale, scale);
309 }
310
311
312 const BAffineTransform&
ScaleBy(const BPoint & center,double x,double y)313 BAffineTransform::ScaleBy(const BPoint& center, double x, double y)
314 {
315 TranslateBy(-center.x, -center.y);
316 ScaleBy(x, y);
317 return TranslateBy(center.x, center.y);
318 }
319
320
321 const BAffineTransform&
ScaleBy(const BPoint & scale)322 BAffineTransform::ScaleBy(const BPoint& scale)
323 {
324 return ScaleBy(scale.x, scale.y);
325 }
326
327
328 const BAffineTransform&
ScaleBy(const BPoint & center,const BPoint & scale)329 BAffineTransform::ScaleBy(const BPoint& center, const BPoint& scale)
330 {
331 return ScaleBy(center, scale.x, scale.y);
332 }
333
334
335 BAffineTransform
ScaleByCopy(double scale) const336 BAffineTransform::ScaleByCopy(double scale) const
337 {
338 return ScaleByCopy(scale, scale);
339 }
340
341
342 BAffineTransform
ScaleByCopy(const BPoint & center,double scale) const343 BAffineTransform::ScaleByCopy(const BPoint& center, double scale) const
344 {
345 return ScaleByCopy(center, scale, scale);
346 }
347
348
349 BAffineTransform
ScaleByCopy(double x,double y) const350 BAffineTransform::ScaleByCopy(double x, double y) const
351 {
352 BAffineTransform copy(*this);
353 copy.ScaleBy(x, y);
354 return copy;
355 }
356
357
358 BAffineTransform
ScaleByCopy(const BPoint & center,double x,double y) const359 BAffineTransform::ScaleByCopy(const BPoint& center, double x, double y) const
360 {
361 BAffineTransform copy(*this);
362 copy.ScaleBy(center, x, y);
363 return copy;
364 }
365
366
367 BAffineTransform
ScaleByCopy(const BPoint & scale) const368 BAffineTransform::ScaleByCopy(const BPoint& scale) const
369 {
370 return ScaleByCopy(scale.x, scale.y);
371 }
372
373
374 BAffineTransform
ScaleByCopy(const BPoint & center,const BPoint & scale) const375 BAffineTransform::ScaleByCopy(const BPoint& center, const BPoint& scale) const
376 {
377 return ScaleByCopy(center, scale.x, scale.y);
378 }
379
380
381 const BAffineTransform&
SetScale(double scale)382 BAffineTransform::SetScale(double scale)
383 {
384 return SetScale(scale, scale);
385 }
386
387
388 const BAffineTransform&
SetScale(double x,double y)389 BAffineTransform::SetScale(double x, double y)
390 {
391 double tx;
392 double ty;
393 double rotation;
394 double shearX;
395 double shearY;
396 if (!GetAffineParameters(&tx, &ty, &rotation, NULL, NULL,
397 &shearX, &shearY)) {
398 return *this;
399 }
400
401 BAffineTransform result;
402 result.ShearBy(shearX, shearY);
403 result.ScaleBy(x, y);
404 result.RotateBy(rotation);
405 result.TranslateBy(tx, ty);
406
407 return *this = result;
408 }
409
410
411 // #pragma mark -
412
413
414 const BAffineTransform&
ShearBy(const BPoint & center,double x,double y)415 BAffineTransform::ShearBy(const BPoint& center, double x, double y)
416 {
417 TranslateBy(-center.x, -center.y);
418 ShearBy(x, y);
419 return TranslateBy(center.x, center.y);
420 }
421
422
423 const BAffineTransform&
ShearBy(const BPoint & shear)424 BAffineTransform::ShearBy(const BPoint& shear)
425 {
426 return ShearBy(shear.x, shear.y);
427 }
428
429
430 const BAffineTransform&
ShearBy(const BPoint & center,const BPoint & shear)431 BAffineTransform::ShearBy(const BPoint& center, const BPoint& shear)
432 {
433 return ShearBy(center, shear.x, shear.y);
434 }
435
436
437 BAffineTransform
ShearByCopy(double x,double y) const438 BAffineTransform::ShearByCopy(double x, double y) const
439 {
440 BAffineTransform copy(*this);
441 copy.ShearBy(x, y);
442 return copy;
443 }
444
445
446 BAffineTransform
ShearByCopy(const BPoint & center,double x,double y) const447 BAffineTransform::ShearByCopy(const BPoint& center, double x, double y) const
448 {
449 BAffineTransform copy(*this);
450 copy.ShearBy(center, x, y);
451 return copy;
452 }
453
454
455 BAffineTransform
ShearByCopy(const BPoint & shear) const456 BAffineTransform::ShearByCopy(const BPoint& shear) const
457 {
458 BAffineTransform copy(*this);
459 copy.ShearBy(shear);
460 return copy;
461 }
462
463
464 BAffineTransform
ShearByCopy(const BPoint & center,const BPoint & shear) const465 BAffineTransform::ShearByCopy(const BPoint& center, const BPoint& shear) const
466 {
467 BAffineTransform copy(*this);
468 copy.ShearBy(center, shear);
469 return copy;
470 }
471
472
473 // #pragma mark -
474
475
476 const BAffineTransform&
PreMultiply(const BAffineTransform & other)477 BAffineTransform::PreMultiply(const BAffineTransform& other)
478 {
479 double t0 = sx * other.sx + shy * other.shx;
480 double t2 = shx * other.sx + sy * other.shx;
481 double t4 = tx * other.sx + ty * other.shx + other.tx;
482 shy = sx * other.shy + shy * other.sy;
483 sy = shx * other.shy + sy * other.sy;
484 ty = tx * other.shy + ty * other.sy + other.ty;
485 sx = t0;
486 shx = t2;
487 tx = t4;
488 return *this;
489 }
490
491
492 bool
IsValid(double epsilon) const493 BAffineTransform::IsValid(double epsilon) const
494 {
495 return fabs(sx) > epsilon && fabs(sy) > epsilon;
496 }
497
498
499 static inline bool
IsEqualEpsilon(double v1,double v2,double epsilon)500 IsEqualEpsilon(double v1, double v2, double epsilon)
501 {
502 return fabs(v1 - v2) <= double(epsilon);
503 }
504
505
506 bool
IsIdentity(double epsilon) const507 BAffineTransform::IsIdentity(double epsilon) const
508 {
509 return IsEqualEpsilon(sx, 1.0, epsilon)
510 && IsEqualEpsilon(shy, 0.0, epsilon)
511 && IsEqualEpsilon(shx, 0.0, epsilon)
512 && IsEqualEpsilon(sy, 1.0, epsilon)
513 && IsEqualEpsilon(tx, 0.0, epsilon)
514 && IsEqualEpsilon(ty, 0.0, epsilon);
515 }
516
517
518 bool
IsDilation(double epsilon) const519 BAffineTransform::IsDilation(double epsilon) const
520 {
521 return IsEqualEpsilon(shy, 0.0, epsilon)
522 && IsEqualEpsilon(shx, 0.0, epsilon);
523 }
524
525
526 bool
IsEqual(const BAffineTransform & other,double epsilon) const527 BAffineTransform::IsEqual(const BAffineTransform& other, double epsilon) const
528 {
529 return IsEqualEpsilon(sx, other.sx, epsilon)
530 && IsEqualEpsilon(shy, other.shy, epsilon)
531 && IsEqualEpsilon(shx, other.shx, epsilon)
532 && IsEqualEpsilon(sy, other.sy, epsilon)
533 && IsEqualEpsilon(tx, other.tx, epsilon)
534 && IsEqualEpsilon(ty, other.ty, epsilon);
535 }
536
537
538 const BAffineTransform&
Invert()539 BAffineTransform::Invert()
540 {
541 double d = InverseDeterminant();
542
543 double t0 = sy * d;
544 sy = sx * d;
545 shy = -shy * d;
546 shx = -shx * d;
547
548 double t4 = -tx * t0 - ty * shx;
549 ty = -tx * shy - ty * sy;
550
551 sx = t0;
552 tx = t4;
553
554 return *this;
555 }
556
557
558 const BAffineTransform&
FlipX()559 BAffineTransform::FlipX()
560 {
561 sx = -sx;
562 shy = -shy;
563 tx = -tx;
564 return *this;
565 }
566
567
568 const BAffineTransform&
FlipY()569 BAffineTransform::FlipY()
570 {
571 shx = -shx;
572 sy = -sy;
573 ty = -ty;
574 return *this;
575 }
576
577
578 const BAffineTransform&
Reset()579 BAffineTransform::Reset()
580 {
581 sx = sy = 1.0;
582 shy = shx = tx = ty = 0.0;
583 return *this;
584 }
585
586
587 void
GetTranslation(double * _tx,double * _ty) const588 BAffineTransform::GetTranslation(double* _tx, double* _ty) const
589 {
590 if (_tx)
591 *_tx = tx;
592 if (_ty)
593 *_ty = ty;
594 }
595
596
597 double
Rotation() const598 BAffineTransform::Rotation() const
599 {
600 double x1 = 0.0;
601 double y1 = 0.0;
602 double x2 = 1.0;
603 double y2 = 0.0;
604 Apply(&x1, &y1);
605 Apply(&x2, &y2);
606 return atan2(y2 - y1, x2 - x1);
607 }
608
609
610 double
Scale() const611 BAffineTransform::Scale() const
612 {
613 double x = 0.707106781 * sx + 0.707106781 * shx;
614 double y = 0.707106781 * shy + 0.707106781 * sy;
615 return sqrt(x * x + y * y);
616 }
617
618
619 void
GetScale(double * _sx,double * _sy) const620 BAffineTransform::GetScale(double* _sx, double* _sy) const
621 {
622 double x1 = 0.0;
623 double y1 = 0.0;
624 double x2 = 1.0;
625 double y2 = 1.0;
626 BAffineTransform t(*this);
627 t.PreMultiply(AffineRotation(-Rotation()));
628 t.Apply(&x1, &y1);
629 t.Apply(&x2, &y2);
630 if (_sx)
631 *_sx = x2 - x1;
632 if (_sy)
633 *_sy = y2 - y1;
634 }
635
636
637 void
GetScaleAbs(double * _sx,double * _sy) const638 BAffineTransform::GetScaleAbs(double* _sx, double* _sy) const
639 {
640 // When there is considerable shear this method gives us much
641 // better estimation than just sx, sy.
642 if (_sx)
643 *_sx = sqrt(sx * sx + shx * shx);
644 if (_sy)
645 *_sy = sqrt(shy * shy + sy * sy);
646 }
647
648
649 bool
GetAffineParameters(double * _translationX,double * _translationY,double * _rotation,double * _scaleX,double * _scaleY,double * _shearX,double * _shearY) const650 BAffineTransform::GetAffineParameters(double* _translationX,
651 double* _translationY, double* _rotation, double* _scaleX, double* _scaleY,
652 double* _shearX, double* _shearY) const
653 {
654 GetTranslation(_translationX, _translationY);
655
656 double rotation = Rotation();
657 if (_rotation != NULL)
658 *_rotation = rotation;
659
660 // Calculate shear
661 double x1 = 0.0;
662 double y1 = 0.0;
663 double x2 = 1.0;
664 double y2 = 0.0;
665 double x3 = 0.0;
666 double y3 = 1.0;
667
668 // Reverse the effects of any rotation
669 BAffineTransform t(*this);
670 t.PreMultiply(AffineRotation(-rotation));
671
672 t.Apply(&x1, &y1);
673 t.Apply(&x2, &y2);
674 t.Apply(&x3, &y3);
675
676 double shearX = y2 - y1;
677 double shearY = x3 - x1;
678
679 // Calculate scale
680 x1 = 0.0;
681 y1 = 0.0;
682 x2 = 1.0;
683 y2 = 0.0;
684 x3 = 0.0;
685 y3 = 1.0;
686
687 // Reverse the effects of any shear
688 t.PreMultiplyInverse(AffineShearing(shearX, shearY));
689
690 t.Apply(&x1, &y1);
691 t.Apply(&x2, &y2);
692 t.Apply(&x3, &y3);
693
694 double scaleX = x2 - x1;
695 double scaleY = y3 - y1;
696
697 if (_scaleX != NULL)
698 *_scaleX = scaleX;
699 if (_scaleY != NULL)
700 *_scaleY = scaleY;
701
702 // Since scale was calculated last, the shear values are still scaled.
703 // We cannot get the affine parameters from a matrix with 0 scale.
704 if (scaleX == 0.0 && scaleY == 0.0)
705 return false;
706
707 if (_shearX != NULL)
708 *_shearX = shearX / scaleX;
709 if (_shearY != NULL)
710 *_shearY = shearY / scaleY;
711
712 return true;
713 }
714
715