| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2013 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 Common.Geometry = {}; | |
| 31 | |
| 32 /** | |
| 33 * @type {number} | |
| 34 */ | |
| 35 Common.Geometry._Eps = 1e-5; | |
| 36 | |
| 37 /** | |
| 38 * @unrestricted | |
| 39 */ | |
| 40 Common.Geometry.Vector = class { | |
| 41 /** | |
| 42 * @param {number} x | |
| 43 * @param {number} y | |
| 44 * @param {number} z | |
| 45 */ | |
| 46 constructor(x, y, z) { | |
| 47 this.x = x; | |
| 48 this.y = y; | |
| 49 this.z = z; | |
| 50 } | |
| 51 | |
| 52 /** | |
| 53 * @return {number} | |
| 54 */ | |
| 55 length() { | |
| 56 return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); | |
| 57 } | |
| 58 | |
| 59 normalize() { | |
| 60 var length = this.length(); | |
| 61 if (length <= Common.Geometry._Eps) | |
| 62 return; | |
| 63 | |
| 64 this.x /= length; | |
| 65 this.y /= length; | |
| 66 this.z /= length; | |
| 67 } | |
| 68 }; | |
| 69 | |
| 70 /** | |
| 71 * @unrestricted | |
| 72 */ | |
| 73 Common.Geometry.Point = class { | |
| 74 /** | |
| 75 * @param {number} x | |
| 76 * @param {number} y | |
| 77 */ | |
| 78 constructor(x, y) { | |
| 79 this.x = x; | |
| 80 this.y = y; | |
| 81 } | |
| 82 | |
| 83 /** | |
| 84 * @param {!Common.Geometry.Point} p | |
| 85 * @return {number} | |
| 86 */ | |
| 87 distanceTo(p) { | |
| 88 return Math.sqrt(Math.pow(p.x - this.x, 2) + Math.pow(p.y - this.y, 2)); | |
| 89 } | |
| 90 | |
| 91 /** | |
| 92 * @param {!Common.Geometry.Point} line | |
| 93 * @return {!Common.Geometry.Point} | |
| 94 */ | |
| 95 projectOn(line) { | |
| 96 if (line.x === 0 && line.y === 0) | |
| 97 return new Common.Geometry.Point(0, 0); | |
| 98 return line.scale((this.x * line.x + this.y * line.y) / (Math.pow(line.x, 2)
+ Math.pow(line.y, 2))); | |
| 99 } | |
| 100 | |
| 101 /** | |
| 102 * @param {number} scalar | |
| 103 * @return {!Common.Geometry.Point} | |
| 104 */ | |
| 105 scale(scalar) { | |
| 106 return new Common.Geometry.Point(this.x * scalar, this.y * scalar); | |
| 107 } | |
| 108 | |
| 109 /** | |
| 110 * @override | |
| 111 * @return {string} | |
| 112 */ | |
| 113 toString() { | |
| 114 return Math.round(this.x * 100) / 100 + ', ' + Math.round(this.y * 100) / 10
0; | |
| 115 } | |
| 116 }; | |
| 117 | |
| 118 /** | |
| 119 * @unrestricted | |
| 120 */ | |
| 121 Common.Geometry.CubicBezier = class { | |
| 122 /** | |
| 123 * @param {!Common.Geometry.Point} point1 | |
| 124 * @param {!Common.Geometry.Point} point2 | |
| 125 */ | |
| 126 constructor(point1, point2) { | |
| 127 this.controlPoints = [point1, point2]; | |
| 128 } | |
| 129 | |
| 130 /** | |
| 131 * @param {string} text | |
| 132 * @return {?Common.Geometry.CubicBezier} | |
| 133 */ | |
| 134 static parse(text) { | |
| 135 var keywordValues = Common.Geometry.CubicBezier.KeywordValues; | |
| 136 var value = text.toLowerCase().replace(/\s+/g, ''); | |
| 137 if (Object.keys(keywordValues).indexOf(value) !== -1) | |
| 138 return Common.Geometry.CubicBezier.parse(keywordValues[value]); | |
| 139 var bezierRegex = /^cubic-bezier\(([^,]+),([^,]+),([^,]+),([^,]+)\)$/; | |
| 140 var match = value.match(bezierRegex); | |
| 141 if (match) { | |
| 142 var control1 = new Common.Geometry.Point(parseFloat(match[1]), parseFloat(
match[2])); | |
| 143 var control2 = new Common.Geometry.Point(parseFloat(match[3]), parseFloat(
match[4])); | |
| 144 return new Common.Geometry.CubicBezier(control1, control2); | |
| 145 } | |
| 146 return null; | |
| 147 } | |
| 148 | |
| 149 /** | |
| 150 * @param {number} t | |
| 151 * @return {!Common.Geometry.Point} | |
| 152 */ | |
| 153 evaluateAt(t) { | |
| 154 /** | |
| 155 * @param {number} v1 | |
| 156 * @param {number} v2 | |
| 157 * @param {number} t | |
| 158 */ | |
| 159 function evaluate(v1, v2, t) { | |
| 160 return 3 * (1 - t) * (1 - t) * t * v1 + 3 * (1 - t) * t * t * v2 + Math.po
w(t, 3); | |
| 161 } | |
| 162 | |
| 163 var x = evaluate(this.controlPoints[0].x, this.controlPoints[1].x, t); | |
| 164 var y = evaluate(this.controlPoints[0].y, this.controlPoints[1].y, t); | |
| 165 return new Common.Geometry.Point(x, y); | |
| 166 } | |
| 167 | |
| 168 /** | |
| 169 * @return {string} | |
| 170 */ | |
| 171 asCSSText() { | |
| 172 var raw = 'cubic-bezier(' + this.controlPoints.join(', ') + ')'; | |
| 173 var keywordValues = Common.Geometry.CubicBezier.KeywordValues; | |
| 174 for (var keyword in keywordValues) { | |
| 175 if (raw === keywordValues[keyword]) | |
| 176 return keyword; | |
| 177 } | |
| 178 return raw; | |
| 179 } | |
| 180 }; | |
| 181 | |
| 182 /** @type {!RegExp} */ | |
| 183 Common.Geometry.CubicBezier.Regex = /((cubic-bezier\([^)]+\))|\b(linear|ease-in-
out|ease-in|ease-out|ease)\b)/g; | |
| 184 | |
| 185 Common.Geometry.CubicBezier.KeywordValues = { | |
| 186 'linear': 'cubic-bezier(0, 0, 1, 1)', | |
| 187 'ease': 'cubic-bezier(0.25, 0.1, 0.25, 1)', | |
| 188 'ease-in': 'cubic-bezier(0.42, 0, 1, 1)', | |
| 189 'ease-in-out': 'cubic-bezier(0.42, 0, 0.58, 1)', | |
| 190 'ease-out': 'cubic-bezier(0, 0, 0.58, 1)' | |
| 191 }; | |
| 192 | |
| 193 | |
| 194 /** | |
| 195 * @unrestricted | |
| 196 */ | |
| 197 Common.Geometry.EulerAngles = class { | |
| 198 /** | |
| 199 * @param {number} alpha | |
| 200 * @param {number} beta | |
| 201 * @param {number} gamma | |
| 202 */ | |
| 203 constructor(alpha, beta, gamma) { | |
| 204 this.alpha = alpha; | |
| 205 this.beta = beta; | |
| 206 this.gamma = gamma; | |
| 207 } | |
| 208 | |
| 209 /** | |
| 210 * @param {!CSSMatrix} rotationMatrix | |
| 211 * @return {!Common.Geometry.EulerAngles} | |
| 212 */ | |
| 213 static fromRotationMatrix(rotationMatrix) { | |
| 214 var beta = Math.atan2(rotationMatrix.m23, rotationMatrix.m33); | |
| 215 var gamma = Math.atan2( | |
| 216 -rotationMatrix.m13, | |
| 217 Math.sqrt(rotationMatrix.m11 * rotationMatrix.m11 + rotationMatrix.m12 *
rotationMatrix.m12)); | |
| 218 var alpha = Math.atan2(rotationMatrix.m12, rotationMatrix.m11); | |
| 219 return new Common.Geometry.EulerAngles( | |
| 220 Common.Geometry.radiansToDegrees(alpha), Common.Geometry.radiansToDegree
s(beta), | |
| 221 Common.Geometry.radiansToDegrees(gamma)); | |
| 222 } | |
| 223 | |
| 224 /** | |
| 225 * @return {string} | |
| 226 */ | |
| 227 toRotate3DString() { | |
| 228 var gammaAxisY = -Math.sin(Common.Geometry.degreesToRadians(this.beta)); | |
| 229 var gammaAxisZ = Math.cos(Common.Geometry.degreesToRadians(this.beta)); | |
| 230 var axis = {alpha: [0, 1, 0], beta: [-1, 0, 0], gamma: [0, gammaAxisY, gamma
AxisZ]}; | |
| 231 return 'rotate3d(' + axis.alpha.join(',') + ',' + this.alpha + 'deg) ' + | |
| 232 'rotate3d(' + axis.beta.join(',') + ',' + this.beta + 'deg) ' + | |
| 233 'rotate3d(' + axis.gamma.join(',') + ',' + this.gamma + 'deg)'; | |
| 234 } | |
| 235 }; | |
| 236 | |
| 237 | |
| 238 /** | |
| 239 * @param {!Common.Geometry.Vector} u | |
| 240 * @param {!Common.Geometry.Vector} v | |
| 241 * @return {number} | |
| 242 */ | |
| 243 Common.Geometry.scalarProduct = function(u, v) { | |
| 244 return u.x * v.x + u.y * v.y + u.z * v.z; | |
| 245 }; | |
| 246 | |
| 247 /** | |
| 248 * @param {!Common.Geometry.Vector} u | |
| 249 * @param {!Common.Geometry.Vector} v | |
| 250 * @return {!Common.Geometry.Vector} | |
| 251 */ | |
| 252 Common.Geometry.crossProduct = function(u, v) { | |
| 253 var x = u.y * v.z - u.z * v.y; | |
| 254 var y = u.z * v.x - u.x * v.z; | |
| 255 var z = u.x * v.y - u.y * v.x; | |
| 256 return new Common.Geometry.Vector(x, y, z); | |
| 257 }; | |
| 258 | |
| 259 /** | |
| 260 * @param {!Common.Geometry.Vector} u | |
| 261 * @param {!Common.Geometry.Vector} v | |
| 262 * @return {!Common.Geometry.Vector} | |
| 263 */ | |
| 264 Common.Geometry.subtract = function(u, v) { | |
| 265 var x = u.x - v.x; | |
| 266 var y = u.y - v.y; | |
| 267 var z = u.z - v.z; | |
| 268 return new Common.Geometry.Vector(x, y, z); | |
| 269 }; | |
| 270 | |
| 271 /** | |
| 272 * @param {!Common.Geometry.Vector} v | |
| 273 * @param {!CSSMatrix} m | |
| 274 * @return {!Common.Geometry.Vector} | |
| 275 */ | |
| 276 Common.Geometry.multiplyVectorByMatrixAndNormalize = function(v, m) { | |
| 277 var t = v.x * m.m14 + v.y * m.m24 + v.z * m.m34 + m.m44; | |
| 278 var x = (v.x * m.m11 + v.y * m.m21 + v.z * m.m31 + m.m41) / t; | |
| 279 var y = (v.x * m.m12 + v.y * m.m22 + v.z * m.m32 + m.m42) / t; | |
| 280 var z = (v.x * m.m13 + v.y * m.m23 + v.z * m.m33 + m.m43) / t; | |
| 281 return new Common.Geometry.Vector(x, y, z); | |
| 282 }; | |
| 283 | |
| 284 /** | |
| 285 * @param {!Common.Geometry.Vector} u | |
| 286 * @param {!Common.Geometry.Vector} v | |
| 287 * @return {number} | |
| 288 */ | |
| 289 Common.Geometry.calculateAngle = function(u, v) { | |
| 290 var uLength = u.length(); | |
| 291 var vLength = v.length(); | |
| 292 if (uLength <= Common.Geometry._Eps || vLength <= Common.Geometry._Eps) | |
| 293 return 0; | |
| 294 var cos = Common.Geometry.scalarProduct(u, v) / uLength / vLength; | |
| 295 if (Math.abs(cos) > 1) | |
| 296 return 0; | |
| 297 return Common.Geometry.radiansToDegrees(Math.acos(cos)); | |
| 298 }; | |
| 299 | |
| 300 /** | |
| 301 * @param {number} deg | |
| 302 * @return {number} | |
| 303 */ | |
| 304 Common.Geometry.degreesToRadians = function(deg) { | |
| 305 return deg * Math.PI / 180; | |
| 306 }; | |
| 307 | |
| 308 /** | |
| 309 * @param {number} rad | |
| 310 * @return {number} | |
| 311 */ | |
| 312 Common.Geometry.radiansToDegrees = function(rad) { | |
| 313 return rad * 180 / Math.PI; | |
| 314 }; | |
| 315 | |
| 316 /** | |
| 317 * @param {!CSSMatrix} matrix | |
| 318 * @param {!Array.<number>} points | |
| 319 * @param {{minX: number, maxX: number, minY: number, maxY: number}=} aggregateB
ounds | |
| 320 * @return {!{minX: number, maxX: number, minY: number, maxY: number}} | |
| 321 */ | |
| 322 Common.Geometry.boundsForTransformedPoints = function(matrix, points, aggregateB
ounds) { | |
| 323 if (!aggregateBounds) | |
| 324 aggregateBounds = {minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -I
nfinity}; | |
| 325 if (points.length % 3) | |
| 326 console.assert('Invalid size of points array'); | |
| 327 for (var p = 0; p < points.length; p += 3) { | |
| 328 var vector = new Common.Geometry.Vector(points[p], points[p + 1], points[p +
2]); | |
| 329 vector = Common.Geometry.multiplyVectorByMatrixAndNormalize(vector, matrix); | |
| 330 aggregateBounds.minX = Math.min(aggregateBounds.minX, vector.x); | |
| 331 aggregateBounds.maxX = Math.max(aggregateBounds.maxX, vector.x); | |
| 332 aggregateBounds.minY = Math.min(aggregateBounds.minY, vector.y); | |
| 333 aggregateBounds.maxY = Math.max(aggregateBounds.maxY, vector.y); | |
| 334 } | |
| 335 return aggregateBounds; | |
| 336 }; | |
| 337 | |
| 338 /** | |
| 339 * @unrestricted | |
| 340 */ | |
| 341 var Size = class { | |
| 342 /** | |
| 343 * @param {number} width | |
| 344 * @param {number} height | |
| 345 */ | |
| 346 constructor(width, height) { | |
| 347 this.width = width; | |
| 348 this.height = height; | |
| 349 } | |
| 350 }; | |
| 351 | |
| 352 /** | |
| 353 * @param {?Size} size | |
| 354 * @return {boolean} | |
| 355 */ | |
| 356 Size.prototype.isEqual = function(size) { | |
| 357 return !!size && this.width === size.width && this.height === size.height; | |
| 358 }; | |
| 359 | |
| 360 /** | |
| 361 * @param {!Size|number} size | |
| 362 * @return {!Size} | |
| 363 */ | |
| 364 Size.prototype.widthToMax = function(size) { | |
| 365 return new Size(Math.max(this.width, (typeof size === 'number' ? size : size.w
idth)), this.height); | |
| 366 }; | |
| 367 | |
| 368 /** | |
| 369 * @param {!Size|number} size | |
| 370 * @return {!Size} | |
| 371 */ | |
| 372 Size.prototype.addWidth = function(size) { | |
| 373 return new Size(this.width + (typeof size === 'number' ? size : size.width), t
his.height); | |
| 374 }; | |
| 375 | |
| 376 /** | |
| 377 * @param {!Size|number} size | |
| 378 * @return {!Size} | |
| 379 */ | |
| 380 Size.prototype.heightToMax = function(size) { | |
| 381 return new Size(this.width, Math.max(this.height, (typeof size === 'number' ?
size : size.height))); | |
| 382 }; | |
| 383 | |
| 384 /** | |
| 385 * @param {!Size|number} size | |
| 386 * @return {!Size} | |
| 387 */ | |
| 388 Size.prototype.addHeight = function(size) { | |
| 389 return new Size(this.width, this.height + (typeof size === 'number' ? size : s
ize.height)); | |
| 390 }; | |
| 391 | |
| 392 /** | |
| 393 * @unrestricted | |
| 394 */ | |
| 395 var Insets = class { | |
| 396 /** | |
| 397 * @param {number} left | |
| 398 * @param {number} top | |
| 399 * @param {number} right | |
| 400 * @param {number} bottom | |
| 401 */ | |
| 402 constructor(left, top, right, bottom) { | |
| 403 this.left = left; | |
| 404 this.top = top; | |
| 405 this.right = right; | |
| 406 this.bottom = bottom; | |
| 407 } | |
| 408 | |
| 409 /** | |
| 410 * @param {?Insets} insets | |
| 411 * @return {boolean} | |
| 412 */ | |
| 413 isEqual(insets) { | |
| 414 return !!insets && this.left === insets.left && this.top === insets.top && t
his.right === insets.right && | |
| 415 this.bottom === insets.bottom; | |
| 416 } | |
| 417 }; | |
| 418 | |
| 419 /** | |
| 420 * @unrestricted | |
| 421 */ | |
| 422 Common.Rect = class { | |
| 423 /** | |
| 424 * @param {number} left | |
| 425 * @param {number} top | |
| 426 * @param {number} width | |
| 427 * @param {number} height | |
| 428 */ | |
| 429 constructor(left, top, width, height) { | |
| 430 this.left = left; | |
| 431 this.top = top; | |
| 432 this.width = width; | |
| 433 this.height = height; | |
| 434 } | |
| 435 | |
| 436 /** | |
| 437 * @param {?Common.Rect} rect | |
| 438 * @return {boolean} | |
| 439 */ | |
| 440 isEqual(rect) { | |
| 441 return !!rect && this.left === rect.left && this.top === rect.top && this.wi
dth === rect.width && | |
| 442 this.height === rect.height; | |
| 443 } | |
| 444 | |
| 445 /** | |
| 446 * @param {number} scale | |
| 447 * @return {!Common.Rect} | |
| 448 */ | |
| 449 scale(scale) { | |
| 450 return new Common.Rect(this.left * scale, this.top * scale, this.width * sca
le, this.height * scale); | |
| 451 } | |
| 452 | |
| 453 /** | |
| 454 * @return {!Size} | |
| 455 */ | |
| 456 size() { | |
| 457 return new Size(this.width, this.height); | |
| 458 } | |
| 459 }; | |
| 460 | |
| 461 /** | |
| 462 * @unrestricted | |
| 463 */ | |
| 464 var Constraints = class { | |
| 465 /** | |
| 466 * @param {!Size=} minimum | |
| 467 * @param {?Size=} preferred | |
| 468 */ | |
| 469 constructor(minimum, preferred) { | |
| 470 /** | |
| 471 * @type {!Size} | |
| 472 */ | |
| 473 this.minimum = minimum || new Size(0, 0); | |
| 474 | |
| 475 /** | |
| 476 * @type {!Size} | |
| 477 */ | |
| 478 this.preferred = preferred || this.minimum; | |
| 479 | |
| 480 if (this.minimum.width > this.preferred.width || this.minimum.height > this.
preferred.height) | |
| 481 throw new Error('Minimum size is greater than preferred.'); | |
| 482 } | |
| 483 }; | |
| 484 | |
| 485 /** | |
| 486 * @param {?Constraints} constraints | |
| 487 * @return {boolean} | |
| 488 */ | |
| 489 Constraints.prototype.isEqual = function(constraints) { | |
| 490 return !!constraints && this.minimum.isEqual(constraints.minimum) && this.pref
erred.isEqual(constraints.preferred); | |
| 491 }; | |
| 492 | |
| 493 /** | |
| 494 * @param {!Constraints|number} value | |
| 495 * @return {!Constraints} | |
| 496 */ | |
| 497 Constraints.prototype.widthToMax = function(value) { | |
| 498 if (typeof value === 'number') | |
| 499 return new Constraints(this.minimum.widthToMax(value), this.preferred.widthT
oMax(value)); | |
| 500 return new Constraints(this.minimum.widthToMax(value.minimum), this.preferred.
widthToMax(value.preferred)); | |
| 501 }; | |
| 502 | |
| 503 /** | |
| 504 * @param {!Constraints|number} value | |
| 505 * @return {!Constraints} | |
| 506 */ | |
| 507 Constraints.prototype.addWidth = function(value) { | |
| 508 if (typeof value === 'number') | |
| 509 return new Constraints(this.minimum.addWidth(value), this.preferred.addWidth
(value)); | |
| 510 return new Constraints(this.minimum.addWidth(value.minimum), this.preferred.ad
dWidth(value.preferred)); | |
| 511 }; | |
| 512 | |
| 513 /** | |
| 514 * @param {!Constraints|number} value | |
| 515 * @return {!Constraints} | |
| 516 */ | |
| 517 Constraints.prototype.heightToMax = function(value) { | |
| 518 if (typeof value === 'number') | |
| 519 return new Constraints(this.minimum.heightToMax(value), this.preferred.heigh
tToMax(value)); | |
| 520 return new Constraints(this.minimum.heightToMax(value.minimum), this.preferred
.heightToMax(value.preferred)); | |
| 521 }; | |
| 522 | |
| 523 /** | |
| 524 * @param {!Constraints|number} value | |
| 525 * @return {!Constraints} | |
| 526 */ | |
| 527 Constraints.prototype.addHeight = function(value) { | |
| 528 if (typeof value === 'number') | |
| 529 return new Constraints(this.minimum.addHeight(value), this.preferred.addHeig
ht(value)); | |
| 530 return new Constraints(this.minimum.addHeight(value.minimum), this.preferred.a
ddHeight(value.preferred)); | |
| 531 }; | |
| OLD | NEW |