1 /**
  2  * Copyright (C) 2009-2012 Klaus Reimer <k@ailis.de>
  3  * See LICENSE.txt for licensing information
  4  * 
  5  * @require threedee.js
  6  */
  7 
  8 /**
  9  * @constructor
 10  * Constructs a new empty vector.
 11  * 
 12  * @param {number=} x
 13  *            The X coordinate (Optional)
 14  * @param {number=} y
 15  *            The Y coordinate (Optional)
 16  * @param {number=} z
 17  *            The Z coordinate (Optional)
 18  * 
 19  * @class
 20  * A vector with three elements.
 21  */
 22 threedee.Vector = function(x, y, z)
 23 {
 24     if (x) this.x = x;
 25     if (y) this.y = y;
 26     if (z) this.z = z;
 27     threedee.Vector.counter++;
 28 };
 29 
 30 /** 
 31  * Instance counter. 
 32  * @private 
 33  * @type {number} 
 34  */
 35 threedee.Vector.counter = 0;
 36 
 37 /** 
 38  * The X coordinate. 
 39  * @type {number} 
 40  */
 41 threedee.Vector.prototype.x = 0;
 42 
 43 /** 
 44  * The Y coordinate. 
 45  * @type {number} 
 46  */
 47 threedee.Vector.prototype.y = 0;
 48 
 49 /** 
 50  * The Z coordinate. 
 51  * @type {number} 
 52  */
 53 threedee.Vector.prototype.z = 0;
 54 
 55 /**
 56  * Returns and resets the current instance counter.
 57  * 
 58  * @return {number} 
 59  *            The number of created instances since the last call
 60  */
 61 threedee.Vector.count = function()
 62 {
 63     var value = threedee.Vector.counter;
 64     threedee.Vector.counter = 0;
 65     return value;
 66 };
 67 
 68 /**
 69  * Returns a copy of this vector.
 70  * 
 71  * @param {?threedee.Vector=} v
 72  *            Optional target vector
 73  * @return {!threedee.Vector} A copy of this vector (or the target vector)
 74  */
 75 threedee.Vector.prototype.copy = function(v)
 76 {
 77     return (v ? v : new threedee.Vector()).set(this.x, this.y, this.z);
 78 };
 79 
 80 /**
 81  * Sets the vector coordinates.
 82  * 
 83  * @param {number} x
 84  *            The X coordinate
 85  * @param {number} y
 86  *            The Y coordinate
 87  * @param {number} z
 88  *            The Z coordinate
 89  * @return {!threedee.Vector}
 90  *            This vector
 91  */            
 92 threedee.Vector.prototype.set = function(x, y, z)
 93 {
 94     this.x = x;
 95     this.y = y;
 96     this.z = z;
 97     return this;
 98 };
 99 
100 /**
101  * Adds the coordinates of the specified vector to this one.
102  * 
103  * @param {!threedee.Vector} v
104  *            The vector to add
105  * @return {!threedee.Vector} This vector
106  */
107 threedee.Vector.prototype.add = function(v)
108 {
109     this.x += v.x;
110     this.y += v.y;
111     this.z += v.z;
112     return this;
113 };
114 
115 /**
116  * Subtracts the coordinates of the specified vector from this one.
117  * 
118  * @param {!threedee.Vector} v
119  *            The vector to subtract
120  * @return {!threedee.Vector} This vector
121  */
122 threedee.Vector.prototype.sub = function(v)
123 {
124     this.x -= v.x;
125     this.y -= v.y;
126     this.z -= v.z;
127     return this;
128 };
129 
130 /**
131  * Scales the vector with the specified factors.
132  * 
133  * @param {number} fx
134  *            The X factor
135  * @param {number} fy
136  *            The Y factor (Optional. Defaults to fx)
137  * @param {number} fz
138  *            The Z factor (Optional. Defaults to fx)
139  * @return {!threedee.Vector} This vector
140  */
141 threedee.Vector.prototype.scale = function(fx, fy, fz)
142 {
143     this.x *= fx;
144     this.y *= fy === undefined ? fx : fy;
145     this.z *= fy === undefined ? fx : fz;
146     return this;
147 };
148 
149 /**
150  * Creates and returns the dot product of this vector and the specified one.
151  * 
152  * @param {!threedee.Vector} v
153  *            The other vector
154  * @return {number}
155  *            The dot product
156  */
157 threedee.Vector.prototype.dot = function(v)
158 {
159     return this.x * v.x + this.y * v.y + this.z * v.z;   
160 };
161 
162 /**
163  * Creates the cross product of this vector and the specified one and stores
164  * the result back into this vector.
165  * 
166  * @param {!threedee.Vector} v
167  *            The other vector
168  * @return {!threedee.Vector} This vector
169  */
170 threedee.Vector.prototype.cross = function(v)
171 {
172     var x, y, z;
173     
174     x = this.y * v.z - this.z * v.y;
175     y = this.z * v.x - this.x * v.z;
176     z = this.x * v.y - this.y * v.x;
177     this.x = x;
178     this.y = y;
179     this.z = z;
180     return this;
181 };
182 
183 /**
184  * Returns the length of the vector.
185  * 
186  * @return {number} The vector length
187  */
188 threedee.Vector.prototype.length = function()
189 {
190     return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
191 };
192 
193 /**
194  * Converts this vector into a unit vector with length 1.
195  * 
196  * @return {!threedee.Vector} This vector
197  */
198 threedee.Vector.prototype.toUnit = function()
199 {
200     var len;
201     
202     len = this.length();
203     this.x /= len;
204     this.y /= len;
205     this.z /= len;
206     return this;
207 };
208 
209 /**
210  * Returns the angle between this vector and the specified one.
211  * 
212  * @param {!threedee.Vector} v
213  *            The other vector
214  * @return {number} 
215  *            The angle in clockwise RAD.
216  */
217 threedee.Vector.prototype.getAngle = function(v)
218 {
219     return Math.acos(this.copy().toUnit().dot(v.toUnit()));
220 };
221 
222 /**
223  * Transforms this vector with the specified matrix.
224  * 
225  * @param {!threedee.Matrix} m
226  *            The matrix
227  * @return {!threedee.Vector}
228  *            This vector
229  */
230 threedee.Vector.prototype.transform = function(m)
231 {
232     return this.set(
233         m.m00 * this.x + m.m01 * this.y + m.m02 * this.z + m.m03,
234         m.m10 * this.x + m.m11 * this.y + m.m12 * this.z + m.m13,
235         m.m20 * this.x + m.m21 * this.y + m.m22 * this.z + m.m23);
236 };
237 
238 /**
239  * Converts the vector into a JSON object with keys 'x', 'y' and 'z'.
240  * 
241  * @return {Object}
242  *            The vector as a JSON object
243  */
244 threedee.Vector.prototype.toJSON = function()
245 {
246     return { "x": this.x, "y": this.y, "z": this.z };
247 };
248 
249 /**
250  * Creates a new vector instance with the data read from the
251  * specified JSON object (with keys 'x', 'y' and 'z'). Returns null if data
252  * was empty.
253  * 
254  * @param {Object} data
255  *            The vector as JSON object
256  * @return {threedee.Vector} The vector object or null if data was empty
257  */
258 threedee.Vector.fromJSON = function(data)
259 {
260     if (!data) return null;
261     return new threedee.Vector(+data["x"], +data["y"], +data["z"]);
262 };
263