| 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 |