@woosh/meep-engine 2.49.8 → 2.49.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/math/bessel_i0.spec.js +43 -0
- package/src/core/math/bessel_j0.js +30 -0
- package/src/core/math/hash/murmur3_32.spec.js +8 -0
- package/src/core/math/hash/squirrel3.spec.js +16 -0
- package/src/core/math/interval/NumericInterval.js +1 -0
- package/src/core/math/{bessel_i0.js → modified_bessel_i0.js} +5 -2
- package/src/core/math/noise/{create_noise_2d.js → create_simplex_noise_2d.js} +2 -2
- package/src/core/math/noise/create_simplex_noise_2d.spec.js +21 -0
- package/src/core/math/normalizeArrayVector.spec.js +15 -0
- package/src/core/math/physics/irradiance/interpolate_irradiance_linear.spec.js +20 -0
- package/src/core/math/physics/irradiance/interpolate_irradiance_lograrithmic.js +4 -4
- package/src/core/math/physics/irradiance/interpolate_irradiance_lograrithmic.spec.js +18 -0
- package/src/core/math/physics/irradiance/interpolate_irradiance_smith.js +1 -1
- package/src/core/math/physics/irradiance/interpolate_irradiance_smith.spec.js +20 -0
- package/src/core/math/random/seededRandomMersenneTwister.spec.js +10 -0
- package/src/core/math/spline/spline_bezier3.js +1 -1
- package/src/core/math/spline/spline_bezier3_bounds.js +2 -1
- package/src/core/math/spline/spline_bezier3_bounds.spec.js +37 -0
- package/src/core/math/statistics/computeSampleSize_Cochran.spec.js +12 -0
- package/src/core/math/statistics/computeStatisticalPartialMedian.js +4 -0
- package/src/core/math/statistics/computeStatisticalPartialMedian.spec.js +13 -0
- package/src/engine/achievements/Achievement.spec.js +21 -0
- package/src/engine/animation/curve/compression/prototypeCurveCompression.js +2 -2
- package/src/engine/animation/curve/compression/{animation_curve_to_float_array.js → sample_animation_curve_to_float_array.js} +10 -3
- package/src/engine/animation/curve/compression/sample_animation_curve_to_float_array.spec.js +29 -0
- package/src/engine/animation/curve/draw/build_curve_editor.js +3 -3
- package/src/engine/development/performance/RingBufferMetric.js +1 -1
- package/src/engine/ecs/animation/Animation.js +2 -180
- package/src/engine/ecs/animation/AnimationClip.js +132 -0
- package/src/engine/ecs/animation/AnimationClip.spec.js +5 -0
- package/src/engine/ecs/animation/AnimationClipFlag.js +7 -0
- package/src/engine/ecs/animation/AnimationFlags.js +8 -0
- package/src/engine/ecs/animation/AnimationSerializationAdapter.js +32 -0
- package/src/engine/ecs/systems/AnimationSystem.js +3 -1
- package/src/engine/graphics/camera/testClippingPlaneComputation.js +1 -1
- package/src/engine/graphics/ecs/animation/AnimationControllerSystem.js +2 -1
- package/src/engine/graphics/ecs/path/testPathDisplaySystem.js +1 -1
- package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +1 -1
- package/src/engine/graphics/load_and_set_cubemap_v0.js +1 -1
- package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +1 -1
- package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +1 -1
- package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +1 -1
- package/src/engine/graphics/texture/sampler/filter/kaiser_1.js +8 -4
- package/src/engine/graphics/texture/sampler/filter/kaiser_bessel_window.js +2 -0
- package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.js +11 -4
- package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.spec.js +30 -0
- package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +18 -2
- package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.spec.js +17 -0
- package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +2 -2
- package/src/generation/grid/GridData.js +0 -60
- /package/src/engine/ecs/{animation → ik}/IKMath.js +0 -0
- /package/src/engine/ecs/{animation → ik}/IKProblem.js +0 -0
- /package/src/engine/ecs/{animation → ik}/IKSolver.js +0 -0
- /package/src/engine/ecs/{animation → ik}/InverseKinematics.js +0 -0
- /package/src/engine/ecs/{animation → ik}/InverseKinematicsSystem.js +0 -0
- /package/src/engine/ecs/{animation → ik}/OneBoneSurfaceAlignmentSolver.js +0 -0
- /package/src/engine/ecs/{animation → ik}/TwoBoneInverseKinematicsSolver.js +0 -0
package/package.json
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { bessel_j0 } from "./bessel_j0.js";
|
|
2
|
+
|
|
3
|
+
test("sanity", () => {
|
|
4
|
+
const v = bessel_j0(0);
|
|
5
|
+
|
|
6
|
+
expect(typeof v).toBe("number");
|
|
7
|
+
expect(v).not.toBeNaN();
|
|
8
|
+
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("sweep through low positive values", () => {
|
|
12
|
+
// https://www.wolframalpha.com/input?i=besselj%5B0%2Cx%5D
|
|
13
|
+
|
|
14
|
+
expect(bessel_j0(0)).toBeCloseTo(1, 1);
|
|
15
|
+
expect(bessel_j0(0.1)).toBeCloseTo(0.997, 1);
|
|
16
|
+
expect(bessel_j0(0.2)).toBeCloseTo(0.990, 1);
|
|
17
|
+
expect(bessel_j0(0.3)).toBeCloseTo(0.977, 1);
|
|
18
|
+
expect(bessel_j0(0.4)).toBeCloseTo(0.960, 1);
|
|
19
|
+
expect(bessel_j0(0.5)).toBeCloseTo(0.938, 1);
|
|
20
|
+
expect(bessel_j0(0.6)).toBeCloseTo(0.912, 1);
|
|
21
|
+
expect(bessel_j0(0.7)).toBeCloseTo(0.881, 1);
|
|
22
|
+
expect(bessel_j0(0.8)).toBeCloseTo(0.846, 1);
|
|
23
|
+
expect(bessel_j0(0.9)).toBeCloseTo(0.807, 1);
|
|
24
|
+
expect(bessel_j0(1)).toBeCloseTo(0.765, 1);
|
|
25
|
+
expect(bessel_j0(2)).toBeCloseTo(0.223, 1);
|
|
26
|
+
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("roots", () => {
|
|
30
|
+
|
|
31
|
+
expect(bessel_j0(2.40482555769577)).toBeCloseTo(0, 1);
|
|
32
|
+
expect(bessel_j0(-2.40482555769577)).toBeCloseTo(0, 1);
|
|
33
|
+
|
|
34
|
+
expect(bessel_j0(5.52007811028631)).toBeCloseTo(0, 1);
|
|
35
|
+
expect(bessel_j0(-5.52007811028631)).toBeCloseTo(0, 1);
|
|
36
|
+
|
|
37
|
+
expect(bessel_j0(8.65372791291101)).toBeCloseTo(0, 1);
|
|
38
|
+
expect(bessel_j0(-8.65372791291101)).toBeCloseTo(0, 1);
|
|
39
|
+
|
|
40
|
+
expect(bessel_j0(11.7915344390143)).toBeCloseTo(0, 1);
|
|
41
|
+
expect(bessel_j0(-11.7915344390143)).toBeCloseTo(0, 1);
|
|
42
|
+
|
|
43
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
|
|
3
|
+
const q = 0.7172491568;
|
|
4
|
+
const p0 = 0.6312725339;
|
|
5
|
+
const ps0 = 0.4308049446;
|
|
6
|
+
const p1 = 0.3500347951;
|
|
7
|
+
const ps1 = 0.4678202347;
|
|
8
|
+
const p2 = -0.06207747907;
|
|
9
|
+
const ps2 = 0.04253832927;
|
|
10
|
+
// const lamb4 = (lamb * lamb) * (lamb * lamb);
|
|
11
|
+
const lamb4 = 0.559840650625;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Bessel first order function of zeroth order
|
|
15
|
+
* @see https://link.springer.com/article/10.1007/s40314-020-01238-z
|
|
16
|
+
* @see https://www.shadertoy.com/view/Wt3czM
|
|
17
|
+
* @param {number} x
|
|
18
|
+
* @return {number}
|
|
19
|
+
*/
|
|
20
|
+
export function bessel_j0(x) {
|
|
21
|
+
assert.notNaN(x, 'x');
|
|
22
|
+
|
|
23
|
+
const xx = x * x;
|
|
24
|
+
|
|
25
|
+
const t0 = Math.sqrt(1.0 + lamb4 * xx);
|
|
26
|
+
const t1 = Math.sqrt(t0);
|
|
27
|
+
|
|
28
|
+
return xx === 0.0 ? 1.0 : 1.0 / (t1 * (1.0 + q * xx)) * ((p0 + p1 * xx + p2 * t0) * Math.cos(x) + ((ps0 + ps1 * xx) * t0 + ps2 * xx) * (Math.sin(x) / x));
|
|
29
|
+
|
|
30
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { squirrel3 } from "./squirrel3.js";
|
|
2
|
+
|
|
3
|
+
function expect_integer(v) {
|
|
4
|
+
|
|
5
|
+
expect(typeof v).toBe("number");
|
|
6
|
+
expect(Number.isInteger(v)).toBe(true);
|
|
7
|
+
expect(v).not.toBeNaN();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
test("sanity check", () => {
|
|
11
|
+
expect_integer(squirrel3(0));
|
|
12
|
+
expect_integer(squirrel3(1));
|
|
13
|
+
expect_integer(squirrel3(-1));
|
|
14
|
+
|
|
15
|
+
expect(squirrel3(0)).not.toEqual(squirrel3(1));
|
|
16
|
+
});
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { assert } from "../assert.js";
|
|
2
2
|
|
|
3
|
+
// const lamb = 0.865;
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
|
-
* Modified bessel function of the first kind
|
|
6
|
+
* Modified bessel function of the first kind zeroth order
|
|
5
7
|
* @see https://mathworld.wolfram.com/ModifiedBesselFunctionoftheFirstKind.html
|
|
6
8
|
* @see https://computergraphics.stackexchange.com/questions/6393/kaiser-windowed-sinc-filter-for-mip-mapping
|
|
7
9
|
* @see https://github.com/terifan/ImageResampler/blob/dbc212ce6aaa769bf3c9623cb6ead58ffd51d76c/src/org/terifan/image_resampler/FilterFactory.java
|
|
8
10
|
* @param {number} x
|
|
9
11
|
* @returns {number}
|
|
10
12
|
*/
|
|
11
|
-
export function
|
|
13
|
+
export function modified_bessel_i0(x) {
|
|
12
14
|
assert.notNaN(x, 'x');
|
|
13
15
|
|
|
14
16
|
let sum = 1.0;
|
|
@@ -24,3 +26,4 @@ export function bessel_i0(x) {
|
|
|
24
26
|
|
|
25
27
|
return sum;
|
|
26
28
|
}
|
|
29
|
+
|
|
@@ -58,9 +58,9 @@ const grad4 = /*#__PURE__*/ new Float64Array([0, 1, 1, 1, 0, 1, 1, -1, 0, 1, -1,
|
|
|
58
58
|
/**
|
|
59
59
|
* Creates a 2D noise function
|
|
60
60
|
* @param random the random function that will be used to build the permutation table
|
|
61
|
-
* @returns {function(x:number, y:number):number}
|
|
61
|
+
* @returns {function(x:number, y:number):number} producing values in range -1 .. 1
|
|
62
62
|
*/
|
|
63
|
-
export function
|
|
63
|
+
export function create_simplex_noise_2d(random = Math.random) {
|
|
64
64
|
// allocate continuous chunk of memory
|
|
65
65
|
const buffer = new ArrayBuffer(512 * 2);
|
|
66
66
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { create_simplex_noise_2d } from "./create_simplex_noise_2d.js";
|
|
2
|
+
|
|
3
|
+
test("sample 10 points in 0..1 range", () => {
|
|
4
|
+
const noise2d = create_simplex_noise_2d(() => 0);
|
|
5
|
+
|
|
6
|
+
const COUNT = 10;
|
|
7
|
+
for (let i = 0; i < COUNT; i++) {
|
|
8
|
+
const u = i / (COUNT - 1);
|
|
9
|
+
for (let j = 0; j < COUNT; j++) {
|
|
10
|
+
const v = j / (COUNT - 1);
|
|
11
|
+
|
|
12
|
+
const value = noise2d(u, v);
|
|
13
|
+
|
|
14
|
+
expect(typeof value).toBe('number');
|
|
15
|
+
expect(value).not.toBeNaN();
|
|
16
|
+
|
|
17
|
+
expect(value).toBeGreaterThanOrEqual(-1);
|
|
18
|
+
expect(value).toBeLessThanOrEqual(1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { normalizeArrayVector } from "./normalizeArrayVector.js";
|
|
2
|
+
|
|
3
|
+
test("1d vector normalization", () => {
|
|
4
|
+
const v = [7];
|
|
5
|
+
|
|
6
|
+
normalizeArrayVector(v, v, 1);
|
|
7
|
+
|
|
8
|
+
expect(v[0]).toBeCloseTo(1);
|
|
9
|
+
|
|
10
|
+
v[0] = -13;
|
|
11
|
+
|
|
12
|
+
normalizeArrayVector(v, v, 1);
|
|
13
|
+
|
|
14
|
+
expect(v[0]).toBeCloseTo(-1);
|
|
15
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { interpolate_irradiance_linear } from "./interpolate_irradiance_linear.js";
|
|
2
|
+
|
|
3
|
+
test("sanity check", () => {
|
|
4
|
+
|
|
5
|
+
expect(interpolate_irradiance_linear(3, 3, 3)).toBe(1);
|
|
6
|
+
|
|
7
|
+
expect(interpolate_irradiance_linear(3, 3, 7)).toBe(1);
|
|
8
|
+
|
|
9
|
+
expect(interpolate_irradiance_linear(7, 3, 7)).toBe(0);
|
|
10
|
+
|
|
11
|
+
expect(interpolate_irradiance_linear(0, 3, 7)).toBe(1);
|
|
12
|
+
|
|
13
|
+
expect(interpolate_irradiance_linear(11, 3, 7)).toBe(0);
|
|
14
|
+
|
|
15
|
+
const mid = interpolate_irradiance_linear(5, 3, 7);
|
|
16
|
+
|
|
17
|
+
expect(mid).toBeGreaterThan(0);
|
|
18
|
+
expect(mid).toBeLessThan(1);
|
|
19
|
+
|
|
20
|
+
});
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { inverseLerp } from "../../inverseLerp.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Approximates logarithmic decay, except it goes to 0 at max
|
|
5
|
+
* Estimation is done using a 5th degree polynomial
|
|
5
6
|
* @param {number} distance
|
|
6
7
|
* @param {number} min
|
|
7
8
|
* @param {number} max
|
|
8
9
|
* @return {number}
|
|
9
10
|
*/
|
|
10
11
|
export function interpolate_irradiance_lograrithmic(distance, min, max) {
|
|
11
|
-
if (distance >= max) {
|
|
12
|
-
return 0;
|
|
13
|
-
}
|
|
14
12
|
|
|
15
13
|
if (distance <= min) {
|
|
16
14
|
return 1;
|
|
15
|
+
} else if (distance >= max) {
|
|
16
|
+
return 0;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const x = inverseLerp(min, max, distance);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { interpolate_irradiance_lograrithmic } from "./interpolate_irradiance_lograrithmic.js";
|
|
2
|
+
|
|
3
|
+
test("sanity check", () => {
|
|
4
|
+
expect(interpolate_irradiance_lograrithmic(3, 3, 3)).toBe(1);
|
|
5
|
+
|
|
6
|
+
expect(interpolate_irradiance_lograrithmic(3, 3, 7)).toBe(1);
|
|
7
|
+
|
|
8
|
+
expect(interpolate_irradiance_lograrithmic(7, 3, 7)).toBe(0);
|
|
9
|
+
|
|
10
|
+
expect(interpolate_irradiance_lograrithmic(0, 3, 7)).toBe(1);
|
|
11
|
+
|
|
12
|
+
expect(interpolate_irradiance_lograrithmic(11, 3, 7)).toBe(0);
|
|
13
|
+
|
|
14
|
+
const mid = interpolate_irradiance_lograrithmic(5, 3, 7);
|
|
15
|
+
|
|
16
|
+
expect(mid).toBeGreaterThan(0);
|
|
17
|
+
expect(mid).toBeLessThan(1);
|
|
18
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { interpolate_irradiance_smith } from "./interpolate_irradiance_smith.js";
|
|
2
|
+
|
|
3
|
+
test("sanity check", () => {
|
|
4
|
+
|
|
5
|
+
expect(interpolate_irradiance_smith(3, 3, 3)).toBe(1);
|
|
6
|
+
|
|
7
|
+
expect(interpolate_irradiance_smith(3, 3, 7)).toBe(1);
|
|
8
|
+
|
|
9
|
+
expect(interpolate_irradiance_smith(7, 3, 7)).toBe(0);
|
|
10
|
+
|
|
11
|
+
expect(interpolate_irradiance_smith(0, 3, 7)).toBe(1);
|
|
12
|
+
|
|
13
|
+
expect(interpolate_irradiance_smith(11, 3, 7)).toBe(0);
|
|
14
|
+
|
|
15
|
+
const mid = interpolate_irradiance_smith(5, 3, 7);
|
|
16
|
+
|
|
17
|
+
expect(mid).toBeGreaterThan(0);
|
|
18
|
+
expect(mid).toBeLessThan(1);
|
|
19
|
+
|
|
20
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { min2 } from "../min2.js";
|
|
2
2
|
import { max2 } from "../max2.js";
|
|
3
3
|
import { assert } from "../../assert.js";
|
|
4
|
+
import { spline_bezier3 } from './spline_bezier3'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Compute bounds of a 3-rd degree bezier curve
|
|
@@ -15,7 +16,7 @@ import { assert } from "../../assert.js";
|
|
|
15
16
|
* @param {number} p2
|
|
16
17
|
* @param {number} p3
|
|
17
18
|
*/
|
|
18
|
-
function spline_bezier3_bounds(result, result_offset, result_stride, p0, p1, p2, p3) {
|
|
19
|
+
export function spline_bezier3_bounds(result, result_offset, result_stride, p0, p1, p2, p3) {
|
|
19
20
|
assert.greaterThan(result_stride, 0, 'result_stride must be greater than 0');
|
|
20
21
|
assert.isInteger(result_stride, 'result_stride');
|
|
21
22
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { spline_bezier3_bounds } from "./spline_bezier3_bounds.js";
|
|
2
|
+
|
|
3
|
+
test("spline of 0 length", () => {
|
|
4
|
+
const bounds = [];
|
|
5
|
+
|
|
6
|
+
spline_bezier3_bounds(
|
|
7
|
+
bounds, 0, 1,
|
|
8
|
+
0, 0, 0, 0
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
expect(bounds[0]).toBeCloseTo(0);
|
|
12
|
+
expect(bounds[1]).toBeCloseTo(0);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("line-shaped spline of", () => {
|
|
16
|
+
const bounds = [];
|
|
17
|
+
|
|
18
|
+
spline_bezier3_bounds(
|
|
19
|
+
bounds, 0, 1,
|
|
20
|
+
-2, -1, 1, 2
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
expect(bounds[0]).toBeCloseTo(-2);
|
|
24
|
+
expect(bounds[1]).toBeCloseTo(2);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("overshooting control point spline of", () => {
|
|
28
|
+
const bounds = [];
|
|
29
|
+
|
|
30
|
+
spline_bezier3_bounds(
|
|
31
|
+
bounds, 0, 1,
|
|
32
|
+
0, -1, 1, 0
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
expect(bounds[0]).toBeLessThan(0);
|
|
36
|
+
expect(bounds[1]).toBeGreaterThan(0);
|
|
37
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { computeSampleSize_Cochran } from "./computeSampleSize_Cochran.js";
|
|
2
|
+
|
|
3
|
+
test("sanity for 95% confidence", () => {
|
|
4
|
+
function execute(error) {
|
|
5
|
+
return Math.floor(computeSampleSize_Cochran(1.95996, 0.5, error))
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
expect(execute(0.05)).toEqual(384);
|
|
9
|
+
expect(execute(0.035)).toEqual(783);
|
|
10
|
+
expect(execute(0.025)).toEqual(1536);
|
|
11
|
+
expect(execute(0.01)).toEqual(9603);
|
|
12
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { compareNumbersAscending } from "../../function/Functions.js";
|
|
2
|
+
import { assert } from "../../assert.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
*
|
|
@@ -8,6 +9,9 @@ import { compareNumbersAscending } from "../../function/Functions.js";
|
|
|
8
9
|
* @returns {number}
|
|
9
10
|
*/
|
|
10
11
|
export function computeStatisticalPartialMedian(values, start, end) {
|
|
12
|
+
assert.isArrayLike(values, 'values');
|
|
13
|
+
assert.lessThan(end, values.length);
|
|
14
|
+
|
|
11
15
|
const copy = values.slice();
|
|
12
16
|
|
|
13
17
|
copy.sort(compareNumbersAscending);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { computeStatisticalPartialMedian } from "./computeStatisticalPartialMedian.js";
|
|
2
|
+
|
|
3
|
+
test("single item", () => {
|
|
4
|
+
expect(computeStatisticalPartialMedian([7], 0, 0)).toEqual(7);
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
test("[1,2,1]", () => {
|
|
8
|
+
expect(computeStatisticalPartialMedian([1,2,1], 0, 2)).toEqual(1);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("[7,6,2,4,1]", () => {
|
|
12
|
+
expect(computeStatisticalPartialMedian([7,6,2,4,1], 0, 4)).toEqual(4);
|
|
13
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Achievement } from "./Achievement.js";
|
|
2
|
+
|
|
3
|
+
test("constructor does not throw", () => {
|
|
4
|
+
expect(() => new Achievement()).not.toThrow();
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
test("fromJSON correctness", () => {
|
|
8
|
+
const achievement = new Achievement();
|
|
9
|
+
|
|
10
|
+
achievement.fromJSON({
|
|
11
|
+
id: "x",
|
|
12
|
+
condition: "hello == kitty",
|
|
13
|
+
icon: "y",
|
|
14
|
+
secret: true
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
expect(achievement.id).toEqual("x");
|
|
18
|
+
expect(achievement.condition).toEqual("hello == kitty");
|
|
19
|
+
expect(achievement.icon).toEqual("y");
|
|
20
|
+
expect(achievement.secret).toEqual(true);
|
|
21
|
+
});
|
|
@@ -4,7 +4,7 @@ import { Keyframe } from "../Keyframe.js";
|
|
|
4
4
|
import { EngineConfiguration } from "../../../EngineConfiguration.js";
|
|
5
5
|
import GUIElementSystem from "../../../ecs/gui/GUIElementSystem.js";
|
|
6
6
|
import ViewportPositionSystem from "../../../ecs/gui/position/ViewportPositionSystem.js";
|
|
7
|
-
import {
|
|
7
|
+
import { sample_animation_curve_to_float_array } from "./sample_animation_curve_to_float_array.js";
|
|
8
8
|
import { downsample_float_array_curve_by_error } from "./downsample_float_array_curve_by_error.js";
|
|
9
9
|
import { build_plot_entity_from_array } from "../draw/build_plot_entity_from_array.js";
|
|
10
10
|
|
|
@@ -28,7 +28,7 @@ async function init() {
|
|
|
28
28
|
|
|
29
29
|
function build_error_scale(ecd, curve) {
|
|
30
30
|
const curve_data = [];
|
|
31
|
-
|
|
31
|
+
sample_animation_curve_to_float_array(curve_data, 0, curve, 256);
|
|
32
32
|
|
|
33
33
|
|
|
34
34
|
build_plot_entity_from_array({
|
|
@@ -5,10 +5,15 @@
|
|
|
5
5
|
* Sample entire animation curve into a flat array with discrete equal intervals
|
|
6
6
|
* @param {number[]|Float32Array} out
|
|
7
7
|
* @param {number} out_offset
|
|
8
|
-
* @param {number} sample_count
|
|
9
8
|
* @param {AnimationCurve} curve
|
|
9
|
+
* @param {number} sample_count
|
|
10
10
|
*/
|
|
11
|
-
export function
|
|
11
|
+
export function sample_animation_curve_to_float_array(
|
|
12
|
+
out,
|
|
13
|
+
out_offset,
|
|
14
|
+
curve,
|
|
15
|
+
sample_count = out.length
|
|
16
|
+
) {
|
|
12
17
|
const keyframes = curve.keys;
|
|
13
18
|
const keyframe_count = keyframes.length;
|
|
14
19
|
|
|
@@ -25,8 +30,10 @@ export function animation_curve_to_float_array(out, curve, out_offset = 0, sampl
|
|
|
25
30
|
const time_end = key_last.time;
|
|
26
31
|
const time_span = time_end - time_start;
|
|
27
32
|
|
|
33
|
+
const multiplier = sample_count > 1 ? 1 / (sample_count - 1) : 0;
|
|
34
|
+
|
|
28
35
|
for (let i = 0; i < sample_count; i++) {
|
|
29
|
-
const f = i
|
|
36
|
+
const f = i * multiplier;
|
|
30
37
|
|
|
31
38
|
const t = time_start + (f * time_span);
|
|
32
39
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { AnimationCurve } from "../AnimationCurve.js";
|
|
2
|
+
import { sample_animation_curve_to_float_array } from "./sample_animation_curve_to_float_array.js";
|
|
3
|
+
import { Keyframe } from "../Keyframe.js";
|
|
4
|
+
|
|
5
|
+
test("0 samples should produce valid result", () => {
|
|
6
|
+
|
|
7
|
+
const curve = new AnimationCurve();
|
|
8
|
+
|
|
9
|
+
const result = new Float32Array(0);
|
|
10
|
+
|
|
11
|
+
expect(() => sample_animation_curve_to_float_array(result, 0, curve, 0)).not.toThrow();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("3 samples on a line", () => {
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
const curve = new AnimationCurve();
|
|
18
|
+
curve.add(Keyframe.from(-1, -1))
|
|
19
|
+
curve.add(Keyframe.from(1, 7))
|
|
20
|
+
|
|
21
|
+
curve.smoothAllTangents();
|
|
22
|
+
|
|
23
|
+
const result = new Float32Array(3);
|
|
24
|
+
sample_animation_curve_to_float_array(result, 0, curve, 3);
|
|
25
|
+
|
|
26
|
+
expect(result[0]).toBeCloseTo(-1);
|
|
27
|
+
expect(result[1]).toBeCloseTo(3);
|
|
28
|
+
expect(result[2]).toBeCloseTo(7);
|
|
29
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import Vector2 from "../../../../core/geom/Vector2.js";
|
|
2
2
|
import EmptyView from "../../../../view/elements/EmptyView.js";
|
|
3
3
|
import { CanvasView } from "../../../../view/elements/CanvasView.js";
|
|
4
|
-
import AABB2 from "../../../../core/geom/AABB2.js";
|
|
4
|
+
import AABB2 from "../../../../core/geom/2d/aabb/AABB2.js";
|
|
5
5
|
import Signal from "../../../../core/events/signal/Signal.js";
|
|
6
6
|
import ObservedValue from "../../../../core/model/ObservedValue.js";
|
|
7
|
-
import {
|
|
7
|
+
import { sample_animation_curve_to_float_array } from "../compression/sample_animation_curve_to_float_array.js";
|
|
8
8
|
import { plot_data } from "./plot_data.js";
|
|
9
9
|
import { DraggableAspect } from "../../../ui/DraggableAspect.js";
|
|
10
10
|
import { min2 } from "../../../../core/math/min2.js";
|
|
@@ -123,7 +123,7 @@ export function build_curve_editor({
|
|
|
123
123
|
const width = graph.size.x;
|
|
124
124
|
const data = new Float32Array(width);
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
sample_animation_curve_to_float_array(data, 0, curve, data.length);
|
|
127
127
|
|
|
128
128
|
plot_data({
|
|
129
129
|
data,
|
|
@@ -58,7 +58,7 @@ export class RingBufferMetric extends AbstractMetric {
|
|
|
58
58
|
} else {
|
|
59
59
|
|
|
60
60
|
result.mean = computeStatisticalMean(array, 0, data_count);
|
|
61
|
-
result.median = computeStatisticalPartialMedian(array, 0, data_count);
|
|
61
|
+
result.median = computeStatisticalPartialMedian(array, 0, data_count - 1);
|
|
62
62
|
result.max = computeArrayMax(array, 0, data_count);
|
|
63
63
|
result.min = computeArrayMin(array, 0, data_count);
|
|
64
64
|
|