Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/math/affinetransform.js
2868 views
1
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
16
/**
17
* @fileoverview Provides an object representation of an AffineTransform and
18
* methods for working with it.
19
*/
20
21
22
goog.provide('goog.math.AffineTransform');
23
24
25
26
/**
27
* Creates a 2D affine transform. An affine transform performs a linear
28
* mapping from 2D coordinates to other 2D coordinates that preserves the
29
* "straightness" and "parallelness" of lines.
30
*
31
* Such a coordinate transformation can be represented by a 3 row by 3 column
32
* matrix with an implied last row of [ 0 0 1 ]. This matrix transforms source
33
* coordinates (x,y) into destination coordinates (x',y') by considering them
34
* to be a column vector and multiplying the coordinate vector by the matrix
35
* according to the following process:
36
* <pre>
37
* [ x'] [ m00 m01 m02 ] [ x ] [ m00x + m01y + m02 ]
38
* [ y'] = [ m10 m11 m12 ] [ y ] = [ m10x + m11y + m12 ]
39
* [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
40
* </pre>
41
*
42
* This class is optimized for speed and minimizes calculations based on its
43
* knowledge of the underlying matrix (as opposed to say simply performing
44
* matrix multiplication).
45
*
46
* @param {number=} opt_m00 The m00 coordinate of the transform.
47
* @param {number=} opt_m10 The m10 coordinate of the transform.
48
* @param {number=} opt_m01 The m01 coordinate of the transform.
49
* @param {number=} opt_m11 The m11 coordinate of the transform.
50
* @param {number=} opt_m02 The m02 coordinate of the transform.
51
* @param {number=} opt_m12 The m12 coordinate of the transform.
52
* @struct
53
* @constructor
54
* @final
55
*/
56
goog.math.AffineTransform = function(
57
opt_m00, opt_m10, opt_m01, opt_m11, opt_m02, opt_m12) {
58
if (arguments.length == 6) {
59
this.setTransform(
60
/** @type {number} */ (opt_m00),
61
/** @type {number} */ (opt_m10),
62
/** @type {number} */ (opt_m01),
63
/** @type {number} */ (opt_m11),
64
/** @type {number} */ (opt_m02),
65
/** @type {number} */ (opt_m12));
66
} else if (arguments.length != 0) {
67
throw Error('Insufficient matrix parameters');
68
} else {
69
this.m00_ = this.m11_ = 1;
70
this.m10_ = this.m01_ = this.m02_ = this.m12_ = 0;
71
}
72
};
73
74
75
/**
76
* @return {boolean} Whether this transform is the identity transform.
77
*/
78
goog.math.AffineTransform.prototype.isIdentity = function() {
79
return this.m00_ == 1 && this.m10_ == 0 && this.m01_ == 0 && this.m11_ == 1 &&
80
this.m02_ == 0 && this.m12_ == 0;
81
};
82
83
84
/**
85
* @return {!goog.math.AffineTransform} A copy of this transform.
86
*/
87
goog.math.AffineTransform.prototype.clone = function() {
88
return new goog.math.AffineTransform(
89
this.m00_, this.m10_, this.m01_, this.m11_, this.m02_, this.m12_);
90
};
91
92
93
/**
94
* Sets this transform to the matrix specified by the 6 values.
95
*
96
* @param {number} m00 The m00 coordinate of the transform.
97
* @param {number} m10 The m10 coordinate of the transform.
98
* @param {number} m01 The m01 coordinate of the transform.
99
* @param {number} m11 The m11 coordinate of the transform.
100
* @param {number} m02 The m02 coordinate of the transform.
101
* @param {number} m12 The m12 coordinate of the transform.
102
* @return {!goog.math.AffineTransform} This affine transform.
103
*/
104
goog.math.AffineTransform.prototype.setTransform = function(
105
m00, m10, m01, m11, m02, m12) {
106
if (!goog.isNumber(m00) || !goog.isNumber(m10) || !goog.isNumber(m01) ||
107
!goog.isNumber(m11) || !goog.isNumber(m02) || !goog.isNumber(m12)) {
108
throw Error('Invalid transform parameters');
109
}
110
this.m00_ = m00;
111
this.m10_ = m10;
112
this.m01_ = m01;
113
this.m11_ = m11;
114
this.m02_ = m02;
115
this.m12_ = m12;
116
return this;
117
};
118
119
120
/**
121
* Sets this transform to be identical to the given transform.
122
*
123
* @param {!goog.math.AffineTransform} tx The transform to copy.
124
* @return {!goog.math.AffineTransform} This affine transform.
125
*/
126
goog.math.AffineTransform.prototype.copyFrom = function(tx) {
127
this.m00_ = tx.m00_;
128
this.m10_ = tx.m10_;
129
this.m01_ = tx.m01_;
130
this.m11_ = tx.m11_;
131
this.m02_ = tx.m02_;
132
this.m12_ = tx.m12_;
133
return this;
134
};
135
136
137
/**
138
* Concatenates this transform with a scaling transformation.
139
*
140
* @param {number} sx The x-axis scaling factor.
141
* @param {number} sy The y-axis scaling factor.
142
* @return {!goog.math.AffineTransform} This affine transform.
143
*/
144
goog.math.AffineTransform.prototype.scale = function(sx, sy) {
145
this.m00_ *= sx;
146
this.m10_ *= sx;
147
this.m01_ *= sy;
148
this.m11_ *= sy;
149
return this;
150
};
151
152
153
/**
154
* Pre-concatenates this transform with a scaling transformation,
155
* i.e. calculates the following matrix product:
156
*
157
* <pre>
158
* [sx 0 0] [m00 m01 m02]
159
* [ 0 sy 0] [m10 m11 m12]
160
* [ 0 0 1] [ 0 0 1]
161
* </pre>
162
*
163
* @param {number} sx The x-axis scaling factor.
164
* @param {number} sy The y-axis scaling factor.
165
* @return {!goog.math.AffineTransform} This affine transform.
166
*/
167
goog.math.AffineTransform.prototype.preScale = function(sx, sy) {
168
this.m00_ *= sx;
169
this.m01_ *= sx;
170
this.m02_ *= sx;
171
this.m10_ *= sy;
172
this.m11_ *= sy;
173
this.m12_ *= sy;
174
return this;
175
};
176
177
178
/**
179
* Concatenates this transform with a translate transformation.
180
*
181
* @param {number} dx The distance to translate in the x direction.
182
* @param {number} dy The distance to translate in the y direction.
183
* @return {!goog.math.AffineTransform} This affine transform.
184
*/
185
goog.math.AffineTransform.prototype.translate = function(dx, dy) {
186
this.m02_ += dx * this.m00_ + dy * this.m01_;
187
this.m12_ += dx * this.m10_ + dy * this.m11_;
188
return this;
189
};
190
191
192
/**
193
* Pre-concatenates this transform with a translate transformation,
194
* i.e. calculates the following matrix product:
195
*
196
* <pre>
197
* [1 0 dx] [m00 m01 m02]
198
* [0 1 dy] [m10 m11 m12]
199
* [0 0 1] [ 0 0 1]
200
* </pre>
201
*
202
* @param {number} dx The distance to translate in the x direction.
203
* @param {number} dy The distance to translate in the y direction.
204
* @return {!goog.math.AffineTransform} This affine transform.
205
*/
206
goog.math.AffineTransform.prototype.preTranslate = function(dx, dy) {
207
this.m02_ += dx;
208
this.m12_ += dy;
209
return this;
210
};
211
212
213
/**
214
* Concatenates this transform with a rotation transformation around an anchor
215
* point.
216
*
217
* @param {number} theta The angle of rotation measured in radians.
218
* @param {number} x The x coordinate of the anchor point.
219
* @param {number} y The y coordinate of the anchor point.
220
* @return {!goog.math.AffineTransform} This affine transform.
221
*/
222
goog.math.AffineTransform.prototype.rotate = function(theta, x, y) {
223
return this.concatenate(
224
goog.math.AffineTransform.getRotateInstance(theta, x, y));
225
};
226
227
228
/**
229
* Pre-concatenates this transform with a rotation transformation around an
230
* anchor point.
231
*
232
* @param {number} theta The angle of rotation measured in radians.
233
* @param {number} x The x coordinate of the anchor point.
234
* @param {number} y The y coordinate of the anchor point.
235
* @return {!goog.math.AffineTransform} This affine transform.
236
*/
237
goog.math.AffineTransform.prototype.preRotate = function(theta, x, y) {
238
return this.preConcatenate(
239
goog.math.AffineTransform.getRotateInstance(theta, x, y));
240
};
241
242
243
/**
244
* Concatenates this transform with a shear transformation.
245
*
246
* @param {number} shx The x shear factor.
247
* @param {number} shy The y shear factor.
248
* @return {!goog.math.AffineTransform} This affine transform.
249
*/
250
goog.math.AffineTransform.prototype.shear = function(shx, shy) {
251
var m00 = this.m00_;
252
var m10 = this.m10_;
253
this.m00_ += shy * this.m01_;
254
this.m10_ += shy * this.m11_;
255
this.m01_ += shx * m00;
256
this.m11_ += shx * m10;
257
return this;
258
};
259
260
261
/**
262
* Pre-concatenates this transform with a shear transformation.
263
* i.e. calculates the following matrix product:
264
*
265
* <pre>
266
* [ 1 shx 0] [m00 m01 m02]
267
* [shy 1 0] [m10 m11 m12]
268
* [ 0 0 1] [ 0 0 1]
269
* </pre>
270
*
271
* @param {number} shx The x shear factor.
272
* @param {number} shy The y shear factor.
273
* @return {!goog.math.AffineTransform} This affine transform.
274
*/
275
goog.math.AffineTransform.prototype.preShear = function(shx, shy) {
276
var m00 = this.m00_;
277
var m01 = this.m01_;
278
var m02 = this.m02_;
279
this.m00_ += shx * this.m10_;
280
this.m01_ += shx * this.m11_;
281
this.m02_ += shx * this.m12_;
282
this.m10_ += shy * m00;
283
this.m11_ += shy * m01;
284
this.m12_ += shy * m02;
285
return this;
286
};
287
288
289
/**
290
* @return {string} A string representation of this transform. The format of
291
* of the string is compatible with SVG matrix notation, i.e.
292
* "matrix(a,b,c,d,e,f)".
293
* @override
294
*/
295
goog.math.AffineTransform.prototype.toString = function() {
296
return 'matrix(' +
297
[this.m00_, this.m10_, this.m01_, this.m11_, this.m02_, this.m12_].join(
298
',') +
299
')';
300
};
301
302
303
/**
304
* @return {number} The scaling factor in the x-direction (m00).
305
*/
306
goog.math.AffineTransform.prototype.getScaleX = function() {
307
return this.m00_;
308
};
309
310
311
/**
312
* @return {number} The scaling factor in the y-direction (m11).
313
*/
314
goog.math.AffineTransform.prototype.getScaleY = function() {
315
return this.m11_;
316
};
317
318
319
/**
320
* @return {number} The translation in the x-direction (m02).
321
*/
322
goog.math.AffineTransform.prototype.getTranslateX = function() {
323
return this.m02_;
324
};
325
326
327
/**
328
* @return {number} The translation in the y-direction (m12).
329
*/
330
goog.math.AffineTransform.prototype.getTranslateY = function() {
331
return this.m12_;
332
};
333
334
335
/**
336
* @return {number} The shear factor in the x-direction (m01).
337
*/
338
goog.math.AffineTransform.prototype.getShearX = function() {
339
return this.m01_;
340
};
341
342
343
/**
344
* @return {number} The shear factor in the y-direction (m10).
345
*/
346
goog.math.AffineTransform.prototype.getShearY = function() {
347
return this.m10_;
348
};
349
350
351
/**
352
* Concatenates an affine transform to this transform.
353
*
354
* @param {!goog.math.AffineTransform} tx The transform to concatenate.
355
* @return {!goog.math.AffineTransform} This affine transform.
356
*/
357
goog.math.AffineTransform.prototype.concatenate = function(tx) {
358
var m0 = this.m00_;
359
var m1 = this.m01_;
360
this.m00_ = tx.m00_ * m0 + tx.m10_ * m1;
361
this.m01_ = tx.m01_ * m0 + tx.m11_ * m1;
362
this.m02_ += tx.m02_ * m0 + tx.m12_ * m1;
363
364
m0 = this.m10_;
365
m1 = this.m11_;
366
this.m10_ = tx.m00_ * m0 + tx.m10_ * m1;
367
this.m11_ = tx.m01_ * m0 + tx.m11_ * m1;
368
this.m12_ += tx.m02_ * m0 + tx.m12_ * m1;
369
return this;
370
};
371
372
373
/**
374
* Pre-concatenates an affine transform to this transform.
375
*
376
* @param {!goog.math.AffineTransform} tx The transform to preconcatenate.
377
* @return {!goog.math.AffineTransform} This affine transform.
378
*/
379
goog.math.AffineTransform.prototype.preConcatenate = function(tx) {
380
var m0 = this.m00_;
381
var m1 = this.m10_;
382
this.m00_ = tx.m00_ * m0 + tx.m01_ * m1;
383
this.m10_ = tx.m10_ * m0 + tx.m11_ * m1;
384
385
m0 = this.m01_;
386
m1 = this.m11_;
387
this.m01_ = tx.m00_ * m0 + tx.m01_ * m1;
388
this.m11_ = tx.m10_ * m0 + tx.m11_ * m1;
389
390
m0 = this.m02_;
391
m1 = this.m12_;
392
this.m02_ = tx.m00_ * m0 + tx.m01_ * m1 + tx.m02_;
393
this.m12_ = tx.m10_ * m0 + tx.m11_ * m1 + tx.m12_;
394
return this;
395
};
396
397
398
/**
399
* Transforms an array of coordinates by this transform and stores the result
400
* into a destination array.
401
*
402
* @param {!Array<number>} src The array containing the source points
403
* as x, y value pairs.
404
* @param {number} srcOff The offset to the first point to be transformed.
405
* @param {!Array<number>} dst The array into which to store the transformed
406
* point pairs.
407
* @param {number} dstOff The offset of the location of the first transformed
408
* point in the destination array.
409
* @param {number} numPts The number of points to transform.
410
*/
411
goog.math.AffineTransform.prototype.transform = function(
412
src, srcOff, dst, dstOff, numPts) {
413
var i = srcOff;
414
var j = dstOff;
415
var srcEnd = srcOff + 2 * numPts;
416
while (i < srcEnd) {
417
var x = src[i++];
418
var y = src[i++];
419
dst[j++] = x * this.m00_ + y * this.m01_ + this.m02_;
420
dst[j++] = x * this.m10_ + y * this.m11_ + this.m12_;
421
}
422
};
423
424
425
/**
426
* @return {number} The determinant of this transform.
427
*/
428
goog.math.AffineTransform.prototype.getDeterminant = function() {
429
return this.m00_ * this.m11_ - this.m01_ * this.m10_;
430
};
431
432
433
/**
434
* Returns whether the transform is invertible. A transform is not invertible
435
* if the determinant is 0 or any value is non-finite or NaN.
436
*
437
* @return {boolean} Whether the transform is invertible.
438
*/
439
goog.math.AffineTransform.prototype.isInvertible = function() {
440
var det = this.getDeterminant();
441
return isFinite(det) && isFinite(this.m02_) && isFinite(this.m12_) &&
442
det != 0;
443
};
444
445
446
/**
447
* @return {!goog.math.AffineTransform} An AffineTransform object
448
* representing the inverse transformation.
449
*/
450
goog.math.AffineTransform.prototype.createInverse = function() {
451
var det = this.getDeterminant();
452
return new goog.math.AffineTransform(
453
this.m11_ / det, -this.m10_ / det, -this.m01_ / det, this.m00_ / det,
454
(this.m01_ * this.m12_ - this.m11_ * this.m02_) / det,
455
(this.m10_ * this.m02_ - this.m00_ * this.m12_) / det);
456
};
457
458
459
/**
460
* Creates a transform representing a scaling transformation.
461
*
462
* @param {number} sx The x-axis scaling factor.
463
* @param {number} sy The y-axis scaling factor.
464
* @return {!goog.math.AffineTransform} A transform representing a scaling
465
* transformation.
466
*/
467
goog.math.AffineTransform.getScaleInstance = function(sx, sy) {
468
return new goog.math.AffineTransform().setToScale(sx, sy);
469
};
470
471
472
/**
473
* Creates a transform representing a translation transformation.
474
*
475
* @param {number} dx The distance to translate in the x direction.
476
* @param {number} dy The distance to translate in the y direction.
477
* @return {!goog.math.AffineTransform} A transform representing a
478
* translation transformation.
479
*/
480
goog.math.AffineTransform.getTranslateInstance = function(dx, dy) {
481
return new goog.math.AffineTransform().setToTranslation(dx, dy);
482
};
483
484
485
/**
486
* Creates a transform representing a shearing transformation.
487
*
488
* @param {number} shx The x-axis shear factor.
489
* @param {number} shy The y-axis shear factor.
490
* @return {!goog.math.AffineTransform} A transform representing a shearing
491
* transformation.
492
*/
493
goog.math.AffineTransform.getShearInstance = function(shx, shy) {
494
return new goog.math.AffineTransform().setToShear(shx, shy);
495
};
496
497
498
/**
499
* Creates a transform representing a rotation transformation.
500
*
501
* @param {number} theta The angle of rotation measured in radians.
502
* @param {number} x The x coordinate of the anchor point.
503
* @param {number} y The y coordinate of the anchor point.
504
* @return {!goog.math.AffineTransform} A transform representing a rotation
505
* transformation.
506
*/
507
goog.math.AffineTransform.getRotateInstance = function(theta, x, y) {
508
return new goog.math.AffineTransform().setToRotation(theta, x, y);
509
};
510
511
512
/**
513
* Sets this transform to a scaling transformation.
514
*
515
* @param {number} sx The x-axis scaling factor.
516
* @param {number} sy The y-axis scaling factor.
517
* @return {!goog.math.AffineTransform} This affine transform.
518
*/
519
goog.math.AffineTransform.prototype.setToScale = function(sx, sy) {
520
return this.setTransform(sx, 0, 0, sy, 0, 0);
521
};
522
523
524
/**
525
* Sets this transform to a translation transformation.
526
*
527
* @param {number} dx The distance to translate in the x direction.
528
* @param {number} dy The distance to translate in the y direction.
529
* @return {!goog.math.AffineTransform} This affine transform.
530
*/
531
goog.math.AffineTransform.prototype.setToTranslation = function(dx, dy) {
532
return this.setTransform(1, 0, 0, 1, dx, dy);
533
};
534
535
536
/**
537
* Sets this transform to a shearing transformation.
538
*
539
* @param {number} shx The x-axis shear factor.
540
* @param {number} shy The y-axis shear factor.
541
* @return {!goog.math.AffineTransform} This affine transform.
542
*/
543
goog.math.AffineTransform.prototype.setToShear = function(shx, shy) {
544
return this.setTransform(1, shy, shx, 1, 0, 0);
545
};
546
547
548
/**
549
* Sets this transform to a rotation transformation.
550
*
551
* @param {number} theta The angle of rotation measured in radians.
552
* @param {number} x The x coordinate of the anchor point.
553
* @param {number} y The y coordinate of the anchor point.
554
* @return {!goog.math.AffineTransform} This affine transform.
555
*/
556
goog.math.AffineTransform.prototype.setToRotation = function(theta, x, y) {
557
var cos = Math.cos(theta);
558
var sin = Math.sin(theta);
559
return this.setTransform(
560
cos, sin, -sin, cos, x - x * cos + y * sin, y - x * sin - y * cos);
561
};
562
563
564
/**
565
* Compares two affine transforms for equality.
566
*
567
* @param {goog.math.AffineTransform} tx The other affine transform.
568
* @return {boolean} whether the two transforms are equal.
569
*/
570
goog.math.AffineTransform.prototype.equals = function(tx) {
571
if (this == tx) {
572
return true;
573
}
574
if (!tx) {
575
return false;
576
}
577
return this.m00_ == tx.m00_ && this.m01_ == tx.m01_ && this.m02_ == tx.m02_ &&
578
this.m10_ == tx.m10_ && this.m11_ == tx.m11_ && this.m12_ == tx.m12_;
579
};
580
581