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
33class BAffineTransform : public BFlattenable {
34public:
35
36#if __cplusplus < 201103L
37	static	const double			kDefaultEpsilon = 1e-14;
38#else
39	static	constexpr double		kDefaultEpsilon = 1e-14;
40#endif
41
42public:
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
205public:
206			double					sx;
207			double					shy;
208			double					shx;
209			double					sy;
210			double					tx;
211			double					ty;
212};
213
214
215extern const BAffineTransform B_AFFINE_IDENTITY_TRANSFORM;
216
217
218// #pragma mark - inline methods
219
220
221inline void
222BAffineTransform::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
230inline void
231BAffineTransform::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
244inline const BAffineTransform&
245BAffineTransform::TranslateBy(double x, double y)
246{
247	tx += x;
248	ty += y;
249	return *this;
250}
251
252
253inline const BAffineTransform&
254BAffineTransform::PreTranslateBy(double x, double y)
255{
256	tx += x * sx + y * shx;
257	ty += x * shy + y * sy;
258	return *this;
259}
260
261
262inline const BAffineTransform&
263BAffineTransform::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
280inline const BAffineTransform&
281BAffineTransform::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
295inline const BAffineTransform&
296BAffineTransform::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
311inline const BAffineTransform&
312BAffineTransform::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
326inline const BAffineTransform&
327BAffineTransform::PreScaleBy(double x, double y)
328{
329	sx *= x;
330	shx *= y;
331	shy *= x;
332	sy *= y;
333	return *this;
334}
335
336
337inline const BAffineTransform&
338BAffineTransform::ShearBy(double x, double y)
339{
340	BAffineTransform shearTransform = AffineShearing(x, y);
341	return PreMultiply(shearTransform);
342}
343
344
345// #pragma mark -
346
347
348inline const BAffineTransform&
349BAffineTransform::Multiply(const BAffineTransform& other)
350{
351	BAffineTransform t(other);
352	return *this = t.PreMultiply(*this);
353}
354
355
356inline const BAffineTransform&
357BAffineTransform::MultiplyInverse(const BAffineTransform& other)
358{
359	BAffineTransform t(other);
360	t.Invert();
361	return Multiply(t);
362}
363
364
365inline const BAffineTransform&
366BAffineTransform::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
377inline BAffineTransform&
378BAffineTransform::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
389inline bool
390BAffineTransform::operator==(const BAffineTransform& other) const
391{
392	return IsEqual(other);
393}
394
395inline bool
396BAffineTransform::operator!=(const BAffineTransform& other) const
397{
398	return !IsEqual(other);
399}
400
401
402inline const BAffineTransform&
403BAffineTransform::operator*=(const BAffineTransform& other)
404{
405	return Multiply(other);
406}
407
408
409inline const BAffineTransform&
410BAffineTransform::operator/=(const BAffineTransform& other)
411{
412	return MultiplyInverse(other);
413}
414
415
416inline BAffineTransform
417BAffineTransform::operator*(const BAffineTransform& other) const
418{
419	return BAffineTransform(*this).Multiply(other);
420}
421
422
423inline BAffineTransform
424BAffineTransform::operator/(const BAffineTransform& other) const
425{
426	return BAffineTransform(*this).MultiplyInverse(other);
427}
428
429
430inline BAffineTransform
431BAffineTransform::operator~() const
432{
433	BAffineTransform result(*this);
434	return result.Invert();
435}
436
437
438// #pragma mark -
439
440
441inline double
442BAffineTransform::Determinant() const
443{
444	return sx * sy - shy * shx;
445}
446
447
448inline double
449BAffineTransform::InverseDeterminant() const
450{
451	return 1.0 / (sx * sy - shy * shx);
452}
453
454
455#endif // _AFFINE_TRANSFORM_H
456