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	static	const double			kDefaultEpsilon = 1e-14;
37
38public:
39									BAffineTransform();
40									BAffineTransform(double sx, double shy,
41										double shx, double sy, double tx,
42										double ty);
43									BAffineTransform(
44										const BAffineTransform& copyFrom);
45	virtual							~BAffineTransform();
46
47	// BFlattenable interface
48	virtual	bool					IsFixedSize() const;
49	virtual	type_code				TypeCode() const;
50	virtual	ssize_t					FlattenedSize() const;
51	virtual	status_t				Flatten(void* buffer,
52										ssize_t size) const;
53	virtual	status_t				Unflatten(type_code code,
54										const void* buffer, ssize_t size);
55
56	// Construction
57	static	BAffineTransform		AffineTranslation(double x, double y);
58	static	BAffineTransform		AffineRotation(double angle);
59	static	BAffineTransform		AffineScaling(double x, double y);
60	static	BAffineTransform		AffineScaling(double scale);
61	static	BAffineTransform		AffineShearing(double x, double y);
62
63	// Application
64	inline	void					Apply(double* x, double* y) const;
65	inline	void					ApplyInverse(double* x, double* y) const;
66
67			BPoint					Apply(const BPoint& point) const;
68			BPoint					ApplyInverse(const BPoint& point) const;
69
70			void					Apply(BPoint* point) const;
71			void					ApplyInverse(BPoint* point) const;
72
73			void					Apply(BPoint* points, uint32 count) const;
74			void					ApplyInverse(BPoint* points,
75										uint32 count) const;
76
77	// Translation
78	inline	const BAffineTransform&	TranslateBy(double x, double y);
79			const BAffineTransform&	TranslateBy(const BPoint& delta);
80
81			BAffineTransform		TranslateByCopy(double x, double y) const;
82			BAffineTransform		TranslateByCopy(const BPoint& delta) const;
83
84//			const BAffineTransform&	SetTranslation(double x, double y);
85
86	// Rotation
87	inline	const BAffineTransform&	RotateBy(double angle);
88			const BAffineTransform&	RotateBy(const BPoint& center,
89										double angle);
90
91			BAffineTransform		RotateByCopy(double angle) const;
92			BAffineTransform		RotateByCopy(const BPoint& center,
93										double angle) const;
94
95//			const BAffineTransform&	SetRotation(double angle);
96
97	// Scaling
98	inline	const BAffineTransform&	ScaleBy(double scale);
99			const BAffineTransform&	ScaleBy(const BPoint& center,
100										double scale);
101	inline	const BAffineTransform&	ScaleBy(double x, double y);
102			const BAffineTransform&	ScaleBy(const BPoint& center, double x,
103										double y);
104			const BAffineTransform&	ScaleBy(const BPoint& scale);
105			const BAffineTransform&	ScaleBy(const BPoint& center,
106										const BPoint& scale);
107
108			BAffineTransform		ScaleByCopy(double scale) const;
109			BAffineTransform		ScaleByCopy(const BPoint& center,
110										double scale) const;
111			BAffineTransform		ScaleByCopy(double x, double y) const;
112			BAffineTransform		ScaleByCopy(const BPoint& center,
113										double x, double y) const;
114			BAffineTransform		ScaleByCopy(const BPoint& scale) const;
115			BAffineTransform		ScaleByCopy(const BPoint& center,
116										const BPoint& scale) const;
117
118			const BAffineTransform&	SetScale(double scale);
119			const BAffineTransform&	SetScale(double x, double y);
120
121	// Shearing
122	inline	const BAffineTransform&	ShearBy(double x, double y);
123			const BAffineTransform&	ShearBy(const BPoint& center, double x,
124										double y);
125			const BAffineTransform&	ShearBy(const BPoint& shear);
126			const BAffineTransform&	ShearBy(const BPoint& center,
127										const BPoint& shear);
128
129			BAffineTransform		ShearByCopy(double x, double y) const;
130			BAffineTransform		ShearByCopy(const BPoint& center,
131										double x, double y) const;
132			BAffineTransform		ShearByCopy(const BPoint& shear) const;
133			BAffineTransform		ShearByCopy(const BPoint& center,
134										const BPoint& shear) const;
135
136//			const BAffineTransform&	SetShear(double x, double y);
137
138	// Multiplication
139	inline	const BAffineTransform&	Multiply(const BAffineTransform& other);
140			const BAffineTransform&	PreMultiply(const BAffineTransform& other);
141	inline	const BAffineTransform&	MultiplyInverse(
142										const BAffineTransform& other);
143	inline	const BAffineTransform&	PreMultiplyInverse(
144										const BAffineTransform& other);
145
146	// Operators
147	inline	BAffineTransform&		operator=(
148										const BAffineTransform& copyFrom);
149
150	inline	bool					operator==(
151										const BAffineTransform& other) const;
152	inline	bool					operator!=(
153										const BAffineTransform& other) const;
154
155	inline	const BAffineTransform&	operator*=(const BAffineTransform& other);
156	inline	const BAffineTransform&	operator/=(const BAffineTransform& other);
157
158	inline	BAffineTransform		operator*(
159										const BAffineTransform& other) const;
160	inline	BAffineTransform		operator/(
161										const BAffineTransform& other) const;
162
163	inline	BAffineTransform		operator~() const;
164
165	// Utility
166			bool					IsValid(double epsilon
167										= kDefaultEpsilon) const;
168			bool					IsIdentity(double epsilon
169										= kDefaultEpsilon) const;
170			bool					IsEqual(const BAffineTransform& other,
171										double epsilon
172											= kDefaultEpsilon) const;
173
174			const BAffineTransform&	Invert();
175			const BAffineTransform&	FlipX();
176			const BAffineTransform&	FlipY();
177			const BAffineTransform&	Reset();
178
179	inline	double					Determinant() const;
180	inline	double					InverseDeterminant() const;
181			void					GetTranslation(double* tx,
182										double* ty) const;
183			double					Rotation() const;
184			double					Scale() const;
185			void					GetScale(double* sx, double* sy) const;
186			void					GetScaleAbs(double* sx,
187										double* sy) const;
188			bool					GetAffineParameters(double* translationX,
189										double* translationY, double* rotation,
190										double* scaleX, double* scaleY,
191										double* shearX, double* shearY) const;
192
193public:
194			double					sx;
195			double					shy;
196			double					shx;
197			double					sy;
198			double					tx;
199			double					ty;
200};
201
202
203extern const BAffineTransform B_AFFINE_IDENTITY_TRANSFORM;
204
205
206// #pragma mark - inline methods
207
208
209inline void
210BAffineTransform::Apply(double* x, double* y) const
211{
212	register double tmp = *x;
213	*x = tmp * sx + *y * shx + tx;
214	*y = tmp * shy + *y * sy + ty;
215}
216
217
218inline void
219BAffineTransform::ApplyInverse(double* x, double* y) const
220{
221	register double d = InverseDeterminant();
222	register double a = (*x - tx) * d;
223	register double b = (*y - ty) * d;
224	*x = a * sy - b * shx;
225	*y = b * sx - a * shy;
226}
227
228
229// #pragma mark -
230
231
232inline const BAffineTransform&
233BAffineTransform::TranslateBy(double x, double y)
234{
235	tx += x;
236	ty += y;
237	return *this;
238}
239
240
241inline const BAffineTransform&
242BAffineTransform::RotateBy(double angle)
243{
244	double ca = cos(angle);
245	double sa = sin(angle);
246	double t0 = sx * ca - shy * sa;
247	double t2 = shx * ca - sy * sa;
248	double t4 = tx * ca - ty * sa;
249	shy = sx * sa + shy * ca;
250	sy = shx * sa + sy * ca;
251	ty = tx * sa + ty * ca;
252	sx = t0;
253	shx = t2;
254	tx = t4;
255	return *this;
256}
257
258
259inline const BAffineTransform&
260BAffineTransform::ScaleBy(double x, double y)
261{
262	double mm0 = x;
263		// Possible hint for the optimizer
264	double mm3 = y;
265	sx *= mm0;
266	shx *= mm0;
267	tx *= mm0;
268	shy *= mm3;
269	sy *= mm3;
270	ty *= mm3;
271	return *this;
272}
273
274
275inline const BAffineTransform&
276BAffineTransform::ScaleBy(double s)
277{
278	double m = s;
279		// Possible hint for the optimizer
280	sx *= m;
281	shx *= m;
282	tx *= m;
283	shy *= m;
284	sy *= m;
285	ty *= m;
286	return *this;
287}
288
289
290inline const BAffineTransform&
291BAffineTransform::ShearBy(double x, double y)
292{
293	BAffineTransform shearTransform = AffineShearing(x, y);
294	return PreMultiply(shearTransform);
295}
296
297
298// #pragma mark -
299
300
301inline const BAffineTransform&
302BAffineTransform::Multiply(const BAffineTransform& other)
303{
304	BAffineTransform t(other);
305	return *this = t.PreMultiply(*this);
306}
307
308
309inline const BAffineTransform&
310BAffineTransform::MultiplyInverse(const BAffineTransform& other)
311{
312	BAffineTransform t(other);
313	t.Invert();
314	return Multiply(t);
315}
316
317
318inline const BAffineTransform&
319BAffineTransform::PreMultiplyInverse(const BAffineTransform& other)
320{
321	BAffineTransform t(other);
322	t.Invert();
323	return *this = t.Multiply(*this);
324}
325
326
327// #pragma mark -
328
329
330inline BAffineTransform&
331BAffineTransform::operator=(const BAffineTransform& other)
332{
333	sx = other.sx;
334	shy = other.shy;
335	shx = other.shx;
336	sy = other.sy;
337	tx = other.tx;
338	ty = other.ty;
339	return *this;
340}
341
342inline bool
343BAffineTransform::operator==(const BAffineTransform& other) const
344{
345	return IsEqual(other);
346}
347
348inline bool
349BAffineTransform::operator!=(const BAffineTransform& other) const
350{
351	return !IsEqual(other);
352}
353
354
355inline const BAffineTransform&
356BAffineTransform::operator*=(const BAffineTransform& other)
357{
358	return Multiply(other);
359}
360
361
362inline const BAffineTransform&
363BAffineTransform::operator/=(const BAffineTransform& other)
364{
365	return MultiplyInverse(other);
366}
367
368
369inline BAffineTransform
370BAffineTransform::operator*(const BAffineTransform& other) const
371{
372	return BAffineTransform(*this).Multiply(other);
373}
374
375
376inline BAffineTransform
377BAffineTransform::operator/(const BAffineTransform& other) const
378{
379	return BAffineTransform(*this).MultiplyInverse(other);
380}
381
382
383inline BAffineTransform
384BAffineTransform::operator~() const
385{
386	BAffineTransform result(*this);
387	return result.Invert();
388}
389
390
391// #pragma mark -
392
393
394inline double
395BAffineTransform::Determinant() const
396{
397	return sx * sy - shy * shx;
398}
399
400
401inline double
402BAffineTransform::InverseDeterminant() const
403{
404	return 1.0 / (sx * sy - shy * shx);
405}
406
407
408#endif // _AFFINE_TRANSFORM_H
409