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
29const BAffineTransform B_AFFINE_IDENTITY_TRANSFORM;
30
31
32BAffineTransform::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
44BAffineTransform::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
57BAffineTransform::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
69BAffineTransform::~BAffineTransform()
70{
71}
72
73
74// #pragma mark -
75
76
77bool
78BAffineTransform::IsFixedSize() const
79{
80	return true;
81}
82
83
84type_code
85BAffineTransform::TypeCode() const
86{
87	return B_AFFINE_TRANSFORM_TYPE;
88}
89
90
91ssize_t
92BAffineTransform::FlattenedSize() const
93{
94	return 6 * sizeof(double);
95}
96
97
98status_t
99BAffineTransform::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
117status_t
118BAffineTransform::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
142BAffineTransform::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
149BAffineTransform::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
157BAffineTransform::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
164BAffineTransform::AffineScaling(double scale)
165{
166	return BAffineTransform(scale, 0.0, 0.0, scale, 0.0, 0.0);
167}
168
169
170/*static*/ BAffineTransform
171BAffineTransform::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
180BPoint
181BAffineTransform::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
190BPoint
191BAffineTransform::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
200void
201BAffineTransform::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
213void
214BAffineTransform::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
226void
227BAffineTransform::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
236void
237BAffineTransform::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
249const BAffineTransform&
250BAffineTransform::TranslateBy(const BPoint& delta)
251{
252	return TranslateBy(delta.x, delta.y);
253}
254
255
256BAffineTransform
257BAffineTransform::TranslateByCopy(double x, double y) const
258{
259	BAffineTransform copy(*this);
260	copy.TranslateBy(x, y);
261	return copy;
262}
263
264
265BAffineTransform
266BAffineTransform::TranslateByCopy(const BPoint& delta) const
267{
268	return TranslateByCopy(delta.x, delta.y);
269}
270
271
272// #pragma mark -
273
274
275const BAffineTransform&
276BAffineTransform::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
284BAffineTransform
285BAffineTransform::RotateByCopy(double angle) const
286{
287	BAffineTransform copy(*this);
288	copy.RotateBy(angle);
289	return copy;
290}
291
292
293BAffineTransform
294BAffineTransform::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
305const BAffineTransform&
306BAffineTransform::ScaleBy(const BPoint& center, double scale)
307{
308	return ScaleBy(center, scale, scale);
309}
310
311
312const BAffineTransform&
313BAffineTransform::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
321const BAffineTransform&
322BAffineTransform::ScaleBy(const BPoint& scale)
323{
324	return ScaleBy(scale.x, scale.y);
325}
326
327
328const BAffineTransform&
329BAffineTransform::ScaleBy(const BPoint& center, const BPoint& scale)
330{
331	return ScaleBy(center, scale.x, scale.y);
332}
333
334
335BAffineTransform
336BAffineTransform::ScaleByCopy(double scale) const
337{
338	return ScaleByCopy(scale, scale);
339}
340
341
342BAffineTransform
343BAffineTransform::ScaleByCopy(const BPoint& center, double scale) const
344{
345	return ScaleByCopy(center, scale, scale);
346}
347
348
349BAffineTransform
350BAffineTransform::ScaleByCopy(double x, double y) const
351{
352	BAffineTransform copy(*this);
353	copy.ScaleBy(x, y);
354	return copy;
355}
356
357
358BAffineTransform
359BAffineTransform::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
367BAffineTransform
368BAffineTransform::ScaleByCopy(const BPoint& scale) const
369{
370	return ScaleByCopy(scale.x, scale.y);
371}
372
373
374BAffineTransform
375BAffineTransform::ScaleByCopy(const BPoint& center, const BPoint& scale) const
376{
377	return ScaleByCopy(center, scale.x, scale.y);
378}
379
380
381const BAffineTransform&
382BAffineTransform::SetScale(double scale)
383{
384	return SetScale(scale, scale);
385}
386
387
388const BAffineTransform&
389BAffineTransform::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
414const BAffineTransform&
415BAffineTransform::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
423const BAffineTransform&
424BAffineTransform::ShearBy(const BPoint& shear)
425{
426	return ShearBy(shear.x, shear.y);
427}
428
429
430const BAffineTransform&
431BAffineTransform::ShearBy(const BPoint& center, const BPoint& shear)
432{
433	return ShearBy(center, shear.x, shear.y);
434}
435
436
437BAffineTransform
438BAffineTransform::ShearByCopy(double x, double y) const
439{
440	BAffineTransform copy(*this);
441	copy.ShearBy(x, y);
442	return copy;
443}
444
445
446BAffineTransform
447BAffineTransform::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
455BAffineTransform
456BAffineTransform::ShearByCopy(const BPoint& shear) const
457{
458	BAffineTransform copy(*this);
459	copy.ShearBy(shear);
460	return copy;
461}
462
463
464BAffineTransform
465BAffineTransform::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
476const BAffineTransform&
477BAffineTransform::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
492bool
493BAffineTransform::IsValid(double epsilon) const
494{
495	return fabs(sx) > epsilon && fabs(sy) > epsilon;
496}
497
498
499static inline bool
500IsEqualEpsilon(double v1, double v2, double epsilon)
501{
502    return fabs(v1 - v2) <= double(epsilon);
503}
504
505
506bool
507BAffineTransform::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
518bool
519BAffineTransform::IsDilation(double epsilon) const
520{
521	return IsEqualEpsilon(shy, 0.0, epsilon)
522		&& IsEqualEpsilon(shx, 0.0, epsilon);
523}
524
525
526bool
527BAffineTransform::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
538const BAffineTransform&
539BAffineTransform::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
558const BAffineTransform&
559BAffineTransform::FlipX()
560{
561	sx = -sx;
562	shy = -shy;
563	tx = -tx;
564	return *this;
565}
566
567
568const BAffineTransform&
569BAffineTransform::FlipY()
570{
571	shx = -shx;
572	sy = -sy;
573	ty = -ty;
574	return *this;
575}
576
577
578const BAffineTransform&
579BAffineTransform::Reset()
580{
581	sx = sy = 1.0;
582	shy = shx = tx = ty = 0.0;
583	return *this;
584}
585
586
587void
588BAffineTransform::GetTranslation(double* _tx, double* _ty) const
589{
590	if (_tx)
591		*_tx = tx;
592	if (_ty)
593		*_ty = ty;
594}
595
596
597double
598BAffineTransform::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
610double
611BAffineTransform::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
619void
620BAffineTransform::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
637void
638BAffineTransform::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
649bool
650BAffineTransform::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