2
* Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
3
* 2010 Dirk Schulze <krit@webkit.org>
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
14
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
#include "AffineTransform.h"
30
#include "FloatConversion.h"
31
#include "FloatQuad.h"
32
#include "FloatRect.h"
35
#include <wtf/MathExtras.h>
39
AffineTransform::AffineTransform()
41
setMatrix(1, 0, 0, 1, 0, 0);
44
AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
46
setMatrix(a, b, c, d, e, f);
49
void AffineTransform::makeIdentity()
51
setMatrix(1, 0, 0, 1, 0, 0);
54
void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f)
64
bool AffineTransform::isIdentity() const
66
return (m_transform[0] == 1 && m_transform[1] == 0
67
&& m_transform[2] == 0 && m_transform[3] == 1
68
&& m_transform[4] == 0 && m_transform[5] == 0);
71
double AffineTransform::xScale() const
73
return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]);
76
double AffineTransform::yScale() const
78
return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]);
81
double AffineTransform::det() const
83
return m_transform[0] * m_transform[3] - m_transform[1] * m_transform[2];
86
bool AffineTransform::isInvertible() const
91
AffineTransform AffineTransform::inverse() const
93
double determinant = det();
94
if (determinant == 0.0)
95
return AffineTransform();
97
AffineTransform result;
98
if (isIdentityOrTranslation()) {
99
result.m_transform[4] = -m_transform[4];
100
result.m_transform[5] = -m_transform[5];
104
result.m_transform[0] = m_transform[3] / determinant;
105
result.m_transform[1] = -m_transform[1] / determinant;
106
result.m_transform[2] = -m_transform[2] / determinant;
107
result.m_transform[3] = m_transform[0] / determinant;
108
result.m_transform[4] = (m_transform[2] * m_transform[5]
109
- m_transform[3] * m_transform[4]) / determinant;
110
result.m_transform[5] = (m_transform[1] * m_transform[4]
111
- m_transform[0] * m_transform[5]) / determinant;
117
// Multiplies this AffineTransform by the provided AffineTransform - i.e.
118
// this = this * other;
119
AffineTransform& AffineTransform::multiply(const AffineTransform& other)
121
AffineTransform trans;
123
trans.m_transform[0] = other.m_transform[0] * m_transform[0] + other.m_transform[1] * m_transform[2];
124
trans.m_transform[1] = other.m_transform[0] * m_transform[1] + other.m_transform[1] * m_transform[3];
125
trans.m_transform[2] = other.m_transform[2] * m_transform[0] + other.m_transform[3] * m_transform[2];
126
trans.m_transform[3] = other.m_transform[2] * m_transform[1] + other.m_transform[3] * m_transform[3];
127
trans.m_transform[4] = other.m_transform[4] * m_transform[0] + other.m_transform[5] * m_transform[2] + m_transform[4];
128
trans.m_transform[5] = other.m_transform[4] * m_transform[1] + other.m_transform[5] * m_transform[3] + m_transform[5];
130
setMatrix(trans.m_transform);
134
AffineTransform& AffineTransform::rotate(double a)
136
// angle is in degree. Switch to radian
138
double cosAngle = cos(a);
139
double sinAngle = sin(a);
140
AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
146
AffineTransform& AffineTransform::scale(double s)
151
AffineTransform& AffineTransform::scale(double sx, double sy)
153
m_transform[0] *= sx;
154
m_transform[1] *= sx;
155
m_transform[2] *= sy;
156
m_transform[3] *= sy;
160
// *this = *this * translation
161
AffineTransform& AffineTransform::translate(double tx, double ty)
163
if (isIdentityOrTranslation()) {
164
m_transform[4] += tx;
165
m_transform[5] += ty;
169
m_transform[4] += tx * m_transform[0] + ty * m_transform[2];
170
m_transform[5] += tx * m_transform[1] + ty * m_transform[3];
174
AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
176
return scale(sx, sy);
179
AffineTransform& AffineTransform::rotateFromVector(double x, double y)
181
return rotate(rad2deg(atan2(y, x)));
184
AffineTransform& AffineTransform::flipX()
189
AffineTransform& AffineTransform::flipY()
194
AffineTransform& AffineTransform::shear(double sx, double sy)
196
double a = m_transform[0];
197
double b = m_transform[1];
199
m_transform[0] += sy * m_transform[2];
200
m_transform[1] += sy * m_transform[3];
201
m_transform[2] += sx * a;
202
m_transform[3] += sx * b;
207
AffineTransform& AffineTransform::skew(double angleX, double angleY)
209
return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
212
AffineTransform& AffineTransform::skewX(double angle)
214
return shear(tan(deg2rad(angle)), 0);
217
AffineTransform& AffineTransform::skewY(double angle)
219
return shear(0, tan(deg2rad(angle)));
222
AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
224
AffineTransform transform;
225
transform.translate(dest.x() - source.x(), dest.y() - source.y());
226
transform.scale(dest.width() / source.width(), dest.height() / source.height());
230
void AffineTransform::map(double x, double y, double& x2, double& y2) const
232
x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]);
233
y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]);
236
IntPoint AffineTransform::mapPoint(const IntPoint& point) const
239
map(point.x(), point.y(), x2, y2);
242
return IntPoint(lround(x2), lround(y2));
245
FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
248
map(point.x(), point.y(), x2, y2);
250
return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
253
IntSize AffineTransform::mapSize(const IntSize& size) const
255
double width2 = size.width() * xScale();
256
double height2 = size.height() * yScale();
258
return IntSize(lround(width2), lround(height2));
261
FloatSize AffineTransform::mapSize(const FloatSize& size) const
263
double width2 = size.width() * xScale();
264
double height2 = size.height() * yScale();
266
return FloatSize(narrowPrecisionToFloat(width2), narrowPrecisionToFloat(height2));
269
IntRect AffineTransform::mapRect(const IntRect &rect) const
271
return enclosingIntRect(mapRect(FloatRect(rect)));
274
FloatRect AffineTransform::mapRect(const FloatRect& rect) const
276
if (isIdentityOrTranslation()) {
277
FloatRect mappedRect(rect);
278
mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
283
result.setP1(mapPoint(rect.location()));
284
result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y())));
285
result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY())));
286
result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY())));
287
return result.boundingBox();
290
FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const
292
if (isIdentityOrTranslation()) {
293
FloatQuad mappedQuad(q);
294
mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
299
result.setP1(mapPoint(q.p1()));
300
result.setP2(mapPoint(q.p2()));
301
result.setP3(mapPoint(q.p3()));
302
result.setP4(mapPoint(q.p4()));
306
void AffineTransform::blend(const AffineTransform& from, double progress)
308
DecomposedType srA, srB;
311
this->decompose(srB);
313
// If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
314
if ((srA.scaleX < 0 && srB.scaleY < 0) || (srA.scaleY < 0 && srB.scaleX < 0)) {
315
srA.scaleX = -srA.scaleX;
316
srA.scaleY = -srA.scaleY;
317
srA.angle += srA.angle < 0 ? piDouble : -piDouble;
320
// Don't rotate the long way around.
321
srA.angle = fmod(srA.angle, 2 * piDouble);
322
srB.angle = fmod(srB.angle, 2 * piDouble);
324
if (fabs(srA.angle - srB.angle) > piDouble) {
325
if (srA.angle > srB.angle)
326
srA.angle -= piDouble * 2;
328
srB.angle -= piDouble * 2;
331
srA.scaleX += progress * (srB.scaleX - srA.scaleX);
332
srA.scaleY += progress * (srB.scaleY - srA.scaleY);
333
srA.angle += progress * (srB.angle - srA.angle);
334
srA.remainderA += progress * (srB.remainderA - srA.remainderA);
335
srA.remainderB += progress * (srB.remainderB - srA.remainderB);
336
srA.remainderC += progress * (srB.remainderC - srA.remainderC);
337
srA.remainderD += progress * (srB.remainderD - srA.remainderD);
338
srA.translateX += progress * (srB.translateX - srA.translateX);
339
srA.translateY += progress * (srB.translateY - srA.translateY);
341
this->recompose(srA);
344
TransformationMatrix AffineTransform::toTransformationMatrix() const
346
return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2],
347
m_transform[3], m_transform[4], m_transform[5]);
350
bool AffineTransform::decompose(DecomposedType& decomp) const
352
AffineTransform m(*this);
354
// Compute scaling factors
355
double sx = xScale();
356
double sy = yScale();
358
// Compute cross product of transformed unit vectors. If negative,
359
// one axis was flipped.
360
if (m.a() * m.d() - m.c() * m.b() < 0) {
361
// Flip axis with minimum unit vector dot product
368
// Remove scale from matrix
369
m.scale(1 / sx, 1 / sy);
372
double angle = atan2(m.b(), m.a());
374
// Remove rotation from matrix
375
m.rotate(rad2deg(-angle));
380
decomp.angle = angle;
381
decomp.remainderA = m.a();
382
decomp.remainderB = m.b();
383
decomp.remainderC = m.c();
384
decomp.remainderD = m.d();
385
decomp.translateX = m.e();
386
decomp.translateY = m.f();
391
void AffineTransform::recompose(const DecomposedType& decomp)
393
this->setA(decomp.remainderA);
394
this->setB(decomp.remainderB);
395
this->setC(decomp.remainderC);
396
this->setD(decomp.remainderD);
397
this->setE(decomp.translateX);
398
this->setF(decomp.translateY);
399
this->rotate(rad2deg(decomp.angle));
400
this->scale(decomp.scaleX, decomp.scaleY);