UNPKG

@turbox3d/math

Version:

Large-scale graphics application math library

344 lines (343 loc) 12.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.MathUtils = void 0; var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _Tolerance = require("./base/Tolerance"); var _Vector = require("./base/Vector2"); var _lut = []; for (var i = 0; i < 256; i++) { _lut[i] = (i < 16 ? '0' : '') + i.toString(16); } var _seed = 1234567; var MathUtils = exports.MathUtils = { DEG2RAD: Math.PI / 180, RAD2DEG: 180 / Math.PI, generateUUID: function generateUUID() { // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 var d0 = Math.random() * 0xffffffff | 0; var d1 = Math.random() * 0xffffffff | 0; var d2 = Math.random() * 0xffffffff | 0; var d3 = Math.random() * 0xffffffff | 0; var uuid = "".concat(_lut[d0 & 0xff] + _lut[d0 >> 8 & 0xff] + _lut[d0 >> 16 & 0xff] + _lut[d0 >> 24 & 0xff], "-").concat(_lut[d1 & 0xff]).concat(_lut[d1 >> 8 & 0xff], "-").concat(_lut[d1 >> 16 & 0x0f | 0x40]).concat(_lut[d1 >> 24 & 0xff], "-").concat(_lut[d2 & 0x3f | 0x80]).concat(_lut[d2 >> 8 & 0xff], "-").concat(_lut[d2 >> 16 & 0xff]).concat(_lut[d2 >> 24 & 0xff]).concat(_lut[d3 & 0xff]).concat(_lut[d3 >> 8 & 0xff]).concat(_lut[d3 >> 16 & 0xff]).concat(_lut[d3 >> 24 & 0xff]); // .toUpperCase() here flattens concatenated strings to save heap memory space. return uuid.toUpperCase(); }, clamp: function clamp(value, min, max) { return Math.max(min, Math.min(max, value)); }, // compute euclidian modulo of m % n // https://en.wikipedia.org/wiki/Modulo_operation euclideanModulo: function euclideanModulo(n, m) { return (n % m + m) % m; }, // Linear mapping from range <a1, a2> to range <b1, b2> mapLinear: function mapLinear(x, a1, a2, b1, b2) { return b1 + (x - a1) * (b2 - b1) / (a2 - a1); }, // https://en.wikipedia.org/wiki/Linear_interpolation lerp: function lerp(x, y, t) { return (1 - t) * x + t * y; }, // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ damp: function damp(x, y, lambda, dt) { return MathUtils.lerp(x, y, 1 - Math.exp(-lambda * dt)); }, // https://www.desmos.com/calculator/vcsjnyz7x4 pingpong: function pingpong(x) { var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; return length - Math.abs(MathUtils.euclideanModulo(x, length * 2) - length); }, // http://en.wikipedia.org/wiki/Smoothstep smoothstep: function smoothstep(x, min, max) { if (x <= min) return 0; if (x >= max) return 1; x = (x - min) / (max - min); return x * x * (3 - 2 * x); }, smootherstep: function smootherstep(x, min, max) { if (x <= min) return 0; if (x >= max) return 1; x = (x - min) / (max - min); return x * x * x * (x * (x * 6 - 15) + 10); }, // Random integer from <low, high> interval randInt: function randInt(low, high) { return low + Math.floor(Math.random() * (high - low + 1)); }, // Random float from <low, high> interval randFloat: function randFloat(low, high) { return low + Math.random() * (high - low); }, // Random float from <-range/2, range/2> interval randFloatSpread: function randFloatSpread(range) { return range * (0.5 - Math.random()); }, // Deterministic pseudo-random float in the interval [ 0, 1 ] seededRandom: function seededRandom(s) { if (s !== undefined) _seed = s % 2147483647; // Park-Miller algorithm _seed = _seed * 16807 % 2147483647; return (_seed - 1) / 2147483646; }, degToRad: function degToRad(degrees) { return degrees * MathUtils.DEG2RAD; }, radToDeg: function radToDeg(radians) { return radians * MathUtils.RAD2DEG; }, isPowerOfTwo: function isPowerOfTwo(value) { return (value & value - 1) === 0 && value !== 0; }, ceilPowerOfTwo: function ceilPowerOfTwo(value) { return Math.pow(2, Math.ceil(Math.log(value) / Math.LN2)); }, floorPowerOfTwo: function floorPowerOfTwo(value) { return Math.pow(2, Math.floor(Math.log(value) / Math.LN2)); }, setQuaternionFromProperEuler: function setQuaternionFromProperEuler(q, a, b, c, order) { // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles // rotations are applied to the axes in the order specified by 'order' // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' // angles are in radians var cos = Math.cos; var sin = Math.sin; var c2 = cos(b / 2); var s2 = sin(b / 2); var c13 = cos((a + c) / 2); var s13 = sin((a + c) / 2); var c1_3 = cos((a - c) / 2); var s1_3 = sin((a - c) / 2); var c3_1 = cos((c - a) / 2); var s3_1 = sin((c - a) / 2); switch (order) { case 'XYX': q.set(c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13); break; case 'YZY': q.set(s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13); break; case 'ZXZ': q.set(s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13); break; case 'XZX': q.set(c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13); break; case 'YXY': q.set(s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13); break; case 'ZYZ': q.set(s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13); break; default: console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ".concat(order)); } }, isEqual: function isEqual(num1, num2, tol) { var tolerance = tol || _Tolerance.Tolerance.global.numTol; if (num1 === num2) { return true; } return Math.abs(num1 - num2) <= tolerance; }, isZero: function isZero(num, tol) { return MathUtils.isEqual(num, 0, tol); }, /** * Check wether num1 is smaller than num2 with specified tolerance. * Global (default) tolerance will be used if tol is not provided. * @param num1 * @param num2 * @param tol */ isSmaller: function isSmaller(num1, num2, tol) { var tolerance = tol || _Tolerance.Tolerance.global.numTol; var diff = num1 - num2; return diff < -tolerance; }, /** * Check whether num1 is bigger than num2 with specified tolerance. * Global (default) tolerance will be used if tol is not provided. * @param num1 * @param num2 * @param tol */ isBigger: function isBigger(num1, num2, tol) { var tolerance = tol || _Tolerance.Tolerance.global.numTol; var diff = num1 - num2; return diff > tolerance; }, /** * Check whether num1 is smaller than or equal to num2 with specified tolerance. * Global (default) tolerance will be used if tol is not provided. * @param num1 * @param num2 * @param tol */ isSmallerOrEqual: function isSmallerOrEqual(num1, num2, tol) { var tolerance = tol || _Tolerance.Tolerance.global.numTol; var diff = num1 - num2; return diff <= tolerance; }, /** * Check whether num1 is bigger than or equal to num2 with specified tolerance. * Global (default) tolerance will be used if tol is not provided. * @param num1 * @param num2 * @param tol */ isBiggerOrEqual: function isBiggerOrEqual(num1, num2, tol) { var tolerance = tol || _Tolerance.Tolerance.global.numTol; var diff = num1 - num2; return diff >= -tolerance; }, /** * Check whether a number is in a range with specified tolerance. * Global (default) tolerance will be used if tol is not provided. * @param value the value to be checked. * @param min the range's lower limit. * @param max the range's upper limit. * @param minOpen whether the range's lower limit is open, default is false. * @param maxOpen whether the range's upper limit is open, default is false. * @param tol */ isInRange: function isInRange(value, min, max, minOpen, maxOpen, tol) { var tolerance = tol || _Tolerance.Tolerance.global.numTol; var diffMin = value - min; var diffMax = value - max; var biggerMin = minOpen ? diffMin > tolerance : diffMin >= -tolerance; var smallerMax = maxOpen ? diffMax < -tolerance : diffMax <= tolerance; return biggerMin && smallerMax; }, /** * Compare two numbers: * If num1 is fuzzy equal to num2, return 0. * If num1 is fuzzy bigger than num2, return 1. * If num1 is fuzzy smaller than num2, return -1. * If num1 or num2 is a NaN, throw exception. * @param num1 * @param num2 * @param tol */ compare: function compare(num1, num2, tol) { if (Number.isNaN(num1) || Number.isNaN(num2)) { throw Error('Invalid NaN number'); } if (MathUtils.isEqual(num1, num2, tol)) { return 0; } if (num1 < num2) { return -1; } return 1; }, /** * 单向线性插值 */ interpolation: function interpolation(start, end) { var segments = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10; var v = end.subtracted(start); var step = v.length / segments; var points = []; var n = v.normalized(); for (var index = 0; index < segments - 1; index++) { points.push(start.added(n.clone().multiplyScalar(step * (index + 1)))); } points.unshift(start.clone()); points.push(end.clone()); return points; }, /** * 根据四方点生成网格 * @param quadPositions 四方点,左上角为起点,按照顺时针顺序 * @param widthSegments 宽度分割段数 * @param heightSegments 高度分割段数 */ generateMeshByQuad: function generateMeshByQuad(quadPositions) { var widthSegments = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10; var heightSegments = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10; var indices = []; var vertices = []; var normals = []; var uvs = []; var a1 = MathUtils.interpolation(quadPositions[0], quadPositions[1], widthSegments); var a2 = MathUtils.interpolation(quadPositions[3], quadPositions[2], widthSegments); var a3 = a1.map(function (v, i) { return MathUtils.interpolation(v.clone(), a2[i].clone(), heightSegments); }); var _loop = function _loop(_i) { if (_i === 0) { vertices.push.apply(vertices, (0, _toConsumableArray2["default"])(a1.flatMap(function (a) { return a.toArray(); }))); } else if (_i === heightSegments) { vertices.push.apply(vertices, (0, _toConsumableArray2["default"])(a2.flatMap(function (a) { return a.toArray(); }))); } else { vertices.push.apply(vertices, (0, _toConsumableArray2["default"])(a3.flatMap(function (a) { return a[_i].toArray(); }))); } for (var _j = 0; _j <= widthSegments; _j++) { normals.push(0, 0, 1); uvs.push(_j * (1 / widthSegments), _i * (1 / heightSegments)); } }; for (var _i = 0; _i <= heightSegments; _i++) { _loop(_i); } for (var _i2 = 0; _i2 < heightSegments; _i2++) { for (var j = 0; j < widthSegments; j++) { var a = _i2 * (widthSegments + 1) + (j + 1); var b = _i2 * (widthSegments + 1) + j; var c = (_i2 + 1) * (widthSegments + 1) + j; var d = (_i2 + 1) * (widthSegments + 1) + (j + 1); indices.push(a, b, d); indices.push(b, c, d); } } return { indices: indices, vertices: vertices, normals: normals, uvs: uvs }; }, /** 把无序的点排序成顺逆时针的邻接点,只支持凸多边形 */clockwisePoints: function clockwisePoints(points) { var clockwise = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var newPoints = [points[0]]; var _loop2 = function _loop2() { var p1 = newPoints[newPoints.length - 1]; var waitComparePoints = points.filter(function (wp) { return wp !== p1; }); var _loop3 = function _loop3() { var p2 = waitComparePoints[index]; var v = new _Vector.Vector2(p2.x - p1.x, p2.y - p1.y); var otherPoints = points.filter(function (p) { return p !== p1 && p !== p2; }); var otherVs = otherPoints.map(function (p) { return new _Vector.Vector2(p.x - p1.x, p.y - p1.y); }); var isAllMatched = otherVs.every(function (ov) { return clockwise ? v.cross(ov) < 0 : v.cross(ov) > 0; }); if (isAllMatched) { newPoints.push(p2); return 1; // break } }; for (var index = 0; index < waitComparePoints.length; index++) { if (_loop3()) break; } }; for (var _i3 = 0; _i3 < points.length - 1; _i3++) { _loop2(); } return newPoints; } };