205 lines
5.0 KiB
JavaScript
205 lines
5.0 KiB
JavaScript
goog.provide('ol.math');
|
|
|
|
|
|
|
|
/**
|
|
* Takes a number and clamps it to within the provided bounds.
|
|
* @param {number} value The input number.
|
|
* @param {number} min The minimum value to return.
|
|
* @param {number} max The maximum value to return.
|
|
* @return {number} The input number if it is within bounds, or the nearest
|
|
* number within the bounds.
|
|
*/
|
|
ol.math.clamp = function(value, min, max) {
|
|
return Math.min(Math.max(value, min), max);
|
|
};
|
|
|
|
|
|
/**
|
|
* Return the hyperbolic cosine of a given number. The method will use the
|
|
* native `Math.cosh` function if it is available, otherwise the hyperbolic
|
|
* cosine will be calculated via the reference implementation of the Mozilla
|
|
* developer network.
|
|
*
|
|
* @param {number} x X.
|
|
* @return {number} Hyperbolic cosine of x.
|
|
*/
|
|
ol.math.cosh = (function() {
|
|
// Wrapped in a iife, to save the overhead of checking for the native
|
|
// implementation on every invocation.
|
|
var cosh;
|
|
if ('cosh' in Math) {
|
|
// The environment supports the native Math.cosh function, use it…
|
|
cosh = Math.cosh;
|
|
} else {
|
|
// … else, use the reference implementation of MDN:
|
|
cosh = function(x) {
|
|
var y = Math.exp(x);
|
|
return (y + 1 / y) / 2;
|
|
};
|
|
}
|
|
return cosh;
|
|
}());
|
|
|
|
|
|
/**
|
|
* @param {number} x X.
|
|
* @return {number} The smallest power of two greater than or equal to x.
|
|
*/
|
|
ol.math.roundUpToPowerOfTwo = function(x) {
|
|
ol.assert(0 < x, 29); // `x` must be greater than `0`
|
|
return Math.pow(2, Math.ceil(Math.log(x) / Math.LN2));
|
|
};
|
|
|
|
|
|
/**
|
|
* Returns the square of the closest distance between the point (x, y) and the
|
|
* line segment (x1, y1) to (x2, y2).
|
|
* @param {number} x X.
|
|
* @param {number} y Y.
|
|
* @param {number} x1 X1.
|
|
* @param {number} y1 Y1.
|
|
* @param {number} x2 X2.
|
|
* @param {number} y2 Y2.
|
|
* @return {number} Squared distance.
|
|
*/
|
|
ol.math.squaredSegmentDistance = function(x, y, x1, y1, x2, y2) {
|
|
var dx = x2 - x1;
|
|
var dy = y2 - y1;
|
|
if (dx !== 0 || dy !== 0) {
|
|
var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
|
|
if (t > 1) {
|
|
x1 = x2;
|
|
y1 = y2;
|
|
} else if (t > 0) {
|
|
x1 += dx * t;
|
|
y1 += dy * t;
|
|
}
|
|
}
|
|
return ol.math.squaredDistance(x, y, x1, y1);
|
|
};
|
|
|
|
|
|
/**
|
|
* Returns the square of the distance between the points (x1, y1) and (x2, y2).
|
|
* @param {number} x1 X1.
|
|
* @param {number} y1 Y1.
|
|
* @param {number} x2 X2.
|
|
* @param {number} y2 Y2.
|
|
* @return {number} Squared distance.
|
|
*/
|
|
ol.math.squaredDistance = function(x1, y1, x2, y2) {
|
|
var dx = x2 - x1;
|
|
var dy = y2 - y1;
|
|
return dx * dx + dy * dy;
|
|
};
|
|
|
|
|
|
/**
|
|
* Solves system of linear equations using Gaussian elimination method.
|
|
*
|
|
* @param {Array.<Array.<number>>} mat Augmented matrix (n x n + 1 column)
|
|
* in row-major order.
|
|
* @return {Array.<number>} The resulting vector.
|
|
*/
|
|
ol.math.solveLinearSystem = function(mat) {
|
|
var n = mat.length;
|
|
|
|
if (goog.DEBUG) {
|
|
for (var row = 0; row < n; row++) {
|
|
console.assert(mat[row].length == n + 1,
|
|
'every row should have correct number of columns');
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < n; i++) {
|
|
// Find max in the i-th column (ignoring i - 1 first rows)
|
|
var maxRow = i;
|
|
var maxEl = Math.abs(mat[i][i]);
|
|
for (var r = i + 1; r < n; r++) {
|
|
var absValue = Math.abs(mat[r][i]);
|
|
if (absValue > maxEl) {
|
|
maxEl = absValue;
|
|
maxRow = r;
|
|
}
|
|
}
|
|
|
|
if (maxEl === 0) {
|
|
return null; // matrix is singular
|
|
}
|
|
|
|
// Swap max row with i-th (current) row
|
|
var tmp = mat[maxRow];
|
|
mat[maxRow] = mat[i];
|
|
mat[i] = tmp;
|
|
|
|
// Subtract the i-th row to make all the remaining rows 0 in the i-th column
|
|
for (var j = i + 1; j < n; j++) {
|
|
var coef = -mat[j][i] / mat[i][i];
|
|
for (var k = i; k < n + 1; k++) {
|
|
if (i == k) {
|
|
mat[j][k] = 0;
|
|
} else {
|
|
mat[j][k] += coef * mat[i][k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Solve Ax=b for upper triangular matrix A (mat)
|
|
var x = new Array(n);
|
|
for (var l = n - 1; l >= 0; l--) {
|
|
x[l] = mat[l][n] / mat[l][l];
|
|
for (var m = l - 1; m >= 0; m--) {
|
|
mat[m][n] -= mat[m][l] * x[l];
|
|
}
|
|
}
|
|
return x;
|
|
};
|
|
|
|
|
|
/**
|
|
* Converts radians to to degrees.
|
|
*
|
|
* @param {number} angleInRadians Angle in radians.
|
|
* @return {number} Angle in degrees.
|
|
*/
|
|
ol.math.toDegrees = function(angleInRadians) {
|
|
return angleInRadians * 180 / Math.PI;
|
|
};
|
|
|
|
|
|
/**
|
|
* Converts degrees to radians.
|
|
*
|
|
* @param {number} angleInDegrees Angle in degrees.
|
|
* @return {number} Angle in radians.
|
|
*/
|
|
ol.math.toRadians = function(angleInDegrees) {
|
|
return angleInDegrees * Math.PI / 180;
|
|
};
|
|
|
|
/**
|
|
* Returns the modulo of a / b, depending on the sign of b.
|
|
*
|
|
* @param {number} a Dividend.
|
|
* @param {number} b Divisor.
|
|
* @return {number} Modulo.
|
|
*/
|
|
ol.math.modulo = function(a, b) {
|
|
var r = a % b;
|
|
return r * b < 0 ? r + b : r;
|
|
};
|
|
|
|
/**
|
|
* Calculates the linearly interpolated value of x between a and b.
|
|
*
|
|
* @param {number} a Number
|
|
* @param {number} b Number
|
|
* @param {number} x Value to be interpolated.
|
|
* @return {number} Interpolated value.
|
|
*/
|
|
ol.math.lerp = function(a, b, x) {
|
|
return a + x * (b - a);
|
|
};
|