@woosh/meep-engine 2.78.1 → 2.80.0

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 (56) hide show
  1. package/build/meep.cjs +235 -233
  2. package/build/meep.min.js +1 -1
  3. package/build/meep.module.js +235 -233
  4. package/package.json +1 -1
  5. package/src/core/geom/2d/aabb/AABB2.js +6 -18
  6. package/src/core/geom/3d/SurfacePoint3.spec.js +1 -1
  7. package/src/core/geom/3d/{matrix → mat4}/m4_multiply.spec.js +3 -4
  8. package/src/core/geom/3d/{matrix → mat4}/m4_multiply_alphatensor.spec.js +3 -3
  9. package/src/core/geom/3d/morton/v3_morton_encode_transformed.spec.js +1 -1
  10. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.spec.js +1 -1
  11. package/src/core/geom/Quaternion.js +1 -1
  12. package/src/core/geom/Vector3.js +2 -2
  13. package/src/core/geom/Vector3.spec.js +2 -2
  14. package/src/core/geom/packing/max-rect/{MaxRectangles.js → MaxRectanglesPacker.js} +25 -32
  15. package/src/core/geom/packing/max-rect/MaxRectanglesPacker.spec.js +60 -0
  16. package/src/core/geom/packing/max-rect/packMaxRectangles.js +19 -0
  17. package/src/core/geom/vec3/v3_angle_between.js +15 -4
  18. package/src/core/geom/vec3/{v3_computeOffsetVector.js → v3_displace_in_direction.js} +11 -2
  19. package/src/core/graph/cluster_mesh_metis.js +3 -3
  20. package/src/core/graph/metis/metis.js +16 -1
  21. package/src/core/graph/metis/metis_options.js +32 -29
  22. package/src/core/math/interval/overlap1D.js +7 -0
  23. package/src/core/math/noise/create_simplex_noise_2d.js +4 -0
  24. package/src/core/math/spline/computeCatmullRomSplineUniformDistance.js +3 -3
  25. package/src/core/math/spline/v3_computeCatmullRomSplineUniformDistance.js +42 -0
  26. package/src/core/model/node-graph/node/NodeDescription.js +12 -10
  27. package/src/core/model/node-graph/node/NodeDescription.spec.js +14 -1
  28. package/src/core/model/object/objectKeyByValue.js +3 -2
  29. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +2 -2
  30. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +2 -2
  31. package/src/engine/ecs/renderable/Renderable.js +1 -1
  32. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +1 -1
  33. package/src/engine/ecs/terrain/tiles/TerrainTile.spec.js +2 -2
  34. package/src/engine/ecs/transform/Transform.js +3 -3
  35. package/src/engine/ecs/transform/Transform.spec.js +3 -3
  36. package/src/engine/ecs/transform-attachment/TransformAttachment.js +2 -1
  37. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +45 -33
  38. package/src/engine/graphics/ecs/path/entity/testEntityPath.js +16 -10
  39. package/src/engine/graphics/material/optimization/MaterialOptimizationContext.js +1 -1
  40. package/src/engine/graphics/texture/atlas/TextureAtlas.js +1 -1
  41. package/src/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.js +3 -3
  42. package/src/engine/graphics/three/expand_aabb_by_transformed_three_object.js +1 -1
  43. package/src/engine/graphics/three/expand_aabb_by_transformed_three_object.spec.js +2 -2
  44. package/src/engine/navigation/ecs/components/Path.js +5 -12
  45. package/src/engine/simulation/Ticker.js +40 -61
  46. package/src/core/geom/LineSegment.js +0 -207
  47. package/src/core/primitives/strings/prefixTree/PrefixTree.js +0 -225
  48. package/src/core/primitives/strings/prefixTree/PrefixTree.spec.js +0 -39
  49. package/src/core/primitives/strings/prefixTree/PrefixTreeLeaf.js +0 -25
  50. package/src/core/primitives/strings/prefixTree/PrefixTreeNode.js +0 -16
  51. /package/src/core/geom/3d/{matrix → mat4}/MATRIX_4_IDENTITY.js +0 -0
  52. /package/src/core/geom/3d/{matrix → mat4}/MATRIX_4_IDENTITY.spec.js +0 -0
  53. /package/src/core/geom/3d/{matrix → mat4}/allocate_transform_m4.js +0 -0
  54. /package/src/core/geom/3d/{matrix → mat4}/m4_make_translation.js +0 -0
  55. /package/src/core/geom/3d/{matrix → mat4}/m4_multiply.js +0 -0
  56. /package/src/core/geom/3d/{matrix → mat4}/m4_multiply_alphatensor.js +0 -0
