1 /***************************************
  2  * Copyright 2011, 2012 GlobWeb contributors.
  3  *
  4  * This file is part of GlobWeb.
  5  *
  6  * GlobWeb is free software: you can redistribute it and/or modify
  7  * it under the terms of the GNU Lesser General Public License as published by
  8  * the Free Software Foundation, version 3 of the License, or
  9  * (at your option) any later version.
 10  *
 11  * GlobWeb is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 14  * GNU Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU General Public License
 17  * along with GlobWeb. If not, see <http://www.gnu.org/licenses/>.
 18  ***************************************/
 19 
 20 define( function() {
 21 
 22 /**************************************************************************************************************/
 23 
 24 /**
 25 	Declare namespace for Numeric functions.
 26 	TODO : Should be put into GlobWeb
 27  */
 28 var Numeric = {};
 29 
 30 /**************************************************************************************************************/
 31 
 32 /**
 33   Linear interpolation between [a, b], t must be [0, 1]
 34 */
 35 Numeric.lerp = function(t, a, b)
 36 {
 37     return a + ((b - a) * t);
 38 }
 39 
 40 /**************************************************************************************************************/
 41 
 42 /**
 43  Cubic interpolation between [a, b], t must be [0, 1]
 44 */
 45 Numeric.cubicInterpolation = function(t, startPos, startVel, endPos, endVel)
 46 {
 47 	var t2 = t * t;
 48 	var t3 = t2 * t; 
 49 	
 50 	// Evaluate the position
 51 	
 52 	var M00 = 2 * startPos[0] - 2 * endPos[0] + startVel[0] + endVel[0];
 53 	var M10 = 2 * startPos[1] - 2 * endPos[1] + startVel[1] + endVel[1];
 54 	var M20 = 2 * startPos[2] - 2 * endPos[2] + startVel[2] + endVel[2];
 55 
 56 	var M01 = -3 * startPos[0] + 3 * endPos[0] - 2 * startVel[0] - endVel[0];
 57 	var M11 = -3 * startPos[1] + 3 * endPos[1] - 2 * startVel[1] - endVel[1];
 58 	var M21 = -3 * startPos[2] + 3 * endPos[2] - 2 * startVel[2] - endVel[2];
 59 	
 60 	var position = vec3.create();
 61 	position[0] = M00 * t3 + M01 * t2 + startVel[0] * t + startPos[0];
 62 	position[1] = M10 * t3 + M11 * t2 + startVel[1] * t + startPos[1];
 63 	position[2] = M20 * t3 + M21 * t2 + startVel[2] * t + startPos[2];
 64 	
 65 	return position;
 66 }
 67 
 68 /**************************************************************************************************************/
 69 
 70 /**
 71  Cubic interpolation between [a, b], t must be [0, 1]
 72 */
 73 Numeric.cubicInterpolationDerivative = function(t, startPos, startVel, endPos, endVel)
 74 {
 75 	var t2 = t * t;
 76 	
 77 	// Evaluates the direction
 78 
 79 	var M01 = 6 * startPos[0] - 6 * endPos[0] + 3 * startVel[0] + 3 * endVel[0];
 80 	var M11 = 6 * startPos[1] - 6 * endPos[1] + 3 * startVel[1] + 3 * endVel[1];
 81 	var M21 = 6 * startPos[2] - 6 * endPos[2] + 3 * startVel[2] + 3 * endVel[2];
 82 
 83 	var M02 = -6 * startPos[0] + 6 * endPos[0] - 4 * startVel[0] - 2 * endVel[0];
 84 	var M12 = -6 * startPos[1] + 6 * endPos[1] - 4 * startVel[1] - 2 * endVel[1];
 85 	var M22 = -6 * startPos[2] + 6 * endPos[2] - 4 * startVel[2] - 2 * endVel[2];
 86 
 87 	var direction = vec3.create();
 88 	direction[0] = M01 * t2 + M02 * t + startVel[0];
 89 	direction[1] = M11 * t2 + M12 * t + startVel[1];
 90 	direction[2] = M21 * t2 + M22 * t + startVel[2];
 91 	
 92 	return direction;
 93 }
 94 
 95 /**************************************************************************************************************/
 96 
 97 /**
 98   Map x between [xMin, xMax] to [0, 1]
 99 */
100 Numeric.map01 = function(x, xMin, xMax)
101 {
102     return (xMin != xMax) ? (x - xMin) / (xMax - xMin) : 0;
103 }
104 
105 /**************************************************************************************************************/
106 
107 /*
108   Map x between [xMin, xMax] to [outMin, outMax]
109 */
110 Numeric.mapLinear = function(x, xMin, xMax, outMin, outMax)
111 {
112     return Numeric.lerp(Numeric.map01(x, xMin, xMax), outMin, outMax);
113 }
114 
115 /**************************************************************************************************************/
116 
117 Numeric.easeInQuad = function(t)
118 {
119     return t*t;
120 }
121 
122 /**************************************************************************************************************/
123 
124 Numeric.easeOutQuad = function(t)
125 {
126     // use 1-(t^2) with input [-1, 0]
127     var v = t - 1; // map [0 1] to [-1 0]
128     return 1.0-(v*v);
129 }
130 
131 /**************************************************************************************************************/
132 
133 /**
134   Remap input t ([0, 1]) to a curve starting slowly
135   and accelerating till 0.5 an decelerating till 1
136 */
137 Numeric.easeInOutQuad = function(t)
138 {
139     var out = t;
140     if (out < 0.5)
141     {
142         // use (0.5*t^2) with input [0, 1]
143         out = out+out; // map [0 0.5] outo [0 1]
144         out = 0.5*(out*out);
145     }
146     else
147     {
148         // use (0.5*(1-t)^2) with input [-1, 0]
149         out = (out+out) - 2.0; // map [0.5 1] to [-1 0]
150         out = 0.5*(1.0-(out*out));
151         out = 0.5 + out;
152     }
153     return out;
154 }
155 
156 /**************************************************************************************************************/
157 
158 /*
159  */
160 Numeric.easeOutInQuad = function(t)
161 {
162     var out = t;
163     if (out < 0.5)
164     {
165         // use (0.5*(1-t)^2) with input [-1, 0]
166         out = (out+out) - 1.0; // map [0 0.5] to [-1 0]
167         out = 0.5*(1.0-(out*out));
168     }
169     else
170     {
171         // use (0.5*t^2) with input [0, 1]
172         out = (out+out) - 1.0; // map [0.5 1] outo [0 1]
173         out = 0.5*(out*out);
174         out = 0.5 + out;
175     }
176     return out;
177 }
178 
179 /**************************************************************************************************************/
180 
181 /**
182   Convert the given degree value in radian
183 */
184 Numeric.toRadian = function(degree)
185 {
186     return degree * Math.PI / 180.0;
187 }
188 
189 /**************************************************************************************************************/
190 
191 /**
192   Convert the given radian value in degree
193 */
194 Numeric.toDegree = function(radian)
195 {
196     return radian * 180.0 / Math.PI;
197 }
198 
199 /**************************************************************************************************************/
200 
201 /**
202   Computes point on a ray
203 */
204 Numeric.pointOnRay = function(rayOrigin, rayDirection, t, dest)
205 {
206     if (!dest) { dest = vec3.create(); }
207 
208     vec3.scale(rayDirection, t, dest);
209     vec3.add(dest, rayOrigin, dest);
210 
211     return dest;
212 }
213 
214 /**************************************************************************************************************/
215 
216 /**
217   Line-line intersection
218   rayDirection must be normalized.
219   Returns t at which intersection occurs or -1 if no intersection.
220 */
221 
222 Numeric.lineIntersection = function( x1, y1, x2, y2, x3, y3, x4, y4 )
223 {
224 	var det = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
225 	if ( det == 0 )
226 	{
227 		return [-1,-1];
228 	}
229 	
230 	var ua = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3);
231 	var ub = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3);
232 	
233 	ua /= det;
234 	ub /= det;
235 	
236 	return [ ua, ub ];
237 	//return ua > 0.0 && ua < 1.0 && ub > 0.0 && ub < 1.0;
238 }
239 
240 /**************************************************************************************************************/
241 
242 /**
243   Ray sphere intersection
244   rayDirection must be normalized.
245   Returns t at which intersection occurs or -1 if no intersection.
246 */
247 Numeric.raySphereIntersection = function(rayOrigin, rayDirection, sphereCenter, sphereRadius)
248 {
249     // cf. http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
250 
251     var rs = vec3.subtract( rayOrigin, sphereCenter, vec3.create() );
252     // rayDirection is normalized so a = 1
253     // var a = vec3.dot(rayDirection, rayDirection);
254     var b = 2.0 * vec3.dot(rayDirection, rs);
255     var c = vec3.dot(rs, rs) - sphereRadius*sphereRadius;
256 
257     // as a == 1, discriminant = b^2 - (4*c)
258     // var discr = (b*b) - (4*a*c);
259     var discr = (b*b) - (4*c);
260     if (discr < 0)
261         return -1;
262 
263     // t0 = (-b - sqrt(discr)) / 2a, t1 = (-b + sqrt(discr)) / 2a, a == 1
264     discr = Math.sqrt(discr);
265     var tNear = (-b - discr) / 2;
266     var tFar  = (-b + discr) / 2;
267     if (tNear > tFar) // Swap t values
268     {
269         var tmp = tNear;
270         tNear = tFar;
271         tFar = tmp;
272     }
273 
274     if (tFar < 0) // Hit is beyond ray origin
275         return -1;
276     
277     return tNear < 0 ? tFar : tNear;
278 }
279 
280 /**************************************************************************************************************/
281 
282 /**
283  * 	Round the given number
284  * 
285  * 	@param num Number to round
286  * 	@param dec Number of decimals
287  */
288 Numeric.roundNumber = function (num, dec)
289 {
290 	var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
291 	return result;
292 }
293 
294 /**************************************************************************************************************/
295 
296 return Numeric;
297 
298 });
299 
300