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