OLD | NEW |
| (Empty) |
1 <!DOCTYPE html> | |
2 <!-- | |
3 Copyright (c) 2014 The Chromium Authors. All rights reserved. | |
4 Use of this source code is governed by a BSD-style license that can be | |
5 found in the LICENSE file. | |
6 --> | |
7 <link rel="import" href="/tracing/base/base.html"> | |
8 <script src="/gl-matrix-min.js"></script> | |
9 | |
10 <script> | |
11 'use strict'; | |
12 | |
13 // In node, the script-src for gl-matrix-min above brings in glmatrix into | |
14 // a module, instead of into the global scope. Whereas, Tracing code | |
15 // assumes that glMatrix is in the global scope. So, in Node only, we | |
16 // require() it in, and then take all its exports and shove them into the | |
17 // global scope by hand. | |
18 (function(global) { | |
19 if (tr.isNode) { | |
20 var glMatrixAbsPath = HTMLImportsLoader.hrefToAbsolutePath( | |
21 '/gl-matrix-min.js'); | |
22 var glMatrixModule = require(glMatrixAbsPath); | |
23 for (var exportName in glMatrixModule) { | |
24 global[exportName] = glMatrixModule[exportName]; | |
25 } | |
26 } | |
27 })(this); | |
28 </script> | |
29 | |
30 <script> | |
31 'use strict'; | |
32 | |
33 tr.exportTo('tr.b', function() { | |
34 var PREFERRED_NUMBER_SERIES_MULTIPLIERS = [1, 2, 5, 10]; | |
35 | |
36 /* Returns true when x and y are within delta of each other. */ | |
37 function approximately(x, y, delta) { | |
38 if (delta === undefined) | |
39 delta = 1e-9; | |
40 return Math.abs(x - y) < delta; | |
41 } | |
42 | |
43 function clamp(x, lo, hi) { | |
44 return Math.min(Math.max(x, lo), hi); | |
45 } | |
46 | |
47 function lerp(percentage, lo, hi) { | |
48 var range = hi - lo; | |
49 return lo + percentage * range; | |
50 } | |
51 | |
52 function normalize(value, lo, hi) { | |
53 return (value - lo) / (hi - lo); | |
54 } | |
55 | |
56 function deg2rad(deg) { | |
57 return (Math.PI * deg) / 180.0; | |
58 } | |
59 | |
60 /* The Gauss error function gives the probability that a measurement (which is | |
61 * under the influence of normally distributed errors with standard deviation | |
62 * sigma = 1) is less than x from the mean value of the standard normal | |
63 * distribution. | |
64 * https://www.desmos.com/calculator/t1v4bdpske | |
65 * | |
66 * @param {number} x A tolerance for error. | |
67 * @return {number} The probability that a measurement is less than |x| from | |
68 * the mean value of the standard normal distribution. | |
69 */ | |
70 function erf(x) { | |
71 // save the sign of x | |
72 // erf(-x) = -erf(x); | |
73 var sign = (x >= 0) ? 1 : -1; | |
74 x = Math.abs(x); | |
75 | |
76 // constants | |
77 var a1 = 0.254829592; | |
78 var a2 = -0.284496736; | |
79 var a3 = 1.421413741; | |
80 var a4 = -1.453152027; | |
81 var a5 = 1.061405429; | |
82 var p = 0.3275911; | |
83 | |
84 // Abramowitz and Stegun formula 7.1.26 | |
85 // maximum error: 1.5e-7 | |
86 var t = 1.0 / (1.0 + p * x); | |
87 var y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * | |
88 Math.exp(-x * x); | |
89 return sign * y; | |
90 } | |
91 | |
92 var tmpVec2 = vec2.create(); | |
93 var tmpVec2b = vec2.create(); | |
94 var tmpVec4 = vec4.create(); | |
95 var tmpMat2d = mat2d.create(); | |
96 | |
97 vec2.createFromArray = function(arr) { | |
98 if (arr.length !== 2) | |
99 throw new Error('Should be length 2'); | |
100 var v = vec2.create(); | |
101 vec2.set(v, arr[0], arr[1]); | |
102 return v; | |
103 }; | |
104 | |
105 vec2.createXY = function(x, y) { | |
106 var v = vec2.create(); | |
107 vec2.set(v, x, y); | |
108 return v; | |
109 }; | |
110 | |
111 vec2.toString = function(a) { | |
112 return '[' + a[0] + ', ' + a[1] + ']'; | |
113 }; | |
114 | |
115 vec2.addTwoScaledUnitVectors = function(out, u1, scale1, u2, scale2) { | |
116 // out = u1 * scale1 + u2 * scale2 | |
117 vec2.scale(tmpVec2, u1, scale1); | |
118 vec2.scale(tmpVec2b, u2, scale2); | |
119 vec2.add(out, tmpVec2, tmpVec2b); | |
120 }; | |
121 | |
122 vec2.interpolatePiecewiseFunction = function(points, x) { | |
123 if (x < points[0][0]) | |
124 return points[0][1]; | |
125 for (var i = 1; i < points.length; ++i) { | |
126 if (x < points[i][0]) { | |
127 var percent = normalize(x, points[i - 1][0], points[i][0]); | |
128 return lerp(percent, points[i - 1][1], points[i][1]); | |
129 } | |
130 } | |
131 return points[points.length - 1][1]; | |
132 }; | |
133 | |
134 vec3.createXYZ = function(x, y, z) { | |
135 var v = vec3.create(); | |
136 vec3.set(v, x, y, z); | |
137 return v; | |
138 }; | |
139 | |
140 vec3.toString = function(a) { | |
141 return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; | |
142 }; | |
143 | |
144 mat2d.translateXY = function(out, x, y) { | |
145 vec2.set(tmpVec2, x, y); | |
146 mat2d.translate(out, out, tmpVec2); | |
147 }; | |
148 | |
149 mat2d.scaleXY = function(out, x, y) { | |
150 vec2.set(tmpVec2, x, y); | |
151 mat2d.scale(out, out, tmpVec2); | |
152 }; | |
153 | |
154 vec4.unitize = function(out, a) { | |
155 out[0] = a[0] / a[3]; | |
156 out[1] = a[1] / a[3]; | |
157 out[2] = a[2] / a[3]; | |
158 out[3] = 1; | |
159 return out; | |
160 }; | |
161 | |
162 vec2.copyFromVec4 = function(out, a) { | |
163 vec4.unitize(tmpVec4, a); | |
164 vec2.copy(out, tmpVec4); | |
165 }; | |
166 | |
167 /** | |
168 * @param {number} x | |
169 * @param {number=} opt_base Defaults to 10 | |
170 * @return {number} | |
171 */ | |
172 function logOrLog10(x, base) { | |
173 if (base === 10) return Math.log10(x); | |
174 return Math.log(x) / Math.log(base); | |
175 } | |
176 | |
177 /** | |
178 * @param {number} x | |
179 * @param {number=} opt_base Defaults to 10 | |
180 * @return {number} | |
181 */ | |
182 function lesserPower(x, opt_base) { | |
183 var base = opt_base || 10; | |
184 return Math.pow(base, Math.floor(logOrLog10(x, base))); | |
185 } | |
186 | |
187 /** | |
188 * @param {number} x | |
189 * @param {number=} opt_base Defaults to 10 | |
190 * @return {number} | |
191 */ | |
192 function greaterPower(x, opt_base) { | |
193 var base = opt_base || 10; | |
194 return Math.pow(base, Math.ceil(logOrLog10(x, base))); | |
195 } | |
196 | |
197 function lesserWholeNumber(x) { | |
198 if (x === 0) return 0; | |
199 const pow10 = (x < 0) ? -lesserPower(-x) : lesserPower(x); | |
200 return pow10 * Math.floor(x / pow10); | |
201 } | |
202 | |
203 function greaterWholeNumber(x) { | |
204 if (x === 0) return 0; | |
205 const pow10 = (x < 0) ? -lesserPower(-x) : lesserPower(x); | |
206 return pow10 * Math.ceil(x / pow10); | |
207 } | |
208 | |
209 /** | |
210 * Uses the 1-2-5 series to find the closest prefered number to min | |
211 * whose absolute value is at least the absolute value of |min|. | |
212 * https://en.wikipedia.org/wiki/Preferred_number | |
213 */ | |
214 function preferredNumberLargerThanMin(min) { | |
215 var absMin = Math.abs(min); | |
216 // The conservative guess is the largest power of 10 less than | |
217 // or equal to |absMin|. | |
218 var conservativeGuess = tr.b.lesserPower(absMin); | |
219 var minPreferedNumber = undefined; | |
220 for (var multiplier of PREFERRED_NUMBER_SERIES_MULTIPLIERS) { | |
221 var tightenedGuess = conservativeGuess * multiplier; | |
222 if (tightenedGuess >= absMin) { | |
223 minPreferedNumber = tightenedGuess; | |
224 break; | |
225 } | |
226 } | |
227 if (minPreferedNumber === undefined) { | |
228 throw new Error('Could not compute preferred number for ' + min); | |
229 } | |
230 if (min < 0) minPreferedNumber *= -1; | |
231 return minPreferedNumber; | |
232 } | |
233 | |
234 return { | |
235 approximately, | |
236 clamp, | |
237 lerp, | |
238 normalize, | |
239 deg2rad, | |
240 erf, | |
241 lesserPower, | |
242 greaterPower, | |
243 lesserWholeNumber, | |
244 greaterWholeNumber, | |
245 preferredNumberLargerThanMin, | |
246 }; | |
247 }); | |
248 </script> | |
OLD | NEW |