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