1/*
2 * Copyright 2006-2007, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan A��mus <superstippi@gmx.de>
7 */
8
9
10#include "AffineTransformer.h"
11
12#ifdef ICON_O_MATIC
13# include <Message.h>
14
15# include "CommonPropertyIDs.h"
16# include "Property.h"
17# include "PropertyObject.h"
18#endif
19
20#include <new>
21
22
23_USING_ICON_NAMESPACE
24using std::nothrow;
25
26
27// constructor
28AffineTransformer::AffineTransformer(VertexSource& source)
29	: Transformer(source, "Transformation"),
30	  Affine(source, *this)
31{
32}
33
34// constructor
35AffineTransformer::AffineTransformer(VertexSource& source,
36									 BMessage* archive)
37	: Transformer(source, archive),
38	  Affine(source, *this)
39{
40	if (!archive)
41		return;
42
43	int32 size = 6;
44	const void* matrix;
45	ssize_t dataSize = size * sizeof(double);
46	if (archive->FindData("matrix", B_DOUBLE_TYPE,
47						  &matrix, &dataSize) == B_OK) {
48		if (dataSize == (ssize_t)(size * sizeof(double)))
49			load_from((const double*)matrix);
50	}
51}
52
53// destructor
54AffineTransformer::~AffineTransformer()
55{
56}
57
58// Clone
59Transformer*
60AffineTransformer::Clone(VertexSource& source) const
61{
62	AffineTransformer* clone = new (nothrow) AffineTransformer(source);
63	if (clone)
64		clone->multiply(*this);
65	return clone;
66}
67
68// rewind
69void
70AffineTransformer::rewind(unsigned path_id)
71{
72	Affine::rewind(path_id);
73}
74
75// vertex
76unsigned
77AffineTransformer::vertex(double* x, double* y)
78{
79	return Affine::vertex(x, y);
80}
81
82// SetSource
83void
84AffineTransformer::SetSource(VertexSource& source)
85{
86	Transformer::SetSource(source);
87	Affine::attach(source);
88}
89
90// ApproximationScale
91double
92AffineTransformer::ApproximationScale() const
93{
94	return fabs(fSource.ApproximationScale() * scale());
95}
96
97// #pragma mark -
98
99#ifdef ICON_O_MATIC
100
101// Archive
102status_t
103AffineTransformer::Archive(BMessage* into, bool deep) const
104{
105	status_t ret = Transformer::Archive(into, deep);
106
107	if (ret == B_OK)
108		into->what = archive_code;
109
110	if (ret == B_OK) {
111		double matrix[6];
112		store_to(matrix);
113		ret = into->AddData("matrix", B_DOUBLE_TYPE,
114							matrix, 6 * sizeof(double));
115	}
116
117	return ret;
118}
119
120// MakePropertyObject
121PropertyObject*
122AffineTransformer::MakePropertyObject() const
123{
124	PropertyObject* object = Transformer::MakePropertyObject();
125	if (!object)
126		return NULL;
127
128	// translation
129	double tx;
130	double ty;
131	translation(&tx, &ty);
132	object->AddProperty(new FloatProperty(PROPERTY_TRANSLATION_X, tx));
133	object->AddProperty(new FloatProperty(PROPERTY_TRANSLATION_Y, ty));
134
135	// rotation
136	object->AddProperty(new FloatProperty(PROPERTY_ROTATION,
137										  agg::rad2deg(rotation())));
138
139	// scale
140	double scaleX;
141	double scaleY;
142	scaling(&scaleX, &scaleY);
143	object->AddProperty(new FloatProperty(PROPERTY_SCALE_X, scaleX));
144	object->AddProperty(new FloatProperty(PROPERTY_SCALE_Y, scaleY));
145
146	return object;
147}
148
149// SetToPropertyObject
150bool
151AffineTransformer::SetToPropertyObject(const PropertyObject* object)
152{
153	AutoNotificationSuspender _(this);
154	Transformer::SetToPropertyObject(object);
155
156	// current affine parameters
157	double tx;
158	double ty;
159	translation(&tx, &ty);
160	double r = rotation();
161	double scaleX;
162	double scaleY;
163	scaling(&scaleX, &scaleY);
164
165	// properties
166	double newTX = object->Value(PROPERTY_TRANSLATION_X, (float)tx);
167	double newTY = object->Value(PROPERTY_TRANSLATION_Y, (float)ty);
168
169	double newR = object->Value(PROPERTY_ROTATION,
170								(float)agg::rad2deg(r));
171	newR = agg::deg2rad(newR);
172
173	double newScaleX = object->Value(PROPERTY_SCALE_X, (float)scaleX);
174	double newScaleY = object->Value(PROPERTY_SCALE_Y, (float)scaleY);
175
176	if (newTX != tx || newTY != ty
177		|| newR != r
178		|| newScaleX != scaleX
179		|| newScaleY != scaleY) {
180
181		reset();
182
183		multiply(agg::trans_affine_scaling(newScaleX, newScaleY));
184		multiply(agg::trans_affine_rotation(newR));
185		multiply(agg::trans_affine_translation(newTX, newTY));
186
187		Notify();
188	}
189
190	return HasPendingNotifications();
191}
192
193#endif // ICON_O_MATIC
194
195
196