Adding mapbox-gl branch
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview The base interface for one-dimensional data interpolation.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.math.interpolator.Interpolator1');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An interface for one dimensional data interpolation.
|
||||
* @interface
|
||||
*/
|
||||
goog.math.interpolator.Interpolator1 = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the data to be interpolated. Note that the data points are expected
|
||||
* to be sorted according to their abscissa values and not have duplicate
|
||||
* values. E.g. calling setData([0, 0, 1], [1, 1, 3]) may give undefined
|
||||
* results, the correct call should be setData([0, 1], [1, 3]).
|
||||
* Calling setData multiple times does not merge the data samples. The last
|
||||
* call to setData is the one used when computing the interpolation.
|
||||
* @param {!Array<number>} x The abscissa of the data points.
|
||||
* @param {!Array<number>} y The ordinate of the data points.
|
||||
*/
|
||||
goog.math.interpolator.Interpolator1.prototype.setData;
|
||||
|
||||
|
||||
/**
|
||||
* Computes the interpolated value at abscissa x. If x is outside the range
|
||||
* of the data points passed in setData, the value is extrapolated.
|
||||
* @param {number} x The abscissa to sample at.
|
||||
* @return {number} The interpolated value at abscissa x.
|
||||
*/
|
||||
goog.math.interpolator.Interpolator1.prototype.interpolate;
|
||||
|
||||
|
||||
/**
|
||||
* Computes the inverse interpolator. That is, it returns invInterp s.t.
|
||||
* this.interpolate(invInterp.interpolate(t))) = t. Note that the inverse
|
||||
* interpolator is only well defined if the data being interpolated is
|
||||
* 'invertible', i.e. it represents a bijective function.
|
||||
* In addition, the returned interpolator is only guaranteed to give the exact
|
||||
* inverse at the input data passed in getData.
|
||||
* If 'this' has no data, the returned Interpolator will be empty as well.
|
||||
* @return {!goog.math.interpolator.Interpolator1} The inverse interpolator.
|
||||
*/
|
||||
goog.math.interpolator.Interpolator1.prototype.getInverse;
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A one dimensional linear interpolator.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.math.interpolator.Linear1');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.math');
|
||||
goog.require('goog.math.interpolator.Interpolator1');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A one dimensional linear interpolator.
|
||||
* @implements {goog.math.interpolator.Interpolator1}
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.math.interpolator.Linear1 = function() {
|
||||
/**
|
||||
* The abscissa of the data points.
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.x_ = [];
|
||||
|
||||
/**
|
||||
* The ordinate of the data points.
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.y_ = [];
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.math.interpolator.Linear1.prototype.setData = function(x, y) {
|
||||
goog.asserts.assert(x.length == y.length,
|
||||
'input arrays to setData should have the same length');
|
||||
if (x.length == 1) {
|
||||
this.x_ = [x[0], x[0] + 1];
|
||||
this.y_ = [y[0], y[0]];
|
||||
} else {
|
||||
this.x_ = x.slice();
|
||||
this.y_ = y.slice();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.math.interpolator.Linear1.prototype.interpolate = function(x) {
|
||||
var pos = goog.array.binarySearch(this.x_, x);
|
||||
if (pos < 0) {
|
||||
pos = -pos - 2;
|
||||
}
|
||||
pos = goog.math.clamp(pos, 0, this.x_.length - 2);
|
||||
|
||||
var progress = (x - this.x_[pos]) / (this.x_[pos + 1] - this.x_[pos]);
|
||||
return goog.math.lerp(this.y_[pos], this.y_[pos + 1], progress);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.math.interpolator.Linear1.prototype.getInverse = function() {
|
||||
var interpolator = new goog.math.interpolator.Linear1();
|
||||
interpolator.setData(this.y_, this.x_);
|
||||
return interpolator;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.math.interpolator.Linear1
|
||||
</title>
|
||||
<script src="../../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.math.interpolator.Linear1Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
goog.provide('goog.math.interpolator.Linear1Test');
|
||||
goog.setTestOnly('goog.math.interpolator.Linear1Test');
|
||||
|
||||
goog.require('goog.math.interpolator.Linear1');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
function testLinear() {
|
||||
// Test special case with no data to interpolate.
|
||||
var x = [];
|
||||
var y = [];
|
||||
var interp = new goog.math.interpolator.Linear1();
|
||||
interp.setData(x, y);
|
||||
assertTrue(isNaN(interp.interpolate(1)));
|
||||
|
||||
// Test special case with 1 data point.
|
||||
x = [0];
|
||||
y = [3];
|
||||
interp = new goog.math.interpolator.Linear1();
|
||||
interp.setData(x, y);
|
||||
assertRoughlyEquals(3, interp.interpolate(1), 1e-4);
|
||||
|
||||
// Test general case.
|
||||
x = [0, 1, 3, 6, 7];
|
||||
y = [0, 0, 0, 0, 0];
|
||||
for (var i = 0; i < x.length; ++i) {
|
||||
y[i] = Math.sin(x[i]);
|
||||
}
|
||||
interp = new goog.math.interpolator.Linear1();
|
||||
interp.setData(x, y);
|
||||
|
||||
var xi = [0, 0.5, 1, 2, 3, 4, 5, 6, 7];
|
||||
var expected = [0, 0.4207, 0.8415, 0.4913, 0.1411, 0.0009, -0.1392,
|
||||
-0.2794, 0.657];
|
||||
var result = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for (var i = 0; i < xi.length; ++i) {
|
||||
result[i] = interp.interpolate(xi[i]);
|
||||
}
|
||||
assertElementsRoughlyEqual(expected, result, 1e-4);
|
||||
}
|
||||
|
||||
|
||||
function testOutOfBounds() {
|
||||
var x = [0, 1, 2];
|
||||
var y = [2, 5, 4];
|
||||
var interp = new goog.math.interpolator.Linear1();
|
||||
interp.setData(x, y);
|
||||
assertRoughlyEquals(interp.interpolate(-1), -1, 1e-4);
|
||||
assertRoughlyEquals(interp.interpolate(4), 2, 1e-4);
|
||||
}
|
||||
|
||||
|
||||
function testInverse() {
|
||||
var x = [0, 1, 3, 6, 7];
|
||||
var y = [0, 2, 7, 8, 10];
|
||||
|
||||
var interp = new goog.math.interpolator.Linear1();
|
||||
interp.setData(x, y);
|
||||
var invInterp = interp.getInverse();
|
||||
|
||||
var xi = [0, 0.5, 1, 2, 3, 4, 5, 6, 7];
|
||||
var yi = [0, 1, 2, 4.5, 7, 7.3333, 7.6667, 8, 10];
|
||||
var resultX = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var resultY = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for (var i = 0; i < xi.length; ++i) {
|
||||
resultY[i] = interp.interpolate(xi[i]);
|
||||
resultX[i] = invInterp.interpolate(yi[i]);
|
||||
}
|
||||
assertElementsRoughlyEqual(xi, resultX, 1e-4);
|
||||
assertElementsRoughlyEqual(yi, resultY, 1e-4);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A one dimensional monotone cubic spline interpolator.
|
||||
*
|
||||
* See http://en.wikipedia.org/wiki/Monotone_cubic_interpolation.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.math.interpolator.Pchip1');
|
||||
|
||||
goog.require('goog.math');
|
||||
goog.require('goog.math.interpolator.Spline1');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A one dimensional monotone cubic spline interpolator.
|
||||
* @extends {goog.math.interpolator.Spline1}
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.math.interpolator.Pchip1 = function() {
|
||||
goog.math.interpolator.Pchip1.base(this, 'constructor');
|
||||
};
|
||||
goog.inherits(goog.math.interpolator.Pchip1, goog.math.interpolator.Spline1);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.math.interpolator.Pchip1.prototype.computeDerivatives = function(
|
||||
dx, slope) {
|
||||
var len = dx.length;
|
||||
var deriv = new Array(len + 1);
|
||||
for (var i = 1; i < len; ++i) {
|
||||
if (goog.math.sign(slope[i - 1]) * goog.math.sign(slope[i]) <= 0) {
|
||||
deriv[i] = 0;
|
||||
} else {
|
||||
var w1 = 2 * dx[i] + dx[i - 1];
|
||||
var w2 = dx[i] + 2 * dx[i - 1];
|
||||
deriv[i] = (w1 + w2) / (w1 / slope[i - 1] + w2 / slope[i]);
|
||||
}
|
||||
}
|
||||
deriv[0] = this.computeDerivativeAtBoundary_(
|
||||
dx[0], dx[1], slope[0], slope[1]);
|
||||
deriv[len] = this.computeDerivativeAtBoundary_(
|
||||
dx[len - 1], dx[len - 2], slope[len - 1], slope[len - 2]);
|
||||
return deriv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Computes the derivative of a data point at a boundary.
|
||||
* @param {number} dx0 The spacing of the 1st data point.
|
||||
* @param {number} dx1 The spacing of the 2nd data point.
|
||||
* @param {number} slope0 The slope of the 1st data point.
|
||||
* @param {number} slope1 The slope of the 2nd data point.
|
||||
* @return {number} The derivative at the 1st data point.
|
||||
* @private
|
||||
*/
|
||||
goog.math.interpolator.Pchip1.prototype.computeDerivativeAtBoundary_ = function(
|
||||
dx0, dx1, slope0, slope1) {
|
||||
var deriv = ((2 * dx0 + dx1) * slope0 - dx0 * slope1) / (dx0 + dx1);
|
||||
if (goog.math.sign(deriv) != goog.math.sign(slope0)) {
|
||||
deriv = 0;
|
||||
} else if (goog.math.sign(slope0) != goog.math.sign(slope1) &&
|
||||
Math.abs(deriv) > Math.abs(3 * slope0)) {
|
||||
deriv = 3 * slope0;
|
||||
}
|
||||
return deriv;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.math.interpolator.Pchip1
|
||||
</title>
|
||||
<script src="../../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.math.interpolator.Pchip1Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
goog.provide('goog.math.interpolator.Pchip1Test');
|
||||
goog.setTestOnly('goog.math.interpolator.Pchip1Test');
|
||||
|
||||
goog.require('goog.math.interpolator.Pchip1');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
function testSpline() {
|
||||
var x = [0, 1, 3, 6, 7];
|
||||
var y = [0, 0, 0, 0, 0];
|
||||
|
||||
for (var i = 0; i < x.length; ++i) {
|
||||
y[i] = Math.sin(x[i]);
|
||||
}
|
||||
var interp = new goog.math.interpolator.Pchip1();
|
||||
interp.setData(x, y);
|
||||
|
||||
var xi = [0, 0.5, 1, 2, 3, 4, 5, 6, 7];
|
||||
var expected = [0, 0.5756, 0.8415, 0.5428, 0.1411, -0.0595, -0.2162,
|
||||
-0.2794, 0.657];
|
||||
var result = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for (var i = 0; i < xi.length; ++i) {
|
||||
result[i] = interp.interpolate(xi[i]);
|
||||
}
|
||||
assertElementsRoughlyEqual(expected, result, 1e-4);
|
||||
}
|
||||
|
||||
|
||||
function testOutOfBounds() {
|
||||
var x = [0, 1, 2, 4];
|
||||
var y = [2, 5, 4, 2];
|
||||
var interp = new goog.math.interpolator.Pchip1();
|
||||
interp.setData(x, y);
|
||||
assertRoughlyEquals(-3, interp.interpolate(-1), 1e-4);
|
||||
assertRoughlyEquals(1, interp.interpolate(5), 1e-4);
|
||||
}
|
||||
|
||||
|
||||
function testInverse() {
|
||||
var x = [0, 1, 3, 6, 7];
|
||||
var y = [0, 2, 7, 8, 10];
|
||||
|
||||
var interp = new goog.math.interpolator.Pchip1();
|
||||
interp.setData(x, y);
|
||||
var invInterp = interp.getInverse();
|
||||
|
||||
var xi = [0, 0.5, 1, 2, 3, 4, 5, 6, 7];
|
||||
var yi = [0, 0.9548, 2, 4.8938, 7, 7.3906, 7.5902, 8, 10];
|
||||
var expectedX = [0, 0.888, 1, 0.2852, 3, 4.1206, 4.7379, 6, 7];
|
||||
var resultX = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var resultY = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for (var i = 0; i < xi.length; ++i) {
|
||||
resultY[i] = interp.interpolate(xi[i]);
|
||||
resultX[i] = invInterp.interpolate(yi[i]);
|
||||
}
|
||||
assertElementsRoughlyEqual(expectedX, resultX, 1e-4);
|
||||
assertElementsRoughlyEqual(yi, resultY, 1e-4);
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview A one dimensional cubic spline interpolator with not-a-knot
|
||||
* boundary conditions.
|
||||
*
|
||||
* See http://en.wikipedia.org/wiki/Spline_interpolation.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.math.interpolator.Spline1');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.math');
|
||||
goog.require('goog.math.interpolator.Interpolator1');
|
||||
goog.require('goog.math.tdma');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A one dimensional cubic spline interpolator with natural boundary conditions.
|
||||
* @implements {goog.math.interpolator.Interpolator1}
|
||||
* @constructor
|
||||
*/
|
||||
goog.math.interpolator.Spline1 = function() {
|
||||
/**
|
||||
* The abscissa of the data points.
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.x_ = [];
|
||||
|
||||
/**
|
||||
* The spline interval coefficients.
|
||||
* Note that, in general, the length of coeffs and x is not the same.
|
||||
* @type {!Array<!Array<number>>}
|
||||
* @private
|
||||
*/
|
||||
this.coeffs_ = [[0, 0, 0, Number.NaN]];
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.math.interpolator.Spline1.prototype.setData = function(x, y) {
|
||||
goog.asserts.assert(x.length == y.length,
|
||||
'input arrays to setData should have the same length');
|
||||
if (x.length > 0) {
|
||||
this.coeffs_ = this.computeSplineCoeffs_(x, y);
|
||||
this.x_ = x.slice();
|
||||
} else {
|
||||
this.coeffs_ = [[0, 0, 0, Number.NaN]];
|
||||
this.x_ = [];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.math.interpolator.Spline1.prototype.interpolate = function(x) {
|
||||
var pos = goog.array.binarySearch(this.x_, x);
|
||||
if (pos < 0) {
|
||||
pos = -pos - 2;
|
||||
}
|
||||
pos = goog.math.clamp(pos, 0, this.coeffs_.length - 1);
|
||||
|
||||
var d = x - this.x_[pos];
|
||||
var d2 = d * d;
|
||||
var d3 = d2 * d;
|
||||
var coeffs = this.coeffs_[pos];
|
||||
return coeffs[0] * d3 + coeffs[1] * d2 + coeffs[2] * d + coeffs[3];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Solve for the spline coefficients such that the spline precisely interpolates
|
||||
* the data points.
|
||||
* @param {Array<number>} x The abscissa of the spline data points.
|
||||
* @param {Array<number>} y The ordinate of the spline data points.
|
||||
* @return {!Array<!Array<number>>} The spline interval coefficients.
|
||||
* @private
|
||||
*/
|
||||
goog.math.interpolator.Spline1.prototype.computeSplineCoeffs_ = function(x, y) {
|
||||
var nIntervals = x.length - 1;
|
||||
var dx = new Array(nIntervals);
|
||||
var delta = new Array(nIntervals);
|
||||
for (var i = 0; i < nIntervals; ++i) {
|
||||
dx[i] = x[i + 1] - x[i];
|
||||
delta[i] = (y[i + 1] - y[i]) / dx[i];
|
||||
}
|
||||
|
||||
// Compute the spline coefficients from the 1st order derivatives.
|
||||
var coeffs = [];
|
||||
if (nIntervals == 0) {
|
||||
// Nearest neighbor interpolation.
|
||||
coeffs[0] = [0, 0, 0, y[0]];
|
||||
} else if (nIntervals == 1) {
|
||||
// Straight line interpolation.
|
||||
coeffs[0] = [0, 0, delta[0], y[0]];
|
||||
} else if (nIntervals == 2) {
|
||||
// Parabola interpolation.
|
||||
var c3 = 0;
|
||||
var c2 = (delta[1] - delta[0]) / (dx[0] + dx[1]);
|
||||
var c1 = delta[0] - c2 * dx[0];
|
||||
var c0 = y[0];
|
||||
coeffs[0] = [c3, c2, c1, c0];
|
||||
} else {
|
||||
// General Spline interpolation. Compute the 1st order derivatives from
|
||||
// the Spline equations.
|
||||
var deriv = this.computeDerivatives(dx, delta);
|
||||
for (var i = 0; i < nIntervals; ++i) {
|
||||
var c3 = (deriv[i] - 2 * delta[i] + deriv[i + 1]) / (dx[i] * dx[i]);
|
||||
var c2 = (3 * delta[i] - 2 * deriv[i] - deriv[i + 1]) / dx[i];
|
||||
var c1 = deriv[i];
|
||||
var c0 = y[i];
|
||||
coeffs[i] = [c3, c2, c1, c0];
|
||||
}
|
||||
}
|
||||
return coeffs;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Computes the derivative at each point of the spline such that
|
||||
* the curve is C2. It uses not-a-knot boundary conditions.
|
||||
* @param {Array<number>} dx The spacing between consecutive data points.
|
||||
* @param {Array<number>} slope The slopes between consecutive data points.
|
||||
* @return {!Array<number>} The Spline derivative at each data point.
|
||||
* @protected
|
||||
*/
|
||||
goog.math.interpolator.Spline1.prototype.computeDerivatives = function(
|
||||
dx, slope) {
|
||||
var nIntervals = dx.length;
|
||||
|
||||
// Compute the main diagonal of the system of equations.
|
||||
var mainDiag = new Array(nIntervals + 1);
|
||||
mainDiag[0] = dx[1];
|
||||
for (var i = 1; i < nIntervals; ++i) {
|
||||
mainDiag[i] = 2 * (dx[i] + dx[i - 1]);
|
||||
}
|
||||
mainDiag[nIntervals] = dx[nIntervals - 2];
|
||||
|
||||
// Compute the sub diagonal of the system of equations.
|
||||
var subDiag = new Array(nIntervals);
|
||||
for (var i = 0; i < nIntervals; ++i) {
|
||||
subDiag[i] = dx[i + 1];
|
||||
}
|
||||
subDiag[nIntervals - 1] = dx[nIntervals - 2] + dx[nIntervals - 1];
|
||||
|
||||
// Compute the super diagonal of the system of equations.
|
||||
var supDiag = new Array(nIntervals);
|
||||
supDiag[0] = dx[0] + dx[1];
|
||||
for (var i = 1; i < nIntervals; ++i) {
|
||||
supDiag[i] = dx[i - 1];
|
||||
}
|
||||
|
||||
// Compute the right vector of the system of equations.
|
||||
var vecRight = new Array(nIntervals + 1);
|
||||
vecRight[0] = ((dx[0] + 2 * supDiag[0]) * dx[1] * slope[0] +
|
||||
dx[0] * dx[0] * slope[1]) / supDiag[0];
|
||||
for (var i = 1; i < nIntervals; ++i) {
|
||||
vecRight[i] = 3 * (dx[i] * slope[i - 1] + dx[i - 1] * slope[i]);
|
||||
}
|
||||
vecRight[nIntervals] = (dx[nIntervals - 1] * dx[nIntervals - 1] *
|
||||
slope[nIntervals - 2] + (2 * subDiag[nIntervals - 1] +
|
||||
dx[nIntervals - 1]) * dx[nIntervals - 2] * slope[nIntervals - 1]) /
|
||||
subDiag[nIntervals - 1];
|
||||
|
||||
// Solve the system of equations.
|
||||
var deriv = goog.math.tdma.solve(
|
||||
subDiag, mainDiag, supDiag, vecRight);
|
||||
|
||||
return deriv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Note that the inverse of a cubic spline is not a cubic spline in general.
|
||||
* As a result the inverse implementation is only approximate. In
|
||||
* particular, it only guarantees the exact inverse at the original input data
|
||||
* points passed to setData.
|
||||
* @override
|
||||
*/
|
||||
goog.math.interpolator.Spline1.prototype.getInverse = function() {
|
||||
var interpolator = new goog.math.interpolator.Spline1();
|
||||
var y = [];
|
||||
for (var i = 0; i < this.x_.length; i++) {
|
||||
y[i] = this.interpolate(this.x_[i]);
|
||||
}
|
||||
interpolator.setData(y, this.x_);
|
||||
return interpolator;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!--
|
||||
Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
|
||||
Use of this source code is governed by the Apache License, Version 2.0.
|
||||
See the COPYING file for details.
|
||||
-->
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>
|
||||
Closure Unit Tests - goog.math.interpolator.Spline1
|
||||
</title>
|
||||
<script src="../../base.js">
|
||||
</script>
|
||||
<script>
|
||||
goog.require('goog.math.interpolator.Spline1Test');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
goog.provide('goog.math.interpolator.Spline1Test');
|
||||
goog.setTestOnly('goog.math.interpolator.Spline1Test');
|
||||
|
||||
goog.require('goog.math.interpolator.Spline1');
|
||||
goog.require('goog.testing.jsunit');
|
||||
|
||||
function testSpline() {
|
||||
// Test special case with no data to interpolate.
|
||||
var x = [];
|
||||
var y = [];
|
||||
var interp = new goog.math.interpolator.Spline1();
|
||||
interp.setData(x, y);
|
||||
assertTrue(isNaN(interp.interpolate(1)));
|
||||
|
||||
// Test special case with 1 data point.
|
||||
x = [0];
|
||||
y = [2];
|
||||
interp = new goog.math.interpolator.Spline1();
|
||||
interp.setData(x, y);
|
||||
assertRoughlyEquals(2, interp.interpolate(1), 1e-4);
|
||||
|
||||
// Test special case with 2 data points.
|
||||
x = [0, 1];
|
||||
y = [2, 5];
|
||||
interp = new goog.math.interpolator.Spline1();
|
||||
interp.setData(x, y);
|
||||
assertRoughlyEquals(3.5, interp.interpolate(.5), 1e-4);
|
||||
|
||||
// Test special case with 3 data points.
|
||||
x = [0, 1, 2];
|
||||
y = [2, 5, 4];
|
||||
interp = new goog.math.interpolator.Spline1();
|
||||
interp.setData(x, y);
|
||||
assertRoughlyEquals(4, interp.interpolate(.5), 1e-4);
|
||||
assertRoughlyEquals(-1, interp.interpolate(3), 1e-4);
|
||||
|
||||
// Test general case.
|
||||
x = [0, 1, 3, 6, 7];
|
||||
y = [0, 0, 0, 0, 0];
|
||||
for (var i = 0; i < x.length; ++i) {
|
||||
y[i] = Math.sin(x[i]);
|
||||
}
|
||||
interp = new goog.math.interpolator.Spline1();
|
||||
interp.setData(x, y);
|
||||
|
||||
var xi = [0, 0.5, 1, 2, 3, 4, 5, 6, 7];
|
||||
var expected = [0, 0.5775, 0.8415, 0.7047, 0.1411, -0.3601, -0.55940,
|
||||
-0.2794, 0.6570];
|
||||
var result = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for (var i = 0; i < xi.length; ++i) {
|
||||
result[i] = interp.interpolate(xi[i]);
|
||||
}
|
||||
assertElementsRoughlyEqual(expected, result, 1e-4);
|
||||
}
|
||||
|
||||
|
||||
function testOutOfBounds() {
|
||||
var x = [0, 1, 2, 4];
|
||||
var y = [2, 5, 4, 1];
|
||||
var interp = new goog.math.interpolator.Spline1();
|
||||
interp.setData(x, y);
|
||||
assertRoughlyEquals(-7.75, interp.interpolate(-1), 1e-4);
|
||||
assertRoughlyEquals(4.5, interp.interpolate(5), 1e-4);
|
||||
}
|
||||
|
||||
|
||||
function testInverse() {
|
||||
var x = [0, 1, 3, 6, 7];
|
||||
var y = [0, 2, 7, 8, 10];
|
||||
|
||||
var interp = new goog.math.interpolator.Spline1();
|
||||
interp.setData(x, y);
|
||||
var invInterp = interp.getInverse();
|
||||
|
||||
var xi = [0, 0.5, 1, 2, 3, 4, 5, 6, 7];
|
||||
var yi = [0, 0.8159, 2, 4.7892, 7, 7.6912, 7.6275, 8, 10];
|
||||
var expectedX = [0, 0.8142, 1, 0.2638, 3, 5.0534, 4.8544, 6, 7];
|
||||
var resultX = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var resultY = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
for (var i = 0; i < xi.length; ++i) {
|
||||
resultY[i] = interp.interpolate(xi[i]);
|
||||
resultX[i] = invInterp.interpolate(yi[i]);
|
||||
}
|
||||
assertElementsRoughlyEqual(expectedX, resultX, 1e-4);
|
||||
assertElementsRoughlyEqual(yi, resultY, 1e-4);
|
||||
}
|
||||
Reference in New Issue
Block a user