OLD | NEW |
1 // | 1 // |
2 // Copyright 2014 Google Inc. All rights reserved. | 2 // Copyright 2014 Google Inc. All rights reserved. |
3 // | 3 // |
4 // Use of this source code is governed by a BSD-style | 4 // Use of this source code is governed by a BSD-style |
5 // license that can be found in the LICENSE file or at | 5 // license that can be found in the LICENSE file or at |
6 // https://developers.google.com/open-source/licenses/bsd | 6 // https://developers.google.com/open-source/licenses/bsd |
7 // | 7 // |
8 | 8 |
9 part of charted.core.interpolators; | 9 part of charted.core.interpolators; |
10 | 10 |
11 /// [Interpolator] accepts [t], such that 0.0 < t < 1.0 and returns | 11 /// [Interpolator] accepts [t], such that 0.0 < t < 1.0 and returns |
12 /// a value in a pre-defined range. | 12 /// a value in a pre-defined range. |
13 typedef Interpolator(num t); | 13 typedef Interpolator(num t); |
14 | 14 |
15 /// [InterpolatorGenerator] accepts two parameters [a], [b] and returns an | 15 /// [InterpolatorGenerator] accepts two parameters [a], [b] and returns an |
16 /// [Interpolator] for transitioning from [a] to [b] | 16 /// [Interpolator] for transitioning from [a] to [b] |
17 typedef Interpolator InterpolatorGenerator(a, b); | 17 typedef Interpolator InterpolatorGenerator(a, b); |
18 | 18 |
19 /// List of registered interpolators - [createInterpolatorFromRegistry] | 19 /// List of registered interpolators - [createInterpolatorFromRegistry] |
20 /// iterates through this list from backwards and the first non-null | 20 /// iterates through this list from backwards and the first non-null |
21 /// interpolate function is returned to the caller. | 21 /// interpolate function is returned to the caller. |
22 List<InterpolatorGenerator> _interpolators = [ createInterpolatorByType ]; | 22 List<InterpolatorGenerator> _interpolators = [createInterpolatorByType]; |
23 | 23 |
24 /// Returns a default interpolator between values [a] and [b]. Unless | 24 /// Returns a default interpolator between values [a] and [b]. Unless |
25 /// more interpolators are added, one of the internal implementations are | 25 /// more interpolators are added, one of the internal implementations are |
26 /// selected by the type of [a] and [b]. | 26 /// selected by the type of [a] and [b]. |
27 Interpolator createInterpolatorFromRegistry(a, b) { | 27 Interpolator createInterpolatorFromRegistry(a, b) { |
28 var fn, i = _interpolators.length; | 28 var fn, i = _interpolators.length; |
29 while (--i >= 0 && fn == null) { | 29 while (--i >= 0 && fn == null) { |
30 fn = _interpolators[i](a, b); | 30 fn = _interpolators[i](a, b); |
31 } | 31 } |
32 return fn; | 32 return fn; |
33 } | 33 } |
34 | 34 |
35 /// Creates an interpolator based on the type of [a] and [b]. | 35 /// Creates an interpolator based on the type of [a] and [b]. |
36 /// | 36 /// |
37 /// Usage note: Use this method only when type of [a] and [b] are not known. | 37 /// Usage note: Use this method only when type of [a] and [b] are not known. |
38 /// When used, this function will prevent tree shaking of all built-in | 38 /// When used, this function will prevent tree shaking of all built-in |
39 /// interpolators. | 39 /// interpolators. |
40 Interpolator createInterpolatorByType(a, b) => | 40 Interpolator createInterpolatorByType(a, b) => (a is List && b is List) |
41 (a is List && b is List) ? createListInterpolator(a, b) : | 41 ? createListInterpolator(a, b) |
42 (a is Map && b is Map) ? createMapInterpolator(a, b) : | 42 : (a is Map && b is Map) |
43 (a is String && b is String) ? createStringInterpolator(a, b) : | 43 ? createMapInterpolator(a, b) |
44 (a is num && b is num) ? createNumberInterpolator(a, b) : | 44 : (a is String && b is String) |
45 (a is Color && b is Color) ? createRgbColorInterpolator(a, b) : | 45 ? createStringInterpolator(a, b) |
46 (t) => (t <= 0.5) ? a : b; | 46 : (a is num && b is num) |
47 | 47 ? createNumberInterpolator(a, b) |
| 48 : (a is Color && b is Color) |
| 49 ? createRgbColorInterpolator(a, b) |
| 50 : (t) => (t <= 0.5) ? a : b; |
48 | 51 |
49 // | 52 // |
50 // Implementations of InterpolatorGenerator | 53 // Implementations of InterpolatorGenerator |
51 // | 54 // |
52 | 55 |
53 /// Generate a numeric interpolator between numbers [a] and [b] | 56 /// Generate a numeric interpolator between numbers [a] and [b] |
54 Interpolator createNumberInterpolator(num a, num b) { | 57 Interpolator createNumberInterpolator(num a, num b) { |
55 b -= a; | 58 b -= a; |
56 return (t) => a + b * t; | 59 return (t) => a + b * t; |
57 } | 60 } |
58 | 61 |
59 /// Generate a rounded number interpolator between numbers [a] and [b] | 62 /// Generate a rounded number interpolator between numbers [a] and [b] |
60 Interpolator createRoundedNumberInterpolator(num a, num b) { | 63 Interpolator createRoundedNumberInterpolator(num a, num b) { |
61 b -= a; | 64 b -= a; |
62 return (t) => (a + b * t).round(); | 65 return (t) => (a + b * t).round(); |
63 } | 66 } |
64 | 67 |
65 | |
66 /// Generate an interpolator between two strings [a] and [b]. | 68 /// Generate an interpolator between two strings [a] and [b]. |
67 /// | 69 /// |
68 /// The interpolator will interpolate all the number pairs in both strings | 70 /// The interpolator will interpolate all the number pairs in both strings |
69 /// that have same number of numeric parts. The function assumes the non | 71 /// that have same number of numeric parts. The function assumes the non |
70 /// number part of the string to be identical and would use string [b] for | 72 /// number part of the string to be identical and would use string [b] for |
71 /// merging the non numeric part of the strings. | 73 /// merging the non numeric part of the strings. |
72 /// | 74 /// |
73 /// Eg: Interpolate between $100.0 and $150.0 | 75 /// Eg: Interpolate between $100.0 and $150.0 |
74 Interpolator createStringInterpolator(String a, String b) { | 76 Interpolator createStringInterpolator(String a, String b) { |
75 if (a == null || b == null) return (t) => b; | 77 if (a == null || b == null) return (t) => b; |
76 | 78 |
77 // See if both A and B represent colors as RGB or HEX strings. | 79 // See if both A and B represent colors as RGB or HEX strings. |
78 // If yes, use color interpolators | 80 // If yes, use color interpolators |
79 if (Color.isRgbColorString(a) && Color.isRgbColorString(b)) { | 81 if (Color.isRgbColorString(a) && Color.isRgbColorString(b)) { |
80 return createRgbColorInterpolator( | 82 return createRgbColorInterpolator( |
81 new Color.fromRgbString(a), new Color.fromRgbString(b)); | 83 new Color.fromRgbString(a), new Color.fromRgbString(b)); |
82 } | 84 } |
83 | 85 |
84 // See if both A and B represent colors as HSL strings. | 86 // See if both A and B represent colors as HSL strings. |
85 // If yes, use color interpolators. | 87 // If yes, use color interpolators. |
86 if (Color.isHslColorString(a) && Color.isHslColorString(b)) { | 88 if (Color.isHslColorString(a) && Color.isHslColorString(b)) { |
87 return createHslColorInterpolator( | 89 return createHslColorInterpolator( |
88 new Color.fromHslString(a), new Color.fromHslString(b)); | 90 new Color.fromHslString(a), new Color.fromHslString(b)); |
89 } | 91 } |
90 | 92 |
91 var numberRegEx = | 93 var numberRegEx = new RegExp(r'[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?'), |
92 new RegExp(r'[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?'), | |
93 numMatchesInA = numberRegEx.allMatches(a), | 94 numMatchesInA = numberRegEx.allMatches(a), |
94 numMatchesInB = numberRegEx.allMatches(b), | 95 numMatchesInB = numberRegEx.allMatches(b), |
95 stringParts = [], | 96 stringParts = [], |
96 numberPartsInA = [], | 97 numberPartsInA = [], |
97 numberPartsInB = [], | 98 numberPartsInB = [], |
98 interpolators = [], | 99 interpolators = [], |
99 s0 = 0; | 100 s0 = 0; |
100 | 101 |
101 numberPartsInA.addAll(numMatchesInA.map((m) => m.group(0))); | 102 numberPartsInA.addAll(numMatchesInA.map((m) => m.group(0))); |
102 | 103 |
103 for (Match m in numMatchesInB) { | 104 for (Match m in numMatchesInB) { |
104 stringParts.add(b.substring(s0, m.start)); | 105 stringParts.add(b.substring(s0, m.start)); |
105 numberPartsInB.add(m.group(0)); | 106 numberPartsInB.add(m.group(0)); |
106 s0 = m.end; | 107 s0 = m.end; |
107 } | 108 } |
108 | 109 |
109 if (s0 < b.length) stringParts.add(b.substring(s0)); | 110 if (s0 < b.length) stringParts.add(b.substring(s0)); |
110 | 111 |
111 int numberLength = math.min(numberPartsInA.length, numberPartsInB.length); | 112 int numberLength = math.min(numberPartsInA.length, numberPartsInB.length); |
112 int maxLength = math.max(numberPartsInA.length, numberPartsInB.length); | 113 int maxLength = math.max(numberPartsInA.length, numberPartsInB.length); |
113 for (var i = 0; i < numberLength; i++) { | 114 for (var i = 0; i < numberLength; i++) { |
114 interpolators.add(createNumberInterpolator(num.parse(numberPartsInA[i]), | 115 interpolators.add(createNumberInterpolator( |
115 num.parse(numberPartsInB[i]))); | 116 num.parse(numberPartsInA[i]), num.parse(numberPartsInB[i]))); |
116 } | 117 } |
117 if (numberPartsInA.length < numberPartsInB.length) { | 118 if (numberPartsInA.length < numberPartsInB.length) { |
118 for (var i = numberLength; i < maxLength; i++) { | 119 for (var i = numberLength; i < maxLength; i++) { |
119 interpolators.add(createNumberInterpolator(num.parse(numberPartsInB[i]), | 120 interpolators.add(createNumberInterpolator( |
120 num.parse(numberPartsInB[i]))); | 121 num.parse(numberPartsInB[i]), num.parse(numberPartsInB[i]))); |
121 } | 122 } |
122 } | 123 } |
123 | 124 |
124 return (t) { | 125 return (t) { |
125 StringBuffer sb = new StringBuffer(); | 126 StringBuffer sb = new StringBuffer(); |
126 for (var i = 0; i < stringParts.length; i++) { | 127 for (var i = 0; i < stringParts.length; i++) { |
127 sb.write(stringParts[i]); | 128 sb.write(stringParts[i]); |
128 if (interpolators.length > i) { | 129 if (interpolators.length > i) { |
129 sb.write(interpolators[i](t)); | 130 sb.write(interpolators[i](t)); |
130 } | 131 } |
131 } | 132 } |
132 return sb.toString(); | 133 return sb.toString(); |
133 }; | 134 }; |
134 } | 135 } |
135 | 136 |
136 /// Generate an interpolator for RGB values. | 137 /// Generate an interpolator for RGB values. |
137 Interpolator createRgbColorInterpolator(Color a, Color b) { | 138 Interpolator createRgbColorInterpolator(Color a, Color b) { |
138 if (a == null || b == null) return (t) => b; | 139 if (a == null || b == null) return (t) => b; |
139 var ar = a.r, | 140 var ar = a.r, ag = a.g, ab = a.b, br = b.r - ar, bg = b.g - ag, bb = b.b - ab; |
140 ag = a.g, | |
141 ab = a.b, | |
142 br = b.r - ar, | |
143 bg = b.g - ag, | |
144 bb = b.b - ab; | |
145 | 141 |
146 return (t) => new Color.fromRgba((ar + br * t).round(), | 142 return (t) => new Color.fromRgba((ar + br * t).round(), (ag + bg * t).round(), |
147 (ag + bg * t).round(), (ab + bb * t).round(), 1.0).toRgbaString(); | 143 (ab + bb * t).round(), 1.0).toRgbaString(); |
148 } | 144 } |
149 | 145 |
150 /// Generate an interpolator using HSL color system converted to Hex string. | 146 /// Generate an interpolator using HSL color system converted to Hex string. |
151 Interpolator createHslColorInterpolator(Color a, Color b) { | 147 Interpolator createHslColorInterpolator(Color a, Color b) { |
152 if (a == null || b == null) return (t) => b; | 148 if (a == null || b == null) return (t) => b; |
153 var ah = a.h, | 149 var ah = a.h, as = a.s, al = a.l, bh = b.h - ah, bs = b.s - as, bl = b.l - al; |
154 as = a.s, | |
155 al = a.l, | |
156 bh = b.h - ah, | |
157 bs = b.s - as, | |
158 bl = b.l - al; | |
159 | 150 |
160 return (t) => new Color.fromHsla((ah + bh * t).round(), | 151 return (t) => new Color.fromHsla((ah + bh * t).round(), (as + bs * t).round(), |
161 (as + bs * t).round(), (al + bl * t).round(), 1.0).toHslaString(); | 152 (al + bl * t).round(), 1.0).toHslaString(); |
162 } | 153 } |
163 | 154 |
164 /// Generates an interpolator to interpolate each element between lists | 155 /// Generates an interpolator to interpolate each element between lists |
165 /// [a] and [b] using registered interpolators. | 156 /// [a] and [b] using registered interpolators. |
166 Interpolator createListInterpolator(List a, List b) { | 157 Interpolator createListInterpolator(List a, List b) { |
167 if (a == null || b == null) return (t) => b; | 158 if (a == null || b == null) return (t) => b; |
168 var x = [], | 159 var x = [], |
169 aLength = a.length, | 160 aLength = a.length, |
170 numInterpolated = b.length, | 161 numInterpolated = b.length, |
171 n0 = math.min(aLength, numInterpolated), | 162 n0 = math.min(aLength, numInterpolated), |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 }; | 202 }; |
212 } | 203 } |
213 | 204 |
214 /// Returns the interpolator that interpolators two transform strings | 205 /// Returns the interpolator that interpolators two transform strings |
215 /// [a] and [b] by their translate, rotate, scale and skewX parts. | 206 /// [a] and [b] by their translate, rotate, scale and skewX parts. |
216 Interpolator createTransformInterpolator(String a, String b) { | 207 Interpolator createTransformInterpolator(String a, String b) { |
217 if (a == null || b == null) return (t) => b; | 208 if (a == null || b == null) return (t) => b; |
218 var numRegExStr = r'[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?', | 209 var numRegExStr = r'[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?', |
219 numberRegEx = new RegExp(numRegExStr), | 210 numberRegEx = new RegExp(numRegExStr), |
220 translateRegEx = | 211 translateRegEx = |
221 new RegExp(r'translate\(' + '$numRegExStr,$numRegExStr' + r'\)'), | 212 new RegExp(r'translate\(' + '$numRegExStr,$numRegExStr' + r'\)'), |
222 scaleRegEx = | 213 scaleRegEx = |
223 new RegExp(r'scale\(' + numRegExStr + r',' + numRegExStr + r'\)'), | 214 new RegExp(r'scale\(' + numRegExStr + r',' + numRegExStr + r'\)'), |
224 rotateRegEx = new RegExp(r'rotate\(' + numRegExStr + r'(deg)?\)'), | 215 rotateRegEx = new RegExp(r'rotate\(' + numRegExStr + r'(deg)?\)'), |
225 skewRegEx = new RegExp(r'skewX\(' + numRegExStr + r'(deg)?\)'), | 216 skewRegEx = new RegExp(r'skewX\(' + numRegExStr + r'(deg)?\)'), |
226 | |
227 translateA = translateRegEx.firstMatch(a), | 217 translateA = translateRegEx.firstMatch(a), |
228 scaleA = scaleRegEx.firstMatch(a), | 218 scaleA = scaleRegEx.firstMatch(a), |
229 rotateA = rotateRegEx.firstMatch(a), | 219 rotateA = rotateRegEx.firstMatch(a), |
230 skewA = skewRegEx.firstMatch(a), | 220 skewA = skewRegEx.firstMatch(a), |
231 | |
232 translateB = translateRegEx.firstMatch(b), | 221 translateB = translateRegEx.firstMatch(b), |
233 scaleB = scaleRegEx.firstMatch(b), | 222 scaleB = scaleRegEx.firstMatch(b), |
234 rotateB = rotateRegEx.firstMatch(b), | 223 rotateB = rotateRegEx.firstMatch(b), |
235 skewB = skewRegEx.firstMatch(b); | 224 skewB = skewRegEx.firstMatch(b); |
236 | 225 |
237 var numSetA = [], | 226 var numSetA = [], numSetB = [], tempStr, match; |
238 numSetB = [], | |
239 tempStr, match; | |
240 | 227 |
241 // translate | 228 // translate |
242 if (translateA != null) { | 229 if (translateA != null) { |
243 tempStr = a.substring(translateA.start, translateA.end); | 230 tempStr = a.substring(translateA.start, translateA.end); |
244 match = numberRegEx.allMatches(tempStr); | 231 match = numberRegEx.allMatches(tempStr); |
245 for (Match m in match) { | 232 for (Match m in match) { |
246 numSetA.add(num.parse(m.group(0))); | 233 numSetA.add(num.parse(m.group(0))); |
247 } | 234 } |
248 } else { | 235 } else { |
249 numSetA.addAll(const[0, 0]); | 236 numSetA.addAll(const [0, 0]); |
250 } | 237 } |
251 | 238 |
252 if (translateB != null) { | 239 if (translateB != null) { |
253 tempStr = b.substring(translateB.start, translateB.end); | 240 tempStr = b.substring(translateB.start, translateB.end); |
254 match = numberRegEx.allMatches(tempStr); | 241 match = numberRegEx.allMatches(tempStr); |
255 for (Match m in match) { | 242 for (Match m in match) { |
256 numSetB.add(num.parse(m.group(0))); | 243 numSetB.add(num.parse(m.group(0))); |
257 } | 244 } |
258 } else { | 245 } else { |
259 numSetB.addAll(const[0, 0]); | 246 numSetB.addAll(const [0, 0]); |
260 } | 247 } |
261 | 248 |
262 // scale | 249 // scale |
263 if (scaleA != null) { | 250 if (scaleA != null) { |
264 tempStr = a.substring(scaleA.start, scaleA.end); | 251 tempStr = a.substring(scaleA.start, scaleA.end); |
265 match = numberRegEx.allMatches(tempStr); | 252 match = numberRegEx.allMatches(tempStr); |
266 for (Match m in match) { | 253 for (Match m in match) { |
267 numSetA.add(num.parse(m.group(0))); | 254 numSetA.add(num.parse(m.group(0))); |
268 } | 255 } |
269 } else { | 256 } else { |
270 numSetA.addAll(const[1, 1]); | 257 numSetA.addAll(const [1, 1]); |
271 } | 258 } |
272 | 259 |
273 if (scaleB != null) { | 260 if (scaleB != null) { |
274 tempStr = b.substring(scaleB.start, scaleB.end); | 261 tempStr = b.substring(scaleB.start, scaleB.end); |
275 match = numberRegEx.allMatches(tempStr); | 262 match = numberRegEx.allMatches(tempStr); |
276 for (Match m in match) { | 263 for (Match m in match) { |
277 numSetB.add(num.parse(m.group(0))); | 264 numSetB.add(num.parse(m.group(0))); |
278 } | 265 } |
279 } else { | 266 } else { |
280 numSetB.addAll(const[1, 1]); | 267 numSetB.addAll(const [1, 1]); |
281 } | 268 } |
282 | 269 |
283 // rotate | 270 // rotate |
284 if (rotateA != null) { | 271 if (rotateA != null) { |
285 tempStr = a.substring(rotateA.start, rotateA.end); | 272 tempStr = a.substring(rotateA.start, rotateA.end); |
286 match = numberRegEx.firstMatch(tempStr); | 273 match = numberRegEx.firstMatch(tempStr); |
287 numSetA.add(num.parse(match.group(0))); | 274 numSetA.add(num.parse(match.group(0))); |
288 } else { | 275 } else { |
289 numSetA.add(0); | 276 numSetA.add(0); |
290 } | 277 } |
(...skipping 26 matching lines...) Expand all Loading... |
317 | 304 |
318 if (skewB != null) { | 305 if (skewB != null) { |
319 tempStr = b.substring(skewB.start, skewB.end); | 306 tempStr = b.substring(skewB.start, skewB.end); |
320 match = numberRegEx.firstMatch(tempStr); | 307 match = numberRegEx.firstMatch(tempStr); |
321 numSetB.add(num.parse(match.group(0))); | 308 numSetB.add(num.parse(match.group(0))); |
322 } else { | 309 } else { |
323 numSetB.add(0); | 310 numSetB.add(0); |
324 } | 311 } |
325 | 312 |
326 return (t) { | 313 return (t) { |
327 return | 314 return 'translate(${createNumberInterpolator(numSetA[0], numSetB[0])(t)},' |
328 'translate(${createNumberInterpolator(numSetA[0], numSetB[0])(t)},' | 315 '${createNumberInterpolator(numSetA[1], numSetB[1])(t)})' |
329 '${createNumberInterpolator(numSetA[1], numSetB[1])(t)})' | |
330 'scale(${createNumberInterpolator(numSetA[2], numSetB[2])(t)},' | 316 'scale(${createNumberInterpolator(numSetA[2], numSetB[2])(t)},' |
331 '${createNumberInterpolator(numSetA[3], numSetB[3])(t)})' | 317 '${createNumberInterpolator(numSetA[3], numSetB[3])(t)})' |
332 'rotate(${createNumberInterpolator(numSetA[4], numSetB[4])(t)})' | 318 'rotate(${createNumberInterpolator(numSetA[4], numSetB[4])(t)})' |
333 'skewX(${createNumberInterpolator(numSetA[5], numSetB[5])(t)})'; | 319 'skewX(${createNumberInterpolator(numSetA[5], numSetB[5])(t)})'; |
334 }; | 320 }; |
335 } | 321 } |
336 | 322 |
337 /// Returns the interpolator that interpolators zoom list [a] to [b]. Zoom | 323 /// Returns the interpolator that interpolators zoom list [a] to [b]. Zoom |
338 /// lists are described by triple elements [ux0, uy0, w0] and [ux1, uy1, w1]. | 324 /// lists are described by triple elements [ux0, uy0, w0] and [ux1, uy1, w1]. |
339 Interpolator createZoomInterpolator(List a, List b) { | 325 Interpolator createZoomInterpolator(List a, List b) { |
340 if (a == null || b == null) return (t) => b; | 326 if (a == null || b == null) return (t) => b; |
341 assert(a.length == b.length && a.length == 3); | 327 assert(a.length == b.length && a.length == 3); |
342 | 328 |
343 var sqrt2 = math.SQRT2, | 329 var sqrt2 = math.SQRT2, param2 = 2, param4 = 4; |
344 param2 = 2, | |
345 param4 = 4; | |
346 | 330 |
347 var ux0 = a[0], uy0 = a[1], w0 = a[2], | 331 var ux0 = a[0], uy0 = a[1], w0 = a[2], ux1 = b[0], uy1 = b[1], w1 = b[2]; |
348 ux1 = b[0], uy1 = b[1], w1 = b[2]; | |
349 | 332 |
350 var dx = ux1 - ux0, | 333 var dx = ux1 - ux0, |
351 dy = uy1 - uy0, | 334 dy = uy1 - uy0, |
352 d2 = dx * dx + dy * dy, | 335 d2 = dx * dx + dy * dy, |
353 d1 = math.sqrt(d2), | 336 d1 = math.sqrt(d2), |
354 b0 = (w1 * w1 - w0 * w0 + param4 * d2) / (2 * w0 * param2 * d1), | 337 b0 = (w1 * w1 - w0 * w0 + param4 * d2) / (2 * w0 * param2 * d1), |
355 b1 = (w1 * w1 - w0 * w0 - param4 * d2) / (2 * w1 * param2 * d1), | 338 b1 = (w1 * w1 - w0 * w0 - param4 * d2) / (2 * w1 * param2 * d1), |
356 r0 = math.log(math.sqrt(b0 * b0 + 1) - b0), | 339 r0 = math.log(math.sqrt(b0 * b0 + 1) - b0), |
357 r1 = math.log(math.sqrt(b1 * b1 + 1) - b1), | 340 r1 = math.log(math.sqrt(b1 * b1 + 1) - b1), |
358 dr = r1 - r0, | 341 dr = r1 - r0, |
359 S = ((!dr.isNaN) ? dr : math.log(w1 / w0)) / sqrt2; | 342 S = ((!dr.isNaN) ? dr : math.log(w1 / w0)) / sqrt2; |
360 | 343 |
361 return (t) { | 344 return (t) { |
362 var s = t * S; | 345 var s = t * S; |
363 if (!dr.isNaN) { | 346 if (!dr.isNaN) { |
364 // General case. | 347 // General case. |
365 var coshr0 = cosh(r0), | 348 var coshr0 = cosh(r0), |
366 u = w0 / (param2 * d1) * (coshr0 * tanh(sqrt2 * s + r0) - sinh(r0)); | 349 u = w0 / (param2 * d1) * (coshr0 * tanh(sqrt2 * s + r0) - sinh(r0)); |
367 return [ | 350 return [ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / cosh(sqrt2 * s + r0)]; |
368 ux0 + u * dx, | |
369 uy0 + u * dy, | |
370 w0 * coshr0 / cosh(sqrt2 * s + r0) | |
371 ]; | |
372 } | 351 } |
373 // Special case for u0 ~= u1. | 352 // Special case for u0 ~= u1. |
374 return [ | 353 return [ux0 + t * dx, uy0 + t * dy, w0 * math.exp(sqrt2 * s)]; |
375 ux0 + t * dx, | |
376 uy0 + t * dy, | |
377 w0 * math.exp(sqrt2 * s) | |
378 ]; | |
379 }; | 354 }; |
380 } | 355 } |
381 | 356 |
382 /// Reverse interpolator for a number. | 357 /// Reverse interpolator for a number. |
383 Interpolator uninterpolateNumber(num a, num b) { | 358 Interpolator uninterpolateNumber(num a, num b) { |
384 b = 1 / (b - a); | 359 b = 1 / (b - a); |
385 return (x) => (x - a) * b; | 360 return (x) => (x - a) * b; |
386 } | 361 } |
387 | 362 |
388 /// Reverse interpolator for a clamped number. | 363 /// Reverse interpolator for a clamped number. |
389 Interpolator uninterpolateClamp(num a, num b) { | 364 Interpolator uninterpolateClamp(num a, num b) { |
390 b = 1 / (b - a); | 365 b = 1 / (b - a); |
391 return (x) => math.max(0, math.min(1, (x - a) * b)); | 366 return (x) => math.max(0, math.min(1, (x - a) * b)); |
392 } | 367 } |
OLD | NEW |