@woosh/meep-engine 2.109.23 → 2.109.25
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/build/meep.cjs +231 -104
- package/build/meep.min.js +1 -1
- package/build/meep.module.js +231 -104
- package/package.json +1 -1
- package/src/core/collection/heap/FastBinaryHeap.d.ts +17 -10
- package/src/core/collection/heap/FastBinaryHeap.d.ts.map +1 -1
- package/src/core/collection/heap/FastBinaryHeap.js +33 -23
- package/src/core/collection/heap/FastBinaryHeap.spec.js +10 -10
- package/src/core/collection/table/RowFirstTable.d.ts +10 -7
- package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
- package/src/core/collection/table/RowFirstTable.js +23 -6
- package/src/core/collection/table/bind/TableRecord.d.ts.map +1 -1
- package/src/core/collection/table/bind/TableRecord.js +4 -0
- package/src/core/geom/3d/normal/octahedron/encode_unit_to_octahedron.js +2 -2
- package/src/core/geom/packing/max-rect/MaxRectanglesPacker.js +2 -2
- package/src/core/model/validate_enum_schema.d.ts +10 -0
- package/src/core/model/validate_enum_schema.d.ts.map +1 -0
- package/src/core/model/validate_enum_schema.js +31 -0
- package/src/engine/animation/async/TimeSeries.d.ts +76 -0
- package/src/engine/animation/async/TimeSeries.d.ts.map +1 -0
- package/src/engine/animation/async/TimeSeries.js +289 -0
- package/src/engine/animation/async/prototypeAsyncAnimation.js +31 -83
- package/src/engine/animation/async/table_find_min_index_in_ordered_column.d.ts +9 -0
- package/src/engine/animation/async/table_find_min_index_in_ordered_column.d.ts.map +1 -0
- package/src/engine/animation/async/table_find_min_index_in_ordered_column.js +32 -0
- package/src/engine/asset/AssetManager.js +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +14 -11
- package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +1 -1
- package/src/engine/graphics/sh3/gi/material/common.glsl +1 -1
- package/src/engine/graphics/sh3/lpv/LightProbeVolume.js +1 -1
- package/src/engine/graphics/sh3/lpv/depth/octahedral/bake_octahedral_depth_map.d.ts.map +1 -1
- package/src/engine/graphics/sh3/lpv/depth/octahedral/bake_octahedral_depth_map.js +5 -0
- package/src/engine/graphics/sh3/prototypeSH3Probe.js +2 -2
- package/src/engine/input/devices/InputDeviceSwitch.d.ts.map +1 -1
- package/src/engine/input/devices/InputDeviceSwitch.js +18 -0
- package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
- package/src/engine/input/devices/KeyboardDevice.js +4 -41
- package/src/engine/input/devices/LocationalInteractionMetadata.d.ts +11 -0
- package/src/engine/input/devices/LocationalInteractionMetadata.d.ts.map +1 -0
- package/src/engine/input/devices/LocationalInteractionMetadata.js +18 -0
- package/src/engine/input/devices/PointerDevice.d.ts.map +1 -1
- package/src/engine/input/devices/PointerDevice.js +90 -37
- package/src/engine/input/devices/eventToSourceIdentifier.d.ts +7 -0
- package/src/engine/input/devices/eventToSourceIdentifier.d.ts.map +1 -0
- package/src/engine/input/devices/eventToSourceIdentifier.js +36 -0
- package/src/engine/input/devices/isHTMLElementFocusable.d.ts +6 -0
- package/src/engine/input/devices/isHTMLElementFocusable.d.ts.map +1 -0
- package/src/engine/input/devices/isHTMLElementFocusable.js +34 -0
- package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +3 -3
- package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.d.ts.map +1 -1
- package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +5 -5
- package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts.map +1 -1
- package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +3 -3
- package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +2 -2
|
@@ -2,20 +2,20 @@ import { passThrough } from "../../function/passThrough.js";
|
|
|
2
2
|
import { returnZero } from "../../function/returnZero.js";
|
|
3
3
|
import { randomIntegerBetween } from "../../math/random/randomIntegerBetween.js";
|
|
4
4
|
import { seededRandom } from "../../math/random/seededRandom.js";
|
|
5
|
-
import
|
|
5
|
+
import FastBinaryHeap from "./FastBinaryHeap.js";
|
|
6
6
|
|
|
7
7
|
test("constructor doesn't throw", () => {
|
|
8
|
-
new
|
|
8
|
+
new FastBinaryHeap(returnZero);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
11
|
test("empty heap has size 0", () => {
|
|
12
|
-
const h = new
|
|
12
|
+
const h = new FastBinaryHeap(returnZero);
|
|
13
13
|
|
|
14
14
|
expect(h.size()).toBe(0);
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
test('clear empty', () => {
|
|
18
|
-
const h = new
|
|
18
|
+
const h = new FastBinaryHeap(returnZero);
|
|
19
19
|
|
|
20
20
|
h.clear();
|
|
21
21
|
|
|
@@ -24,7 +24,7 @@ test('clear empty', () => {
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
test('clear heap with 1 element', () => {
|
|
27
|
-
const h = new
|
|
27
|
+
const h = new FastBinaryHeap(returnZero);
|
|
28
28
|
|
|
29
29
|
h.push(1);
|
|
30
30
|
|
|
@@ -35,7 +35,7 @@ test('clear heap with 1 element', () => {
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
test("isEmpty", () => {
|
|
38
|
-
const h = new
|
|
38
|
+
const h = new FastBinaryHeap(returnZero);
|
|
39
39
|
|
|
40
40
|
expect(h.isEmpty()).toBe(true);
|
|
41
41
|
|
|
@@ -49,7 +49,7 @@ test("isEmpty", () => {
|
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
test("push followed by a pop", () => {
|
|
52
|
-
const h = new
|
|
52
|
+
const h = new FastBinaryHeap(returnZero);
|
|
53
53
|
|
|
54
54
|
h.push(7);
|
|
55
55
|
|
|
@@ -63,7 +63,7 @@ test("push followed by a pop", () => {
|
|
|
63
63
|
});
|
|
64
64
|
|
|
65
65
|
test("contains method", () => {
|
|
66
|
-
const h = new
|
|
66
|
+
const h = new FastBinaryHeap(returnZero);
|
|
67
67
|
|
|
68
68
|
expect(h.contains(7)).toBe(false);
|
|
69
69
|
|
|
@@ -82,7 +82,7 @@ test("contains method", () => {
|
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
test("correct sorting of 4 numbers", () => {
|
|
85
|
-
const h = new
|
|
85
|
+
const h = new FastBinaryHeap(passThrough);
|
|
86
86
|
|
|
87
87
|
const input = [2, 7, 1, 5];
|
|
88
88
|
|
|
@@ -100,7 +100,7 @@ test("correct sorting of 4 numbers", () => {
|
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
test.skip("performance 100k random fill -> drain", () => {
|
|
103
|
-
const h = new
|
|
103
|
+
const h = new FastBinaryHeap(passThrough);
|
|
104
104
|
|
|
105
105
|
const random = seededRandom(42);
|
|
106
106
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compact binary table storage
|
|
3
|
+
*/
|
|
1
4
|
export class RowFirstTable {
|
|
2
5
|
/**
|
|
3
6
|
*
|
|
4
|
-
* @param {RowFirstTableSpec} spec
|
|
7
|
+
* @param {RowFirstTableSpec} spec what does the schema look like? How many columns do we have and what are their types?
|
|
5
8
|
* @param {boolean} [shared_array] should we use SharedArrayBuffer instead of ArrayBuffer?
|
|
6
9
|
* @constructor
|
|
7
10
|
*/
|
|
@@ -71,9 +74,9 @@ export class RowFirstTable {
|
|
|
71
74
|
hash(): number;
|
|
72
75
|
/**
|
|
73
76
|
*
|
|
74
|
-
* @param {
|
|
77
|
+
* @param {number} rowCount
|
|
75
78
|
*/
|
|
76
|
-
setCapacity(rowCount:
|
|
79
|
+
setCapacity(rowCount: number): void;
|
|
77
80
|
/**
|
|
78
81
|
* Drop excess capacity, setting capacity exactly to the current length
|
|
79
82
|
*/
|
|
@@ -112,15 +115,15 @@ export class RowFirstTable {
|
|
|
112
115
|
insertRows(index: number, rowCount: number): void;
|
|
113
116
|
/**
|
|
114
117
|
*
|
|
115
|
-
* @param {Array.<
|
|
118
|
+
* @param {Array.<number>} values
|
|
116
119
|
*/
|
|
117
120
|
addRow(values: Array<number>): void;
|
|
118
121
|
/**
|
|
119
122
|
*
|
|
120
|
-
* @param {
|
|
121
|
-
* @param {function} valueSupplier supplier of row values, called with row index and an empty row to be filled
|
|
123
|
+
* @param {number} count number of rows to be added
|
|
124
|
+
* @param {function(row_index:number, row:Array.<number>):*} valueSupplier supplier of row values, called with row index and an empty row to be filled
|
|
122
125
|
*/
|
|
123
|
-
addRows(count:
|
|
126
|
+
addRows(count: number, valueSupplier: any): void;
|
|
124
127
|
/**
|
|
125
128
|
* Copy data from another table. Specs must match.
|
|
126
129
|
* NOTE: does not send onAdded signal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RowFirstTable.d.ts","sourceRoot":"","sources":["../../../../../src/core/collection/table/RowFirstTable.js"],"names":[],"mappings":"AAMA;IACI;;;;;OAKG;IACH,oDAHW,OAAO,EAuDjB;IA/CG;;;OAGG;IACH,wBAAgB;IAEhB;;;OAGG;IACH,gBAFU,qBAAsB,CAET;IAEvB;;;OAGG;IACH,MAFU,WAAW,CAEuB;IAE5C;;;OAGG;IACH,gBAFU,MAAM,CAEyB;IAEzC;;;OAGG;IACH,QAFU,MAAM,CAED;IAEf;;;OAGG;IACH,UAFU,MAAM,CAEC;IAEjB;;;OAGG;IACH,UAFU,QAAQ,CAEE;IAEpB;;MAEC;IAKL;;OAEG;IACH,mBAiBC;IAXG;;;OAGG;IACH,sBAFmB,QAAQ,QAAE,MAAM,QAAE,MAAM,EAAE,KAAG,IAAI,CAEb;IAEvC;;;OAGG;IACH,uBAFmB,QAAQ,QAAE,MAAM,QAAE,MAAM,EAAE,KAAG,IAAI,CAEX;IAG7C;;;;OAIG;IACH,uDAMC;IAED;;;OAGG;IACH,QAFa,MAAM,CA4BlB;IAED;;;OAGG;IACH,
|
|
1
|
+
{"version":3,"file":"RowFirstTable.d.ts","sourceRoot":"","sources":["../../../../../src/core/collection/table/RowFirstTable.js"],"names":[],"mappings":"AAMA;;GAEG;AACH;IACI;;;;;OAKG;IACH,oDAHW,OAAO,EAuDjB;IA/CG;;;OAGG;IACH,wBAAgB;IAEhB;;;OAGG;IACH,gBAFU,qBAAsB,CAET;IAEvB;;;OAGG;IACH,MAFU,WAAW,CAEuB;IAE5C;;;OAGG;IACH,gBAFU,MAAM,CAEyB;IAEzC;;;OAGG;IACH,QAFU,MAAM,CAED;IAEf;;;OAGG;IACH,UAFU,MAAM,CAEC;IAEjB;;;OAGG;IACH,UAFU,QAAQ,CAEE;IAEpB;;MAEC;IAKL;;OAEG;IACH,mBAiBC;IAXG;;;OAGG;IACH,sBAFmB,QAAQ,QAAE,MAAM,QAAE,MAAM,EAAE,KAAG,IAAI,CAEb;IAEvC;;;OAGG;IACH,uBAFmB,QAAQ,QAAE,MAAM,QAAE,MAAM,EAAE,KAAG,IAAI,CAEX;IAG7C;;;;OAIG;IACH,uDAMC;IAED;;;OAGG;IACH,QAFa,MAAM,CA4BlB;IAED;;;OAGG;IACH,sBAFW,MAAM,QA+ChB;IAED;;OAEG;IACH,aAEC;IAED;;;OAGG;IACH,iBAFW,MAAM,QAchB;IAED;;;;;OAKG;IACH,yBAJW,MAAM,eACN,MAAM,SACN,MAAM,QAchB;IAED;;;;;OAKG;IACH,wBAJW,MAAM,eACN,MAAM,GACJ,MAAM,CAclB;IAED;;;;OAIG;IACH,kBAHW,MAAM,YACN,MAAM,QAyBhB;IAED;;;;;OAKG;IACH,kBAHW,MAAM,YACN,MAAM,QAqBhB;IAED;;;OAGG;IACH,eAFW,MAAO,MAAM,CAAC,QAexB;IAED;;;;OAIG;IACH,eAHW,MAAM,4BAoChB;IAED;;;;OAIG;IACH,YAFW,aAAa,QAsBvB;IAED;;;OAGG;IACH,cAHW,aAAa,GACX,OAAO,CAyBnB;IAED;;;;OAIG;IACH,wCAIC;IAED;;;;OAIG;IACH,cAHW,MAAM,UACN,MAAM,EAAE,QAMlB;IAED;;OAEG;IACH,qBA4BC;IAED;;OAEG;IACH,cAIC;IAED;;;OAGG;IACH,wBAEC;IAED;;;OAGG;IACH,cAFa,MAAM,EAAE,EAAE,CAgBtB;IAED;;OAEG;IACH,uBAIC;CACJ;mBA3gBkB,+BAA+B"}
|
|
@@ -4,10 +4,13 @@ import Signal from "../../events/signal/Signal.js";
|
|
|
4
4
|
import { max2 } from "../../math/max2.js";
|
|
5
5
|
import { array_copy } from "../array/array_copy.js";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Compact binary table storage
|
|
9
|
+
*/
|
|
7
10
|
export class RowFirstTable {
|
|
8
11
|
/**
|
|
9
12
|
*
|
|
10
|
-
* @param {RowFirstTableSpec} spec
|
|
13
|
+
* @param {RowFirstTableSpec} spec what does the schema look like? How many columns do we have and what are their types?
|
|
11
14
|
* @param {boolean} [shared_array] should we use SharedArrayBuffer instead of ArrayBuffer?
|
|
12
15
|
* @constructor
|
|
13
16
|
*/
|
|
@@ -134,13 +137,22 @@ export class RowFirstTable {
|
|
|
134
137
|
|
|
135
138
|
/**
|
|
136
139
|
*
|
|
137
|
-
* @param {
|
|
140
|
+
* @param {number} rowCount
|
|
138
141
|
*/
|
|
139
142
|
setCapacity(rowCount) {
|
|
143
|
+
assert.isNonNegativeInteger(rowCount, 'rowCount');
|
|
144
|
+
|
|
145
|
+
if(this.capacity === rowCount){
|
|
146
|
+
// already right size
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
140
151
|
const oldData = this.data;
|
|
141
152
|
|
|
142
153
|
const bytesPerRecord = this.bytesPerRecord;
|
|
143
154
|
const byteSize = rowCount * bytesPerRecord;
|
|
155
|
+
|
|
144
156
|
try {
|
|
145
157
|
// can be either ArrayBuffer or SharedArrayBuffer
|
|
146
158
|
const BufferConstructor = this.data.constructor;
|
|
@@ -186,6 +198,8 @@ export class RowFirstTable {
|
|
|
186
198
|
* @param {number} rowCount
|
|
187
199
|
*/
|
|
188
200
|
resize(rowCount) {
|
|
201
|
+
assert.isNonNegativeInteger(rowCount, 'rowCount');
|
|
202
|
+
|
|
189
203
|
if (this.capacity < rowCount) {
|
|
190
204
|
//grow
|
|
191
205
|
const growFactor = 1.5;
|
|
@@ -296,7 +310,7 @@ export class RowFirstTable {
|
|
|
296
310
|
|
|
297
311
|
/**
|
|
298
312
|
*
|
|
299
|
-
* @param {Array.<
|
|
313
|
+
* @param {Array.<number>} values
|
|
300
314
|
*/
|
|
301
315
|
addRow(values) {
|
|
302
316
|
|
|
@@ -308,7 +322,6 @@ export class RowFirstTable {
|
|
|
308
322
|
|
|
309
323
|
this.length = newRowCount;
|
|
310
324
|
|
|
311
|
-
|
|
312
325
|
this.writeRowMethod(this.dataView, this.bytesPerRecord * rowIndex, values);
|
|
313
326
|
|
|
314
327
|
this.on.added.send2(rowIndex, values);
|
|
@@ -316,8 +329,8 @@ export class RowFirstTable {
|
|
|
316
329
|
|
|
317
330
|
/**
|
|
318
331
|
*
|
|
319
|
-
* @param {
|
|
320
|
-
* @param {function} valueSupplier supplier of row values, called with row index and an empty row to be filled
|
|
332
|
+
* @param {number} count number of rows to be added
|
|
333
|
+
* @param {function(row_index:number, row:Array.<number>):*} valueSupplier supplier of row values, called with row index and an empty row to be filled
|
|
321
334
|
*/
|
|
322
335
|
addRows(count, valueSupplier) {
|
|
323
336
|
const newRowCount = this.length + count;
|
|
@@ -416,6 +429,8 @@ export class RowFirstTable {
|
|
|
416
429
|
* @param {Array} result where row values are to be stored
|
|
417
430
|
*/
|
|
418
431
|
getRow(index, result) {
|
|
432
|
+
assert.isNonNegativeInteger(index,'index');
|
|
433
|
+
|
|
419
434
|
this.readRowMethod(this.dataView, this.bytesPerRecord * index, result);
|
|
420
435
|
}
|
|
421
436
|
|
|
@@ -425,6 +440,8 @@ export class RowFirstTable {
|
|
|
425
440
|
* @param {number[]} record
|
|
426
441
|
*/
|
|
427
442
|
setRow(index, record) {
|
|
443
|
+
assert.isNonNegativeInteger(index,'index');
|
|
444
|
+
|
|
428
445
|
this.writeRowMethod(this.dataView, this.bytesPerRecord * index, record);
|
|
429
446
|
}
|
|
430
447
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableRecord.d.ts","sourceRoot":"","sources":["../../../../../../src/core/collection/table/bind/TableRecord.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TableRecord.d.ts","sourceRoot":"","sources":["../../../../../../src/core/collection/table/bind/TableRecord.js"],"names":[],"mappings":"AAKA;IA+DI;;;OAGG;IACH,yBAYC;IA/BD,qBAEC;IAND,kBAEC;IAOD,uBAIC;IAED,YAEC;IAoBD,sCAEC;IAED;;;;OAIG;IACH,sCAFW,MAAM,QAKhB;;CACJ;kCAhGiC,yBAAyB"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { assert } from "../../../assert.js";
|
|
2
|
+
import { BinaryDataType } from "../../../binary/type/BinaryDataType.js";
|
|
3
|
+
import { validate_enum_schema } from "../../../model/validate_enum_schema.js";
|
|
2
4
|
import { RowFirstTableSpec } from "../RowFirstTableSpec.js";
|
|
3
5
|
|
|
4
6
|
export class TableRecord {
|
|
@@ -72,6 +74,8 @@ export class TableRecord {
|
|
|
72
74
|
assert.notNull(schema, 'schema');
|
|
73
75
|
assert.defined(schema, 'schema');
|
|
74
76
|
|
|
77
|
+
assert.ok(validate_enum_schema(schema, BinaryDataType, console.warn), 'invalid schema');
|
|
78
|
+
|
|
75
79
|
this.#schema = schema;
|
|
76
80
|
const keys = Object.keys(schema);
|
|
77
81
|
|
|
@@ -23,10 +23,10 @@ export function encode_unit_to_octahedron(
|
|
|
23
23
|
const inverse_sum = 1 / abs_sum;
|
|
24
24
|
|
|
25
25
|
let p_x = x * inverse_sum;
|
|
26
|
-
let p_y =
|
|
26
|
+
let p_y = z * inverse_sum;
|
|
27
27
|
|
|
28
28
|
// Reflect the folds of the lower hemisphere over the diagonals
|
|
29
|
-
if (
|
|
29
|
+
if (y < 0) {
|
|
30
30
|
const abs_x = Math.abs(p_x);
|
|
31
31
|
const abs_y = Math.abs(p_y);
|
|
32
32
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { assert } from "../../../assert.js";
|
|
2
|
-
import
|
|
2
|
+
import FastBinaryHeap from "../../../collection/heap/FastBinaryHeap.js";
|
|
3
3
|
import AABB2 from "../../2d/aabb/AABB2.js";
|
|
4
4
|
import { QuadTreeDatum } from "../../2d/quad-tree/QuadTreeDatum.js";
|
|
5
5
|
import { QuadTreeNode } from "../../2d/quad-tree/QuadTreeNode.js";
|
|
@@ -136,7 +136,7 @@ export class MaxRectanglesPacker {
|
|
|
136
136
|
return -Math.min(box.getWidth(), box.getHeight());
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
const heap = new
|
|
139
|
+
const heap = new FastBinaryHeap(scoreBoxByMinSide);
|
|
140
140
|
|
|
141
141
|
for (let i = 0; i < numBoxes; i++) {
|
|
142
142
|
heap.push(i);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template T
|
|
3
|
+
* @param {Object<BinaryDataType>} schema
|
|
4
|
+
* @param {Object<T>} enumerable
|
|
5
|
+
* @param {function(message:string)} [error_consumer]
|
|
6
|
+
* @param {*} [error_consumer_context]
|
|
7
|
+
*/
|
|
8
|
+
export function validate_enum_schema<T>(schema: any, enumerable: any, error_consumer?: typeof noop, error_consumer_context?: any): boolean;
|
|
9
|
+
import { noop } from "../function/noop.js";
|
|
10
|
+
//# sourceMappingURL=validate_enum_schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate_enum_schema.d.ts","sourceRoot":"","sources":["../../../../src/core/model/validate_enum_schema.js"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,2IAoBC;qBA7BoB,qBAAqB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { assert } from "../assert.js";
|
|
2
|
+
import { noop } from "../function/noop.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @template T
|
|
6
|
+
* @param {Object<BinaryDataType>} schema
|
|
7
|
+
* @param {Object<T>} enumerable
|
|
8
|
+
* @param {function(message:string)} [error_consumer]
|
|
9
|
+
* @param {*} [error_consumer_context]
|
|
10
|
+
*/
|
|
11
|
+
export function validate_enum_schema(schema, enumerable, error_consumer = noop, error_consumer_context) {
|
|
12
|
+
|
|
13
|
+
assert.notNull(schema, 'schema');
|
|
14
|
+
assert.isObject(schema, 'schema');
|
|
15
|
+
|
|
16
|
+
let valid = true;
|
|
17
|
+
const valid_types = Object.values(enumerable);
|
|
18
|
+
|
|
19
|
+
for (const schemaKey in schema) {
|
|
20
|
+
|
|
21
|
+
const type = schema[schemaKey];
|
|
22
|
+
|
|
23
|
+
if (!valid_types.includes(type)) {
|
|
24
|
+
error_consumer.call(error_consumer_context, `Field '${schemaKey}' is expected to have have BinaryDataType value, instead found '${type}'. Valid values are: ${valid_types.join(', ')}.`);
|
|
25
|
+
valid = false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return valid;
|
|
31
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template T
|
|
3
|
+
*/
|
|
4
|
+
export class TimeSeries<T> {
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param {Object<BinaryDataType>} schema
|
|
8
|
+
* @param {string} [time_column_name]
|
|
9
|
+
*/
|
|
10
|
+
constructor(schema: any, time_column_name?: string);
|
|
11
|
+
/**
|
|
12
|
+
* @type {RowFirstTableSpec}
|
|
13
|
+
*/
|
|
14
|
+
spec: RowFirstTableSpec;
|
|
15
|
+
/**
|
|
16
|
+
* @type {RowFirstTable}
|
|
17
|
+
*/
|
|
18
|
+
table: RowFirstTable;
|
|
19
|
+
time_column_index: number;
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @param {number} index
|
|
23
|
+
* @returns {Object}
|
|
24
|
+
*/
|
|
25
|
+
getSampleObjectByIndex(index: number): any;
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* @returns {number}
|
|
29
|
+
*/
|
|
30
|
+
get sample_count(): number;
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* @returns {number}
|
|
34
|
+
*/
|
|
35
|
+
get last_timestamp(): number;
|
|
36
|
+
validateNextSample(data: any): void;
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param {number[]} data
|
|
40
|
+
*/
|
|
41
|
+
addSample(data: number[]): void;
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
* @param {Object} sample
|
|
45
|
+
*/
|
|
46
|
+
addObjectSample(sample: any): void;
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @param {number[]} result
|
|
50
|
+
* @param {number} index
|
|
51
|
+
*/
|
|
52
|
+
getSampleByIndex(result: number[], index: number): void;
|
|
53
|
+
/**
|
|
54
|
+
*
|
|
55
|
+
* @param {number} time
|
|
56
|
+
* @returns {number}
|
|
57
|
+
*/
|
|
58
|
+
findLowSampleIndexByTime(time: number): number;
|
|
59
|
+
/**
|
|
60
|
+
*
|
|
61
|
+
* @param {number[]} result
|
|
62
|
+
* @param {number} result_offset
|
|
63
|
+
* @param {number} time
|
|
64
|
+
*/
|
|
65
|
+
sampleLinear(result: number[], result_offset: number, time: number): void;
|
|
66
|
+
/**
|
|
67
|
+
* Get linearly interpolated sample for given time in object form, following supplied schema
|
|
68
|
+
* @param {number} time
|
|
69
|
+
* @returns {Object}
|
|
70
|
+
*/
|
|
71
|
+
sampleObjectLinear(time: number): any;
|
|
72
|
+
#private;
|
|
73
|
+
}
|
|
74
|
+
import { RowFirstTableSpec } from "../../../core/collection/table/RowFirstTableSpec.js";
|
|
75
|
+
import { RowFirstTable } from "../../../core/collection/table/RowFirstTable.js";
|
|
76
|
+
//# sourceMappingURL=TimeSeries.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimeSeries.d.ts","sourceRoot":"","sources":["../../../../../src/engine/animation/async/TimeSeries.js"],"names":[],"mappings":"AAiBA;;GAEG;AACH;IA+BI;;;;OAIG;IACH,4CAFW,MAAM,EAuChB;IAxED;;OAEG;IACH,MAFU,iBAAiB,CAEvB;IAEJ;;OAEG;IACH,OAFU,aAAa,CAElB;IAEL,0BAAsB;IAyHtB;;;;OAIG;IACH,8BAHW,MAAM,OAOhB;IAED;;;OAGG;IACH,2BAEC;IAED;;;OAGG;IACH,6BAWC;IAED,oCAcC;IAED;;;OAGG;IACH,gBAFW,MAAM,EAAE,QAQlB;IAED;;;OAGG;IACH,mCAIC;IAED;;;;OAIG;IACH,yBAHW,MAAM,EAAE,SACR,MAAM,QAIhB;IAED;;;;OAIG;IACH,+BAHW,MAAM,GACJ,MAAM,CAMlB;IAED;;;;;OAKG;IACH,qBAJW,MAAM,EAAE,iBACR,MAAM,QACN,MAAM,QAuBhB;IAED;;;;OAIG;IACH,yBAHW,MAAM,OAShB;;CAEJ;kCA7RiC,qDAAqD;8BADzD,iDAAiD"}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { assert } from "../../../core/assert.js";
|
|
2
|
+
import { BinaryDataType } from "../../../core/binary/type/BinaryDataType.js";
|
|
3
|
+
import { RowFirstTable } from "../../../core/collection/table/RowFirstTable.js";
|
|
4
|
+
import { RowFirstTableSpec } from "../../../core/collection/table/RowFirstTableSpec.js";
|
|
5
|
+
import { inverseLerp } from "../../../core/math/inverseLerp.js";
|
|
6
|
+
import { lerp } from "../../../core/math/lerp.js";
|
|
7
|
+
import { max2 } from "../../../core/math/max2.js";
|
|
8
|
+
import { min2 } from "../../../core/math/min2.js";
|
|
9
|
+
import { validate_enum_schema } from "../../../core/model/validate_enum_schema.js";
|
|
10
|
+
import { table_find_min_index_in_ordered_column } from "./table_find_min_index_in_ordered_column.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @type {number[]}
|
|
15
|
+
*/
|
|
16
|
+
const scratch_row = [];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @template T
|
|
20
|
+
*/
|
|
21
|
+
export class TimeSeries {
|
|
22
|
+
/**
|
|
23
|
+
* @type {RowFirstTableSpec}
|
|
24
|
+
*/
|
|
25
|
+
spec
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @type {RowFirstTable}
|
|
29
|
+
*/
|
|
30
|
+
table
|
|
31
|
+
|
|
32
|
+
time_column_index = 0;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @type {Object<BinaryDataType>}
|
|
37
|
+
*/
|
|
38
|
+
#schema = {}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @type {Object<number>}
|
|
43
|
+
*/
|
|
44
|
+
#schema_column_names_to_indices = {};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @type {string[]}
|
|
49
|
+
*/
|
|
50
|
+
#schema_column_indices_to_names = [];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
* @param {Object<BinaryDataType>} schema
|
|
55
|
+
* @param {string} [time_column_name]
|
|
56
|
+
*/
|
|
57
|
+
constructor(schema, time_column_name = 'time') {
|
|
58
|
+
assert.isString(time_column_name, 'time_column_name');
|
|
59
|
+
assert.notNull(schema, 'schema');
|
|
60
|
+
assert.isObject(schema, 'schema');
|
|
61
|
+
|
|
62
|
+
let issues = [];
|
|
63
|
+
|
|
64
|
+
if (!validate_enum_schema(schema, BinaryDataType, (issue) => issues.push(issue))) {
|
|
65
|
+
throw new TypeError(`Invalid schema. Problems:\n ${issues.join('\n')}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.#schema = schema;
|
|
69
|
+
|
|
70
|
+
const schema_keys = Object.keys(schema);
|
|
71
|
+
|
|
72
|
+
const time_row_index = schema_keys.indexOf(time_column_name);
|
|
73
|
+
|
|
74
|
+
if (time_row_index === -1) {
|
|
75
|
+
throw new TypeError(`supplies schema does not include time column '${time_column_name}', exising columns: ${schema_keys.join(', ')}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.time_column_index = time_row_index;
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
this.#schema_column_names_to_indices = {};
|
|
82
|
+
|
|
83
|
+
for (let i = 0; i < schema_keys.length; i++) {
|
|
84
|
+
const key = schema_keys[i];
|
|
85
|
+
|
|
86
|
+
this.#schema_column_names_to_indices[key] = i;
|
|
87
|
+
this.#schema_column_indices_to_names[i] = key;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.spec = RowFirstTableSpec.get(Object.values(schema));
|
|
91
|
+
|
|
92
|
+
this.table = new RowFirstTable(this.spec);
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
*
|
|
98
|
+
* @param {number[]} row
|
|
99
|
+
* @param {Object} object
|
|
100
|
+
*/
|
|
101
|
+
#object_to_row(row, object) {
|
|
102
|
+
|
|
103
|
+
const columnCount = this.spec.getColumnCount();
|
|
104
|
+
|
|
105
|
+
for (let i = 0; i < columnCount; i++) {
|
|
106
|
+
|
|
107
|
+
const key = this.#schema_column_indices_to_names[i];
|
|
108
|
+
|
|
109
|
+
const value = object[key];
|
|
110
|
+
|
|
111
|
+
const t = typeof value;
|
|
112
|
+
|
|
113
|
+
if (t !== "number") {
|
|
114
|
+
throw new TypeError(`Expected sample.${key} to be a number, instead was ${t} (=${value})`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
row[i] = value;
|
|
118
|
+
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
*
|
|
124
|
+
* @param {Object} object
|
|
125
|
+
* @param {number[]} row
|
|
126
|
+
*/
|
|
127
|
+
#row_to_object(object, row) {
|
|
128
|
+
|
|
129
|
+
const columnCount = this.spec.getColumnCount();
|
|
130
|
+
for (let i = 0; i < columnCount; i++) {
|
|
131
|
+
|
|
132
|
+
const key = this.#schema_column_indices_to_names[i];
|
|
133
|
+
|
|
134
|
+
object[key] = row[i];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
*
|
|
141
|
+
* @param {number[]} row
|
|
142
|
+
* @returns {Object}
|
|
143
|
+
*/
|
|
144
|
+
#row_to_object_allocating(row) {
|
|
145
|
+
|
|
146
|
+
const result = {};
|
|
147
|
+
|
|
148
|
+
this.#row_to_object(result, row);
|
|
149
|
+
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
*
|
|
155
|
+
* @param {number} index
|
|
156
|
+
* @returns {Object}
|
|
157
|
+
*/
|
|
158
|
+
getSampleObjectByIndex(index) {
|
|
159
|
+
this.table.getRow(index, scratch_row);
|
|
160
|
+
|
|
161
|
+
return this.#row_to_object_allocating(scratch_row);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
*
|
|
166
|
+
* @returns {number}
|
|
167
|
+
*/
|
|
168
|
+
get sample_count() {
|
|
169
|
+
return this.table.length;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
*
|
|
174
|
+
* @returns {number}
|
|
175
|
+
*/
|
|
176
|
+
get last_timestamp() {
|
|
177
|
+
const table = this.table;
|
|
178
|
+
const record_count = table.length;
|
|
179
|
+
|
|
180
|
+
if (record_count === 0) {
|
|
181
|
+
// default
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const time_column = this.time_column_index;
|
|
186
|
+
return table.readCellValue(record_count - 1, time_column);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
validateNextSample(data) {
|
|
190
|
+
|
|
191
|
+
const table = this.table;
|
|
192
|
+
const record_count = table.length;
|
|
193
|
+
|
|
194
|
+
if (record_count > 0) {
|
|
195
|
+
const time_column = this.time_column_index;
|
|
196
|
+
const last_time = table.readCellValue(record_count - 1, time_column);
|
|
197
|
+
|
|
198
|
+
if (data[time_column] <= last_time) {
|
|
199
|
+
throw new Error(`Sample.time[${time_column}] = ${data[time_column]}, which is <= to previous time stamp(=${last_time}). Each sample's time stamp must be strictly greater than the previous one`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
*
|
|
207
|
+
* @param {number[]} data
|
|
208
|
+
*/
|
|
209
|
+
addSample(data) {
|
|
210
|
+
// validate
|
|
211
|
+
this.validateNextSample(data);
|
|
212
|
+
|
|
213
|
+
const table = this.table;
|
|
214
|
+
table.addRow(data);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
*
|
|
219
|
+
* @param {Object} sample
|
|
220
|
+
*/
|
|
221
|
+
addObjectSample(sample) {
|
|
222
|
+
this.#object_to_row(scratch_row, sample);
|
|
223
|
+
|
|
224
|
+
this.addSample(scratch_row);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
*
|
|
229
|
+
* @param {number[]} result
|
|
230
|
+
* @param {number} index
|
|
231
|
+
*/
|
|
232
|
+
getSampleByIndex(result, index) {
|
|
233
|
+
this.table.getRow(index, result)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
*
|
|
238
|
+
* @param {number} time
|
|
239
|
+
* @returns {number}
|
|
240
|
+
*/
|
|
241
|
+
findLowSampleIndexByTime(time) {
|
|
242
|
+
const table = this.table;
|
|
243
|
+
const time_column_index = this.time_column_index;
|
|
244
|
+
return max2(0, table_find_min_index_in_ordered_column(table, time, time_column_index))
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
*
|
|
249
|
+
* @param {number[]} result
|
|
250
|
+
* @param {number} result_offset
|
|
251
|
+
* @param {number} time
|
|
252
|
+
*/
|
|
253
|
+
sampleLinear(result, result_offset, time) {
|
|
254
|
+
const table = this.table;
|
|
255
|
+
const time_column_index = this.time_column_index;
|
|
256
|
+
|
|
257
|
+
// seek to the right sample
|
|
258
|
+
const sample_index = this.findLowSampleIndexByTime(time);
|
|
259
|
+
const next_sample_index = min2(table.length - 1, sample_index + 1);
|
|
260
|
+
|
|
261
|
+
const prev = table.readCellValue(sample_index, time_column_index);
|
|
262
|
+
const next = table.readCellValue(next_sample_index, time_column_index);
|
|
263
|
+
|
|
264
|
+
const normalized_offset = inverseLerp(prev, next, time);
|
|
265
|
+
|
|
266
|
+
const column_count = this.spec.getColumnCount();
|
|
267
|
+
|
|
268
|
+
for (let i = 0; i < column_count; i++) {
|
|
269
|
+
const v0 = table.readCellValue(sample_index, i);
|
|
270
|
+
const v1 = table.readCellValue(next_sample_index, i);
|
|
271
|
+
|
|
272
|
+
result[result_offset + i] = lerp(v0, v1, normalized_offset)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Get linearly interpolated sample for given time in object form, following supplied schema
|
|
278
|
+
* @param {number} time
|
|
279
|
+
* @returns {Object}
|
|
280
|
+
*/
|
|
281
|
+
sampleObjectLinear(time) {
|
|
282
|
+
|
|
283
|
+
this.sampleLinear(scratch_row, 0, time);
|
|
284
|
+
|
|
285
|
+
return this.#row_to_object_allocating(scratch_row);
|
|
286
|
+
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
}
|