UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

127 lines (100 loc) 4.26 kB
import { assert } from "../../assert.js"; import { array_copy } from "../../collection/array/array_copy.js"; import { clamp } from "../clamp.js"; import { computeNonuniformCatmullRomSplineSample } from "./computeNonuniformCatmullRomSplineSample.js"; /** * * @type {number[]} */ const sample = []; /** * * @type {number[]} */ const p0 = []; /** * * @type {number[]} */ const p1 = []; /** * * @type {number[]} */ const p2 = []; /** * * @type {number[]} */ const p3 = []; /** * Takes distances between points into account and samples at equal intervals along linear distance along the point sequence. Computationally slightly more expensive, but produces very predictable and stable results * @param {number[]|Float32Array} result * @param {number[]|Float32Array} input * @param {number} input_length number of points in the input * @param {number} dimensions number of dimensions per vertex * @param {number} sample_count number of discrete points to be generated * @param {number} [alpha=0.5] parameter for control point weights (see non-parametric catmull-rom for details on "alpha" definition) */ export function computeCatmullRomSplineUniformDistance(result, input, input_length, dimensions, sample_count, alpha = 0.5) { assert.greaterThan(dimensions, 0, 'number of dimensions must be greater than 0'); assert.isNonNegativeInteger(dimensions, 'dimensions'); assert.greaterThanOrEqual(sample_count, 2, 'number of samples must be >= 2'); assert.isNonNegativeInteger(sample_count, 'sample_count'); // we need to pre-compute come values such as distances between each point pair in the input const distances = []; let distances_sum = 0; // compute distances for (let i = 1; i < input_length; i++) { let sqr_d = 0; for (let j = 0; j < dimensions; j++) { const v0 = input[(i - 1) * dimensions + j]; const v1 = input[i * dimensions + j]; const dx = v0 - v1; sqr_d += dx * dx; } const distance = Math.sqrt(sqr_d); distances_sum += distance; distances[i - 1] = distances_sum; } const step_distance = distances_sum / (sample_count - 1); let cursor_index = 0; let current_input_distance = 0; let next_point_distance = 0; let included_point_count = 0; while (cursor_index < input_length) { const next_input_distance = distances[cursor_index]; const distance_delta = next_input_distance - current_input_distance; while (next_input_distance >= next_point_distance) { // include point let t; if (distance_delta === 0) { t = 0; } else { const relative_position = next_point_distance - current_input_distance; t = relative_position / distance_delta } const i0 = clamp(cursor_index - 1, 0, input_length - 1); const i1 = clamp(cursor_index, 0, input_length - 1); const i2 = clamp(cursor_index + 1, 0, input_length - 1); const i3 = clamp(cursor_index + 2, 0, input_length - 1); // read relevant inputs array_copy(input, i0 * dimensions, p0, 0, dimensions); array_copy(input, i1 * dimensions, p1, 0, dimensions); array_copy(input, i2 * dimensions, p2, 0, dimensions); array_copy(input, i3 * dimensions, p3, 0, dimensions); computeNonuniformCatmullRomSplineSample(sample, p0, p1, p2, p3, dimensions, t, alpha); const result_address = included_point_count * dimensions; array_copy(sample, 0, result, result_address, dimensions); // increment search variables for the next point included_point_count++; next_point_distance += step_distance; } cursor_index++; current_input_distance = next_input_distance; } if (included_point_count < sample_count) { // include last point array_copy(input, (input_length - 1) * dimensions, result, (sample_count - 1) * dimensions, dimensions); } }