@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.
Files changed (55) hide show
  1. package/build/meep.cjs +231 -104
  2. package/build/meep.min.js +1 -1
  3. package/build/meep.module.js +231 -104
  4. package/package.json +1 -1
  5. package/src/core/collection/heap/FastBinaryHeap.d.ts +17 -10
  6. package/src/core/collection/heap/FastBinaryHeap.d.ts.map +1 -1
  7. package/src/core/collection/heap/FastBinaryHeap.js +33 -23
  8. package/src/core/collection/heap/FastBinaryHeap.spec.js +10 -10
  9. package/src/core/collection/table/RowFirstTable.d.ts +10 -7
  10. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  11. package/src/core/collection/table/RowFirstTable.js +23 -6
  12. package/src/core/collection/table/bind/TableRecord.d.ts.map +1 -1
  13. package/src/core/collection/table/bind/TableRecord.js +4 -0
  14. package/src/core/geom/3d/normal/octahedron/encode_unit_to_octahedron.js +2 -2
  15. package/src/core/geom/packing/max-rect/MaxRectanglesPacker.js +2 -2
  16. package/src/core/model/validate_enum_schema.d.ts +10 -0
  17. package/src/core/model/validate_enum_schema.d.ts.map +1 -0
  18. package/src/core/model/validate_enum_schema.js +31 -0
  19. package/src/engine/animation/async/TimeSeries.d.ts +76 -0
  20. package/src/engine/animation/async/TimeSeries.d.ts.map +1 -0
  21. package/src/engine/animation/async/TimeSeries.js +289 -0
  22. package/src/engine/animation/async/prototypeAsyncAnimation.js +31 -83
  23. package/src/engine/animation/async/table_find_min_index_in_ordered_column.d.ts +9 -0
  24. package/src/engine/animation/async/table_find_min_index_in_ordered_column.d.ts.map +1 -0
  25. package/src/engine/animation/async/table_find_min_index_in_ordered_column.js +32 -0
  26. package/src/engine/asset/AssetManager.js +1 -1
  27. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  28. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +14 -11
  29. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +1 -1
  30. package/src/engine/graphics/sh3/gi/material/common.glsl +1 -1
  31. package/src/engine/graphics/sh3/lpv/LightProbeVolume.js +1 -1
  32. package/src/engine/graphics/sh3/lpv/depth/octahedral/bake_octahedral_depth_map.d.ts.map +1 -1
  33. package/src/engine/graphics/sh3/lpv/depth/octahedral/bake_octahedral_depth_map.js +5 -0
  34. package/src/engine/graphics/sh3/prototypeSH3Probe.js +2 -2
  35. package/src/engine/input/devices/InputDeviceSwitch.d.ts.map +1 -1
  36. package/src/engine/input/devices/InputDeviceSwitch.js +18 -0
  37. package/src/engine/input/devices/KeyboardDevice.d.ts.map +1 -1
  38. package/src/engine/input/devices/KeyboardDevice.js +4 -41
  39. package/src/engine/input/devices/LocationalInteractionMetadata.d.ts +11 -0
  40. package/src/engine/input/devices/LocationalInteractionMetadata.d.ts.map +1 -0
  41. package/src/engine/input/devices/LocationalInteractionMetadata.js +18 -0
  42. package/src/engine/input/devices/PointerDevice.d.ts.map +1 -1
  43. package/src/engine/input/devices/PointerDevice.js +90 -37
  44. package/src/engine/input/devices/eventToSourceIdentifier.d.ts +7 -0
  45. package/src/engine/input/devices/eventToSourceIdentifier.d.ts.map +1 -0
  46. package/src/engine/input/devices/eventToSourceIdentifier.js +36 -0
  47. package/src/engine/input/devices/isHTMLElementFocusable.d.ts +6 -0
  48. package/src/engine/input/devices/isHTMLElementFocusable.d.ts.map +1 -0
  49. package/src/engine/input/devices/isHTMLElementFocusable.js +34 -0
  50. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +3 -3
  51. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.d.ts.map +1 -1
  52. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +5 -5
  53. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts.map +1 -1
  54. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +3 -3
  55. 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 BinaryHeap from "./FastBinaryHeap.js";
5
+ import FastBinaryHeap from "./FastBinaryHeap.js";
6
6
 
7
7
  test("constructor doesn't throw", () => {
8
- new BinaryHeap(returnZero);
8
+ new FastBinaryHeap(returnZero);
9
9
  });
10
10
 
11
11
  test("empty heap has size 0", () => {
12
- const h = new BinaryHeap(returnZero);
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 BinaryHeap(returnZero);
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 BinaryHeap(returnZero);
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 BinaryHeap(returnZero);
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 BinaryHeap(returnZero);
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 BinaryHeap(returnZero);
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 BinaryHeap(passThrough);
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 BinaryHeap(passThrough);
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 {int} rowCount
77
+ * @param {number} rowCount
75
78
  */
76
- setCapacity(rowCount: int): void;
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.<Number>} values
118
+ * @param {Array.<number>} values
116
119
  */
117
120
  addRow(values: Array<number>): void;
118
121
  /**
119
122
  *
120
- * @param {int} count number of rows to be added
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: int, valueSupplier: Function): void;
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,iCAoCC;IAED;;OAEG;IACH,aAEC;IAED;;;OAGG;IACH,iBAFW,MAAM,QAYhB;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,aAAc,QAgBxB;IAED;;;;OAIG;IACH,mDAiCC;IAED;;;;OAIG;IACH,YAFW,aAAa,QAsBvB;IAED;;;OAGG;IACH,cAHW,aAAa,GACX,OAAO,CAyBnB;IAED;;;;OAIG;IACH,wCAEC;IAED;;;;OAIG;IACH,cAHW,MAAM,UACN,MAAM,EAAE,QAIlB;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;mBA1fkB,+BAA+B"}
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 {int} rowCount
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.<Number>} values
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 {int} count number of rows to be added
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":"AAGA;IA+DI;;;OAGG;IACH,yBAUC;IA7BD,qBAEC;IAND,kBAEC;IAOD,uBAIC;IAED,YAEC;IAkBD,sCAEC;IAED;;;;OAIG;IACH,sCAFW,MAAM,QAKhB;;CACJ;kCA9FiC,yBAAyB"}
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 = y * inverse_sum;
26
+ let p_y = z * inverse_sum;
27
27
 
28
28
  // Reflect the folds of the lower hemisphere over the diagonals
29
- if (z < 0) {
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 BinaryHeap from "../../../collection/heap/FastBinaryHeap.js";
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 BinaryHeap(scoreBoxByMinSide);
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
+ }