@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
127 lines (100 loc) • 4.26 kB
JavaScript
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);
}
}