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
31WebInspector.Geometry = {};
32
33/**
34 * @type {number}
35 */
36WebInspector.Geometry._Eps = 1e-5;
37
38/**
39 * @constructor
40 * @param {number} x
41 * @param {number} y
42 * @param {number} z
43 */
44WebInspector.Geometry.Vector = function(x, y, z)
45{
46    this.x = x;
47    this.y = y;
48    this.z = z;
49}
50
51WebInspector.Geometry.Vector.prototype = {
52    /**
53     * @return {number}
54     */
55    length: function()
56    {
57        return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
58    },
59
60    normalize: function()
61    {
62        var length = this.length();
63        if (length <= WebInspector.Geometry._Eps)
64            return;
65
66        this.x /= length;
67        this.y /= length;
68        this.z /= length;
69    }
70}
71
72/**
73 * @constructor
74 * @param {number} alpha
75 * @param {number} beta
76 * @param {number} gamma
77 */
78WebInspector.Geometry.EulerAngles = function(alpha, beta, gamma)
79{
80    this.alpha = alpha;
81    this.beta = beta;
82    this.gamma = gamma;
83}
84
85/**
86 * @param {!CSSMatrix} rotationMatrix
87 * @return {!WebInspector.Geometry.EulerAngles}
88 */
89WebInspector.Geometry.EulerAngles.fromRotationMatrix = function(rotationMatrix)
90{
91    var beta = Math.atan2(rotationMatrix.m23, rotationMatrix.m33);
92    var gamma = Math.atan2(-rotationMatrix.m13, Math.sqrt(rotationMatrix.m11 * rotationMatrix.m11 + rotationMatrix.m12 * rotationMatrix.m12));
93    var alpha = Math.atan2(rotationMatrix.m12, rotationMatrix.m11);
94    return new WebInspector.Geometry.EulerAngles(WebInspector.Geometry.radToDeg(alpha), WebInspector.Geometry.radToDeg(beta), WebInspector.Geometry.radToDeg(gamma));
95}
96
97/**
98 * @param {!WebInspector.Geometry.Vector} u
99 * @param {!WebInspector.Geometry.Vector} v
100 * @return {number}
101 */
102WebInspector.Geometry.scalarProduct = function(u, v)
103{
104    return u.x * v.x + u.y * v.y + u.z * v.z;
105}
106
107/**
108 * @param {!WebInspector.Geometry.Vector} u
109 * @param {!WebInspector.Geometry.Vector} v
110 * @return {!WebInspector.Geometry.Vector}
111 */
112WebInspector.Geometry.crossProduct = function(u, v)
113{
114    var x = u.y * v.z - u.z * v.y;
115    var y = u.z * v.x - u.x * v.z;
116    var z = u.x * v.y - u.y * v.x;
117    return new WebInspector.Geometry.Vector(x, y, z);
118}
119
120/**
121 * @param {!WebInspector.Geometry.Vector} u
122 * @param {!WebInspector.Geometry.Vector} v
123 * @return {!WebInspector.Geometry.Vector}
124 */
125WebInspector.Geometry.subtract = function(u, v)
126{
127    var x = u.x - v.x;
128    var y = u.y - v.y;
129    var z = u.z - v.z;
130    return new WebInspector.Geometry.Vector(x, y, z);
131}
132
133/**
134 * @param {!WebInspector.Geometry.Vector} v
135 * @param {!CSSMatrix} m
136 * @return {!WebInspector.Geometry.Vector}
137 */
138WebInspector.Geometry.multiplyVectorByMatrixAndNormalize = function(v, m)
139{
140    var t = v.x * m.m14 + v.y * m.m24 + v.z * m.m34 + m.m44;
141    var x = (v.x * m.m11 + v.y * m.m21 + v.z * m.m31 + m.m41) / t;
142    var y = (v.x * m.m12 + v.y * m.m22 + v.z * m.m32 + m.m42) / t;
143    var z = (v.x * m.m13 + v.y * m.m23 + v.z * m.m33 + m.m43) / t;
144    return new WebInspector.Geometry.Vector(x, y, z);
145}
146
147/**
148 * @param {!WebInspector.Geometry.Vector} u
149 * @param {!WebInspector.Geometry.Vector} v
150 * @return {number}
151 */
152WebInspector.Geometry.calculateAngle = function(u, v)
153{
154    var uLength = u.length();
155    var vLength = v.length();
156    if (uLength <= WebInspector.Geometry._Eps || vLength <= WebInspector.Geometry._Eps)
157        return 0;
158    var cos = WebInspector.Geometry.scalarProduct(u, v) / uLength / vLength;
159    if (Math.abs(cos) > 1)
160        return 0;
161    return WebInspector.Geometry.radToDeg(Math.acos(cos));
162}
163
164/**
165 * @param {number} rad
166 * @return {number}
167 */
168WebInspector.Geometry.radToDeg = function(rad)
169{
170    return rad * 180 / Math.PI;
171}
172
173
174/**
175 * @constructor
176 * @param {number} width
177 * @param {number} height
178 */
179function Size(width, height)
180{
181    this.width = width;
182    this.height = height;
183}
184
185/**
186 * @param {?Size} size
187 * @return {boolean}
188 */
189Size.prototype.isEqual = function(size)
190{
191    return !!size && this.width === size.width && this.height === size.height;
192};
193
194/**
195 * @param {!Size|number} size
196 * @return {!Size}
197 */
198Size.prototype.widthToMax = function(size)
199{
200    return new Size(Math.max(this.width, (typeof size === "number" ? size : size.width)), this.height);
201};
202
203/**
204 * @param {!Size|number} size
205 * @return {!Size}
206 */
207Size.prototype.addWidth = function(size)
208{
209    return new Size(this.width + (typeof size === "number" ? size : size.width), this.height);
210};
211
212/**
213 * @param {!Size|number} size
214 * @return {!Size}
215 */
216Size.prototype.heightToMax = function(size)
217{
218    return new Size(this.width, Math.max(this.height, (typeof size === "number" ? size : size.height)));
219};
220
221/**
222 * @param {!Size|number} size
223 * @return {!Size}
224 */
225Size.prototype.addHeight = function(size)
226{
227    return new Size(this.width, this.height + (typeof size === "number" ? size : size.height));
228};
229