package/build/meep.cjs CHANGED
@@ -1980,10 +1980,15 @@ function v3_length(x, y, z) {
1980
1980
  * @param {number} z1
1981
1981
  * @returns {number}
1982
1982
  */
1983
- function v3_angle_between(x0, y0, z0, x1, y1, z1) {
1983
+ function v3_angle_between(
1984
+ x0, y0, z0,
1985
+ x1, y1, z1
1986
+ ) {
1987
+
1984
1988
  const theta = v3_angle_cos_between(x0, y0, z0, x1, y1, z1);
1985
1989
 
1986
1990
  return Math.acos(theta);
1991
+
1987
1992
  }
1988
1993
 
1989
1994
  /**
@@ -1994,9 +1999,13 @@ function v3_angle_between(x0, y0, z0, x1, y1, z1) {
1994
1999
  * @param {number} x1
1995
2000
  * @param {number} y1
1996
2001
  * @param {number} z1
1997
- * @returns {number}
2002
+ * @returns {number} value between -1 and 1, cosine of the angle between vectors
1998
2003
  */
1999
- function v3_angle_cos_between(x0, y0, z0, x1, y1, z1){
2004
+ function v3_angle_cos_between(
2005
+ x0, y0, z0,
2006
+ x1, y1, z1
2007
+ ) {
2008
+
2000
2009
  const d = v3_dot(x0, y0, z0, x1, y1, z1);
2001
2010
 
2002
2011
  const magnitude_0 = v3_length(x0, y0, z0);
@@ -2006,10 +2015,12 @@ function v3_angle_cos_between(x0, y0, z0, x1, y1, z1){
2006
2015
 
2007
2016
  if (l === 0) {
2008
2017
  // collective magnitude is 0, provide arbitrary angle
2018
+ // avoid division by 0
2009
2019
  return 0;
2010
2020
  }
2011
2021
 
2012
2022
  return clamp$1(d / l, -1, 1);
2023
+
2013
2024
  }
2014
2025
 
2015
2026
  /**
@@ -2211,7 +2222,7 @@ let Vector3$1 = class Vector3 {
2211
2222
 
2212
2223
  /**
2213
2224
  *
2214
- * @param {number[]} array
2225
+ * @param {number[]|Float32Array} array
2215
2226
  * @param {number} offset
2216
2227
  */
2217
2228
  readFromArray(array, offset = 0) {
@@ -2224,7 +2235,7 @@ let Vector3$1 = class Vector3 {
2224
2235
 
2225
2236
  /**
2226
2237
  *
2227
- * @param {number[]} array
2238
+ * @param {number[]|Float32Array} array
2228
2239
  * @param {number} offset
2229
2240
  */
2230
2241
  writeToArray(array, offset = 0) {
@@ -4708,7 +4719,7 @@ let Quaternion$1 = class Quaternion {
4708
4719
  * @param {Quaternion} result
4709
4720
  * @param {Quaternion} from
4710
4721
  * @param {Quaternion} to
4711
- * @param {number} max_delta
4722
+ * @param {number} max_delta in radians
4712
4723
  */
4713
4724
  static rotateTowards(result, from, to, max_delta) {
4714
4725
 
@@ -72960,6 +72971,7 @@ class TransformAttachment {
72960
72971
 
72961
72972
  /**
72962
72973
  * transform relative to the attachment target
72974
+ * Think of it as "local transform"
72963
72975
  * @type {Transform}
72964
72976
  */
72965
72977
  transform = new Transform();
@@ -73573,7 +73585,10 @@ class UpdateContext {
73573
73585
  }
73574
73586
 
73575
73587
  update() {
73576
- this.transform.multiplyTransforms(this.parent_transform, this.attachment.transform);
73588
+ this.transform.multiplyTransforms(
73589
+ this.parent_transform,
73590
+ this.attachment.transform
73591
+ );
73577
73592
  }
73578
73593
 
73579
73594
  /**
@@ -73596,51 +73611,51 @@ class UpdateContext {
73596
73611
  link() {
73597
73612
  const t_parent = this.parent_transform;
73598
73613
 
73599
- t_parent.position.onChanged.add(this.update, this);
73600
- t_parent.rotation.onChanged.add(this.update, this);
73601
- t_parent.scale.onChanged.add(this.update, this);
73614
+ t_parent.subscribe(this.update, this);
73602
73615
 
73603
73616
  const t_attachment = this.attachment.transform;
73604
- t_attachment.position.onChanged.add(this.update,this);
73605
- t_attachment.rotation.onChanged.add(this.update,this);
73606
- t_attachment.scale.onChanged.add(this.update,this);
73617
+
73618
+ t_attachment.subscribe(this.update, this);
73607
73619
  }
73608
73620
 
73609
73621
  unlink() {
73610
73622
  const transform = this.parent_transform;
73611
73623
 
73612
- transform.position.onChanged.remove(this.update, this);
73613
- transform.rotation.onChanged.remove(this.update, this);
73614
- transform.scale.onChanged.remove(this.update, this);
73624
+ transform.unsubscribe(this.update, this);
73615
73625
 
73616
73626
  const t_attachment = this.attachment.transform;
73617
- t_attachment.position.onChanged.remove(this.update,this);
73618
- t_attachment.rotation.onChanged.remove(this.update,this);
73619
- t_attachment.scale.onChanged.remove(this.update,this);
73627
+
73628
+ t_attachment.unsubscribe(this.update, this);
73620
73629
  }
73621
73630
  }
73622
73631
 
73623
73632
  class TransformAttachmentSystem extends System {
73633
+
73634
+ /**
73635
+ *
73636
+ * @type {UpdateContext[]}
73637
+ * @private
73638
+ */
73639
+ __contexts = [];
73640
+
73641
+ /**
73642
+ *
73643
+ * @type {UpdateContext[]}
73644
+ * @private
73645
+ */
73646
+ __queue = [];
73647
+ __queue_size = 0;
73648
+ __queue_cursor = 0;
73649
+
73624
73650
  constructor() {
73625
73651
  super();
73626
73652
 
73627
73653
  this.dependencies = [TransformAttachment, Transform];
73628
73654
 
73629
- /**
73630
- *
73631
- * @type {UpdateContext[]}
73632
- * @private
73633
- */
73634
- this.__contexts = [];
73635
-
73636
- /**
73637
- *
73638
- * @type {UpdateContext[]}
73639
- * @private
73640
- */
73641
- this.__queue = [];
73642
- this.__queue_size = 0;
73643
- this.__queue_cursor = 0;
73655
+ this.components_used = [
73656
+ ResourceAccessSpecification.from(TransformAttachment, ResourceAccessKind.Read),
73657
+ ResourceAccessSpecification.from(Transform, ResourceAccessKind.Read | ResourceAccessKind.Write),
73658
+ ];
73644
73659
  }
73645
73660
 
73646
73661
  /**
@@ -73668,6 +73683,12 @@ class TransformAttachmentSystem extends System {
73668
73683
  this.__queue[this.__queue_size++] = ctx;
73669
73684
  }
73670
73685
 
73686
+ /**
73687
+ *
73688
+ * @param {number} entity
73689
+ * @returns {boolean}
73690
+ * @private
73691
+ */
73671
73692
  __dequeue_entity(entity) {
73672
73693
  for (let i = 0; i < this.__queue_size; i++) {
73673
73694
  const ctx = this.__queue[i];
@@ -73696,9 +73717,7 @@ class TransformAttachmentSystem extends System {
73696
73717
  ctx.entity = entity;
73697
73718
 
73698
73719
 
73699
- const ecd = this.entityManager.dataset;
73700
-
73701
- ctx.ecd = ecd;
73720
+ ctx.ecd = this.entityManager.dataset;
73702
73721
 
73703
73722
  if (ctx.bind_parent()) {
73704
73723
  this.__finalize_link(ctx);
@@ -73733,12 +73752,14 @@ class TransformAttachmentSystem extends System {
73733
73752
 
73734
73753
  update(timeDelta) {
73735
73754
  const step_count = min2(this.__queue_size, QUEUE_ITERATION_COUNT);
73755
+
73736
73756
  for (let i = 0; i < step_count; i++) {
73737
73757
  const index = this.__queue_cursor % this.__queue_size;
73738
73758
 
73739
73759
  const ctx = this.__queue[index];
73740
73760
 
73741
73761
  if (ctx.bind_parent()) {
73762
+ // parent obtained
73742
73763
  this.__finalize_link(ctx);
73743
73764
 
73744
73765
  this.__queue.splice(index, 1);
@@ -73748,6 +73769,7 @@ class TransformAttachmentSystem extends System {
73748
73769
  this.__queue_cursor++;
73749
73770
  }
73750
73771
  }
73772
+
73751
73773
  }
73752
73774
  }
73753
73775
 
@@ -77599,10 +77621,11 @@ class ShadedGeometrySystem extends System {
77599
77621
  }
77600
77622
 
77601
77623
  /**
77602
- *
77624
+ * Given an object and a value, find the first property with matching value and returns name of that property
77625
+ * Useful for working with ENUM-like objects
77603
77626
  * @param {Object<T>} object
77604
77627
  * @param {T} value
77605
- * @returns {string|undefined}
77628
+ * @returns {string|undefined} name of the property, or undefined if property not found
77606
77629
  */
77607
77630
  function objectKeyByValue(object, value) {
77608
77631
  for (let i in object) {
@@ -79210,46 +79233,6 @@ Stats.Panel = function ( name, fg, bg ) {
79210
79233
 
79211
79234
  };
79212
79235
 
79213
- /**
79214
- *
79215
- * @param {number} ax0
79216
- * @param {number} ay0
79217
- * @param {number} ax1
79218
- * @param {number} ay1
79219
- * @param {number} bx0
79220
- * @param {number} by0
79221
- * @param {number} bx1
79222
- * @param {number} by1
79223
- * @param {AABB2} result
79224
- * @returns {boolean} true if overlap exists, false if no overlap
79225
- */
79226
- function aabb2_compute_overlap(
79227
- ax0, ay0, ax1, ay1,
79228
- bx0, by0, bx1, by1,
79229
- result
79230
- ) {
79231
-
79232
- const x0 = max2(ax0, bx0);
79233
- const x1 = min2(ax1, bx1);
79234
-
79235
- if (x0 >= x1) {
79236
- //no overlap
79237
- return false;
79238
- }
79239
-
79240
- const y0 = max2(ay0, by0);
79241
- const y1 = min2(ay1, by1);
79242
-
79243
- if (y0 >= y1) {
79244
- //no overlap
79245
- return false;
79246
- }
79247
-
79248
- result.set(x0, y0, x1, y1);
79249
-
79250
- return true;
79251
- }
79252
-
79253
79236
  /**
79254
79237
  *
79255
79238
  * Find intersection point between two line segments if they intersect at all
@@ -79334,6 +79317,46 @@ function line_segment_compute_line_segment_intersection_2d(
79334
79317
  return collision;
79335
79318
  }
79336
79319
 
79320
+ /**
79321
+ *
79322
+ * @param {number} ax0
79323
+ * @param {number} ay0
79324
+ * @param {number} ax1
79325
+ * @param {number} ay1
79326
+ * @param {number} bx0
79327
+ * @param {number} by0
79328
+ * @param {number} bx1
79329
+ * @param {number} by1
79330
+ * @param {AABB2} result
79331
+ * @returns {boolean} true if overlap exists, false if no overlap
79332
+ */
79333
+ function aabb2_compute_overlap(
79334
+ ax0, ay0, ax1, ay1,
79335
+ bx0, by0, bx1, by1,
79336
+ result
79337
+ ) {
79338
+
79339
+ const x0 = max2(ax0, bx0);
79340
+ const x1 = min2(ax1, bx1);
79341
+
79342
+ if (x0 >= x1) {
79343
+ //no overlap
79344
+ return false;
79345
+ }
79346
+
79347
+ const y0 = max2(ay0, by0);
79348
+ const y1 = min2(ay1, by1);
79349
+
79350
+ if (y0 >= y1) {
79351
+ //no overlap
79352
+ return false;
79353
+ }
79354
+
79355
+ result.set(x0, y0, x1, y1);
79356
+
79357
+ return true;
79358
+ }
79359
+
79337
79360
  /**
79338
79361
  * Created by Alex on 08/08/2016.
79339
79362
  * @copyright Alex Goldring 2016
@@ -79462,7 +79485,7 @@ class AABB2 {
79462
79485
  /**
79463
79486
  *
79464
79487
  * @param {AABB2} other
79465
- * @returns {number}
79488
+ * @returns {boolean}
79466
79489
  */
79467
79490
  overlapExists(other) {
79468
79491
  const ax0 = this.x0;
@@ -79489,6 +79512,7 @@ class AABB2 {
79489
79512
  _expandToFit(x0, y0, x1, y1) {
79490
79513
  this.x0 = min2(this.x0, x0);
79491
79514
  this.y0 = min2(this.y0, y0);
79515
+
79492
79516
  this.x1 = max2(this.x1, x1);
79493
79517
  this.y1 = max2(this.y1, y1);
79494
79518
  }
@@ -79499,21 +79523,8 @@ class AABB2 {
79499
79523
  * @param {number} y
79500
79524
  */
79501
79525
  _expandToFitPoint(x, y) {
79502
- if (x < this.x0) {
79503
- this.x0 = x;
79504
- }
79505
-
79506
- if (x > this.x1) {
79507
- this.x1 = x;
79508
- }
79509
-
79510
- if (y < this.y0) {
79511
- this.y0 = y;
79512
- }
79513
-
79514
- if (y > this.y1) {
79515
- this.y1 = y;
79516
- }
79526
+ // shortcut, use a 0-size box
79527
+ this._expandToFit(x, y, x, y);
79517
79528
  }
79518
79529
 
79519
79530
  /**
@@ -95323,23 +95334,38 @@ class Clock {
95323
95334
  * Created by Alex on 06/05/2015.
95324
95335
  */
95325
95336
 
95337
+ /**
95338
+ * Simulation tick generator
95339
+ * Dispatches "tick" every animation frame or "maxDelay" time, whichever happens to be soonest
95340
+ * This is essentially the timing bus that all the simulation systems subscribe to for their step advancement
95341
+ */
95326
95342
  class Ticker {
95327
95343
  /**
95328
95344
  * @readonly
95329
95345
  * @type {Clock}
95330
95346
  */
95331
95347
  clock = new Clock();
95348
+
95332
95349
  /**
95333
95350
  * @private
95334
95351
  * @type {boolean}
95335
95352
  */
95336
- isRunning = false;
95353
+ #isRunning = false;
95354
+
95337
95355
 
95338
95356
  /**
95339
- *
95340
- * @type {SignalHandler[]}
95357
+ * Dispatches time delta in seconds since last tick
95358
+ * @readonly
95359
+ * @type {Signal<number>}
95341
95360
  */
95342
- callbacks = [];
95361
+ onTick = new Signal();
95362
+
95363
+ /**
95364
+ * @deprecated
95365
+ */
95366
+ get callbacks() {
95367
+ throw new Error('deprecated, use onTick signal instead');
95368
+ }
95343
95369
 
95344
95370
  /**
95345
95371
  *
@@ -95350,78 +95376,43 @@ class Ticker {
95350
95376
  }
95351
95377
 
95352
95378
  /**
95353
- *
95379
+ * @deprecated use onTick signal directly instead
95354
95380
  * @param {function} callback
95355
95381
  * @param {*} [thisArg]
95356
95382
  */
95357
95383
  subscribe(callback, thisArg) {
95358
- const handler = new SignalHandler(callback, thisArg);
95359
-
95360
- this.callbacks.push(handler);
95384
+ this.onTick.add(callback, thisArg);
95361
95385
  }
95362
95386
 
95363
95387
  /**
95364
- *
95388
+ * @deprecated use onTick signal directly instead
95365
95389
  * @param {function} callback
95366
95390
  * @param {*} [thisArg]
95367
95391
  */
95368
95392
  unsubscribe(callback, thisArg) {
95369
-
95370
- const callbacks = this.callbacks;
95371
- const n = callbacks.length;
95372
- for (let i = 0; i < n; i++) {
95373
- const cb = callbacks[i];
95374
-
95375
- if (cb.handle === callback) {
95376
- if (thisArg !== undefined) {
95377
- if (thisArg === cb.context) {
95378
- callbacks.splice(i, 1);
95379
- return;
95380
- }
95381
- } else {
95382
- callbacks.splice(i, 1);
95383
- return;
95384
- }
95385
- }
95386
- }
95387
-
95393
+ this.onTick.remove(callback, thisArg);
95388
95394
  }
95389
95395
 
95390
95396
  /**
95391
95397
  *
95392
- * @param {number} maxTimeout
95398
+ * @param {number} [maxTimeout]
95393
95399
  */
95394
95400
  start({ maxTimeout = 100 } = {}) {
95395
95401
 
95396
-
95397
- const self = this;
95398
95402
  let timeout = null;
95399
95403
  let animationFrame = null;
95400
95404
 
95401
- this.isRunning = true;
95402
-
95403
- function update() {
95404
- if (self.isRunning) {
95405
-
95406
- const delta = self.clock.getDelta();
95407
-
95408
- const callbacks = self.callbacks;
95409
-
95410
- for (let i = 0; i < callbacks.length; i++) {
95411
- const callback = callbacks[i];
95412
-
95413
- try {
95414
- callback.handle.call(callback.context, delta);
95415
- } catch (e) {
95416
- }
95405
+ this.#isRunning = true;
95417
95406
 
95418
- }
95407
+ const update = () => {
95408
+ if (!this.#isRunning) {
95409
+ return;
95419
95410
  }
95420
- }
95421
95411
 
95422
- function cycle() {
95423
- update();
95424
- }
95412
+ const delta = this.clock.getDelta();
95413
+
95414
+ this.onTick.send1(delta);
95415
+ };
95425
95416
 
95426
95417
  function timeoutCallback() {
95427
95418
  cancelAnimationFrame(animationFrame);
@@ -95437,22 +95428,22 @@ class Ticker {
95437
95428
 
95438
95429
  function animate() {
95439
95430
  animationFrame = requestAnimationFrame(animationFrameCallback);
95440
- cycle();
95431
+ update();
95441
95432
  timeout = setTimeout(timeoutCallback, maxTimeout);
95442
95433
  }
95443
95434
 
95444
- self.clock.getDelta(); //purge delta
95445
- self.clock.start();
95435
+ this.clock.getDelta(); //purge delta
95436
+ this.clock.start();
95446
95437
 
95447
95438
  requestAnimationFrame(animationFrameCallback);
95448
95439
  }
95449
95440
 
95450
95441
  pause() {
95451
- this.isRunning = false;
95442
+ this.#isRunning = false;
95452
95443
  }
95453
95444
 
95454
95445
  resume() {
95455
- this.isRunning = true;
95446
+ this.#isRunning = true;
95456
95447
  }
95457
95448
  }
95458
95449
 
@@ -106077,76 +106068,6 @@ class QuadTreeNode extends AABB2 {
106077
106068
 
106078
106069
  }
106079
106070
 
106080
- /**
106081
- * Remove all rectangles that are fully contained within others
106082
- * @param {QuadTreeNode} boxes
106083
- */
106084
- function removeRedundantBoxes(boxes) {
106085
- const removals = [];
106086
-
106087
-
106088
- let datum;
106089
-
106090
- /**
106091
- *
106092
- * @param {QuadTreeDatum} intersection
106093
- */
106094
- function visitDatumIntersection(intersection) {
106095
- if (datum === intersection) {
106096
- //skip self
106097
- return;
106098
- }
106099
-
106100
- const ax0 = intersection.x0;
106101
- const ay0 = intersection.y0;
106102
- const ax1 = intersection.x1;
106103
- const ay1 = intersection.y1;
106104
-
106105
- const bx0 = datum.x0;
106106
- const by0 = datum.y0;
106107
- const bx1 = datum.x1;
106108
- const by1 = datum.y1;
106109
-
106110
- //question is now whether it is containment
106111
- if (ax0 >= bx0 && ax1 <= bx1 && ay0 >= by0 && ay1 <= by1) {
106112
- //b contains a
106113
- removals.push(intersection);
106114
- } else if (bx0 >= ax0 && bx1 <= ax1 && by0 >= ay0 && by1 <= ay1) {
106115
- //a contains b
106116
- removals.push(datum);
106117
-
106118
- //scheduled removal of the datum, prevent further traversal
106119
- return false;
106120
- }
106121
- }
106122
-
106123
- /**
106124
- *
106125
- * @param {QuadTreeNode} node
106126
- */
106127
- function visitTreeNode(node) {
106128
- const data = node.data;
106129
- const dataCount = data.length;
106130
-
106131
- for (let i = 0; i < dataCount; i++) {
106132
- /**
106133
- *
106134
- * @type {QuadTreeDatum}
106135
- */
106136
- datum = data[i];
106137
-
106138
- node.traverseRectangleIntersections(datum.x0, datum.y0, datum.x1, datum.y1, visitDatumIntersection);
106139
- }
106140
- }
106141
-
106142
- boxes.traversePreOrder(visitTreeNode);
106143
-
106144
- for (let i = 0; i < removals.length; i++) {
106145
- const removal = removals[i];
106146
- removal.disconnect();
106147
- }
106148
- }
106149
-
106150
106071
  /**
106151
106072
  *
106152
106073
  * @param {number} containerWidth
@@ -106382,6 +106303,81 @@ function packOneBox(box, free) {
106382
106303
  return true;
106383
106304
  }
106384
106305
 
106306
+ /**
106307
+ * Remove all rectangles that are fully contained within others
106308
+ * @param {QuadTreeNode} boxes
106309
+ */
106310
+ function removeRedundantBoxes(boxes) {
106311
+ const removals = [];
106312
+
106313
+
106314
+ let datum;
106315
+
106316
+ /**
106317
+ *
106318
+ * @param {QuadTreeDatum} intersection
106319
+ */
106320
+ function visitDatumIntersection(intersection) {
106321
+ if (datum === intersection) {
106322
+ //skip self
106323
+ return;
106324
+ }
106325
+
106326
+ const ax0 = intersection.x0;
106327
+ const ay0 = intersection.y0;
106328
+ const ax1 = intersection.x1;
106329
+ const ay1 = intersection.y1;
106330
+
106331
+ const bx0 = datum.x0;
106332
+ const by0 = datum.y0;
106333
+ const bx1 = datum.x1;
106334
+ const by1 = datum.y1;
106335
+
106336
+ //question is now whether it is containment
106337
+ if (ax0 >= bx0 && ax1 <= bx1 && ay0 >= by0 && ay1 <= by1) {
106338
+ //b contains a
106339
+ removals.push(intersection);
106340
+ } else if (bx0 >= ax0 && bx1 <= ax1 && by0 >= ay0 && by1 <= ay1) {
106341
+ //a contains b
106342
+ removals.push(datum);
106343
+
106344
+ //scheduled removal of the datum, prevent further traversal
106345
+ return false;
106346
+ }
106347
+ }
106348
+
106349
+ /**
106350
+ *
106351
+ * @param {QuadTreeNode} node
106352
+ */
106353
+ function visitTreeNode(node) {
106354
+ const data = node.data;
106355
+ const dataCount = data.length;
106356
+
106357
+ for (let i = 0; i < dataCount; i++) {
106358
+ /**
106359
+ *
106360
+ * @type {QuadTreeDatum}
106361
+ */
106362
+ datum = data[i];
106363
+
106364
+ node.traverseRectangleIntersections(datum.x0, datum.y0, datum.x1, datum.y1, visitDatumIntersection);
106365
+ }
106366
+ }
106367
+
106368
+ boxes.traversePreOrder(visitTreeNode);
106369
+
106370
+ for (let i = 0; i < removals.length; i++) {
106371
+ const removal = removals[i];
106372
+ removal.disconnect();
106373
+ }
106374
+ }
106375
+
106376
+ /**
106377
+ * Packs rectangles into a finite area, packer is incremental and supports both insertions and removals of rectangles
106378
+ * Implementation of "max rectangles" packing algorithm.
106379
+ * Useful for packing texture atlases
106380
+ */
106385
106381
  class MaxRectanglesPacker {
106386
106382
  /**
106387
106383
  *
@@ -106396,6 +106392,8 @@ class MaxRectanglesPacker {
106396
106392
  * @type {QuadTreeNode}
106397
106393
  */
106398
106394
  this.free = new QuadTreeNode(0, 0, width, height);
106395
+
106396
+ // initialize a with a free space occupying the entire area
106399
106397
  this.free.add(null, 0, 0, width, height);
106400
106398
 
106401
106399
  /**
@@ -106470,7 +106468,8 @@ class MaxRectanglesPacker {
106470
106468
  }
106471
106469
 
106472
106470
  /**
106473
- *
106471
+ * Tests whether a rectangle of given dimensions can be packed into remaining space
106472
+ * Essentially, if this method succeeds - insertion will succeed as well, and if it fails - insertion will fail too
106474
106473
  * @param {number} w
106475
106474
  * @param {number} h
106476
106475
  * @return {boolean}
@@ -106554,9 +106553,10 @@ class MaxRectanglesPacker {
106554
106553
  }
106555
106554
 
106556
106555
  /**
106557
- * Resize the packer canvas
106556
+ * Resize the packer canvas, may trigger repacking if new dimensions are smaller than the existing ones
106558
106557
  * @param {number} width
106559
106558
  * @param {number} height
106559
+ * @returns {boolean} false if packing fails after resize, true otherwise
106560
106560
  */
106561
106561
  resize(width, height) {
106562
106562
 
@@ -106569,18 +106569,20 @@ class MaxRectanglesPacker {
106569
106569
 
106570
106570
  if (oldWidth > width || oldHeight > height) {
106571
106571
  //canvas was made smaller in at least one dimension, re-pack is required
106572
- this.repack();
106573
- } else {
106574
- //canvas was enlarged, we can simply add new free areas
106575
- if (width > oldWidth) {
106576
- this.free.insertDatum(new QuadTreeDatum(oldWidth, 0, width, height));
106577
- }
106578
- if (height > oldHeight) {
106579
- this.free.insertDatum(new QuadTreeDatum(0, oldHeight, width, height));
106580
- }
106572
+ return this.repack();
106573
+ }
106574
+
106575
+ //canvas was enlarged, we can simply add new free areas
106576
+ if (width > oldWidth) {
106577
+ this.free.insertDatum(new QuadTreeDatum(oldWidth, 0, width, height));
106578
+ }
106579
+ if (height > oldHeight) {
106580
+ this.free.insertDatum(new QuadTreeDatum(0, oldHeight, width, height));
106581
106581
  }
106582
106582
 
106583
106583
  // assert.ok(this.validate());
106584
+
106585
+ return true;
106584
106586
  }
106585
106587
 
106586
106588
  validate() {