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