@2112-lab/central-plant 0.1.28 → 0.1.30
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/dist/bundle/index.js +1840 -2
- package/dist/cjs/pathfinder/src/ConnectorManager.js +321 -0
- package/dist/cjs/pathfinder/src/GridSystem.js +169 -0
- package/dist/cjs/pathfinder/src/PathManager.js +487 -0
- package/dist/cjs/pathfinder/src/SceneManager.js +232 -0
- package/dist/cjs/pathfinder/src/TreePathManager.js +217 -0
- package/dist/cjs/pathfinder/src/Vector3.js +108 -0
- package/dist/cjs/pathfinder/src/index.js +363 -0
- package/dist/cjs/src/managers/components/pathfindingManager.js +2 -2
- package/dist/esm/pathfinder/src/ConnectorManager.js +317 -0
- package/dist/esm/pathfinder/src/GridSystem.js +165 -0
- package/dist/esm/pathfinder/src/PathManager.js +483 -0
- package/dist/esm/pathfinder/src/SceneManager.js +228 -0
- package/dist/esm/pathfinder/src/TreePathManager.js +213 -0
- package/dist/esm/pathfinder/src/Vector3.js +104 -0
- package/dist/esm/pathfinder/src/index.js +359 -0
- package/dist/esm/src/managers/components/pathfindingManager.js +1 -1
- package/package.json +1 -2
package/dist/bundle/index.js
CHANGED
|
@@ -6,7 +6,6 @@ console.log("Loading Central Plant Utils Bundle...");
|
|
|
6
6
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
7
7
|
|
|
8
8
|
var THREE = require('three');
|
|
9
|
-
var pathfinder = require('@2112-lab/pathfinder');
|
|
10
9
|
|
|
11
10
|
function _interopNamespace(e) {
|
|
12
11
|
if (e && e.__esModule) return e;
|
|
@@ -17362,6 +17361,1845 @@ var KeyboardControlsManager = /*#__PURE__*/function () {
|
|
|
17362
17361
|
}]);
|
|
17363
17362
|
}();
|
|
17364
17363
|
|
|
17364
|
+
/**
|
|
17365
|
+
* A simple 3D vector class for internal use
|
|
17366
|
+
* @class Vector3
|
|
17367
|
+
*/
|
|
17368
|
+
var Vector3 = /*#__PURE__*/function () {
|
|
17369
|
+
/**
|
|
17370
|
+
* Create a new Vector3
|
|
17371
|
+
* @param {number} [x=0] - The x component
|
|
17372
|
+
* @param {number} [y=0] - The y component
|
|
17373
|
+
* @param {number} [z=0] - The z component
|
|
17374
|
+
*/
|
|
17375
|
+
function Vector3() {
|
|
17376
|
+
var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
17377
|
+
var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
17378
|
+
var z = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
17379
|
+
_classCallCheck(this, Vector3);
|
|
17380
|
+
this.x = x;
|
|
17381
|
+
this.y = y;
|
|
17382
|
+
this.z = z;
|
|
17383
|
+
}
|
|
17384
|
+
|
|
17385
|
+
/**
|
|
17386
|
+
* Create a copy of this vector
|
|
17387
|
+
* @returns {Vector3} A new vector with the same components
|
|
17388
|
+
*/
|
|
17389
|
+
return _createClass(Vector3, [{
|
|
17390
|
+
key: "clone",
|
|
17391
|
+
value: function clone() {
|
|
17392
|
+
return new Vector3(this.x, this.y, this.z);
|
|
17393
|
+
}
|
|
17394
|
+
|
|
17395
|
+
/**
|
|
17396
|
+
* Convert the vector to an array
|
|
17397
|
+
* @returns {Array<number>} Array representation [x, y, z]
|
|
17398
|
+
*/
|
|
17399
|
+
}, {
|
|
17400
|
+
key: "toArray",
|
|
17401
|
+
value: function toArray() {
|
|
17402
|
+
return [this.x, this.y, this.z];
|
|
17403
|
+
}
|
|
17404
|
+
|
|
17405
|
+
/**
|
|
17406
|
+
* Normalize this vector (make it unit length)
|
|
17407
|
+
* @returns {Vector3} This vector (for chaining)
|
|
17408
|
+
*/
|
|
17409
|
+
}, {
|
|
17410
|
+
key: "normalize",
|
|
17411
|
+
value: function normalize() {
|
|
17412
|
+
var length = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
|
|
17413
|
+
if (length > 0) {
|
|
17414
|
+
this.x /= length;
|
|
17415
|
+
this.y /= length;
|
|
17416
|
+
this.z /= length;
|
|
17417
|
+
}
|
|
17418
|
+
return this;
|
|
17419
|
+
}
|
|
17420
|
+
|
|
17421
|
+
/**
|
|
17422
|
+
* Subtract another vector from this one
|
|
17423
|
+
* @param {Vector3} v - Vector to subtract
|
|
17424
|
+
* @returns {Vector3} This vector (for chaining)
|
|
17425
|
+
*/
|
|
17426
|
+
}, {
|
|
17427
|
+
key: "sub",
|
|
17428
|
+
value: function sub(v) {
|
|
17429
|
+
this.x -= v.x;
|
|
17430
|
+
this.y -= v.y;
|
|
17431
|
+
this.z -= v.z;
|
|
17432
|
+
return this;
|
|
17433
|
+
}
|
|
17434
|
+
|
|
17435
|
+
/**
|
|
17436
|
+
* Multiply this vector by a scalar value
|
|
17437
|
+
* @param {number} scalar - The scalar value to multiply by
|
|
17438
|
+
* @returns {Vector3} This vector (for chaining)
|
|
17439
|
+
*/
|
|
17440
|
+
}, {
|
|
17441
|
+
key: "multiplyScalar",
|
|
17442
|
+
value: function multiplyScalar(scalar) {
|
|
17443
|
+
this.x *= scalar;
|
|
17444
|
+
this.y *= scalar;
|
|
17445
|
+
this.z *= scalar;
|
|
17446
|
+
return this;
|
|
17447
|
+
}
|
|
17448
|
+
|
|
17449
|
+
/**
|
|
17450
|
+
* Add another vector to this one
|
|
17451
|
+
* @param {Vector3} v - Vector to add
|
|
17452
|
+
* @returns {Vector3} This vector (for chaining)
|
|
17453
|
+
*/
|
|
17454
|
+
}, {
|
|
17455
|
+
key: "add",
|
|
17456
|
+
value: function add(v) {
|
|
17457
|
+
this.x += v.x;
|
|
17458
|
+
this.y += v.y;
|
|
17459
|
+
this.z += v.z;
|
|
17460
|
+
return this;
|
|
17461
|
+
}
|
|
17462
|
+
}]);
|
|
17463
|
+
}();
|
|
17464
|
+
|
|
17465
|
+
/**
|
|
17466
|
+
* Manages scene operations including object finding, position calculations, and hierarchy traversal
|
|
17467
|
+
*/
|
|
17468
|
+
var SceneManager = /*#__PURE__*/function () {
|
|
17469
|
+
/**
|
|
17470
|
+
* Create a new SceneManager instance
|
|
17471
|
+
* @param {Object} scene - The scene configuration object
|
|
17472
|
+
*/
|
|
17473
|
+
function SceneManager(scene) {
|
|
17474
|
+
_classCallCheck(this, SceneManager);
|
|
17475
|
+
this.scene = scene;
|
|
17476
|
+
}
|
|
17477
|
+
|
|
17478
|
+
/**
|
|
17479
|
+
* Get the root scene object
|
|
17480
|
+
* @returns {Object} The root scene object
|
|
17481
|
+
*/
|
|
17482
|
+
return _createClass(SceneManager, [{
|
|
17483
|
+
key: "getRoot",
|
|
17484
|
+
value: function getRoot() {
|
|
17485
|
+
return this.scene.object;
|
|
17486
|
+
}
|
|
17487
|
+
|
|
17488
|
+
/**
|
|
17489
|
+
* Get world position from worldBoundingBox center
|
|
17490
|
+
* @param {Object} object - Scene object
|
|
17491
|
+
* @returns {Vector3} World position
|
|
17492
|
+
*/
|
|
17493
|
+
}, {
|
|
17494
|
+
key: "getWorldPosition",
|
|
17495
|
+
value: function getWorldPosition(object) {
|
|
17496
|
+
var _object$userData;
|
|
17497
|
+
if (!((_object$userData = object.userData) !== null && _object$userData !== void 0 && _object$userData.worldBoundingBox)) {
|
|
17498
|
+
console.log("[DEBUG] Object ".concat(object.uuid, " has no worldBoundingBox in userData"));
|
|
17499
|
+
return new Vector3();
|
|
17500
|
+
}
|
|
17501
|
+
var _object$userData$worl = object.userData.worldBoundingBox,
|
|
17502
|
+
min = _object$userData$worl.min,
|
|
17503
|
+
max = _object$userData$worl.max;
|
|
17504
|
+
return new Vector3((min[0] + max[0]) / 2, (min[1] + max[1]) / 2, (min[2] + max[2]) / 2);
|
|
17505
|
+
}
|
|
17506
|
+
|
|
17507
|
+
/**
|
|
17508
|
+
* Get bounding box from worldBoundingBox in userData
|
|
17509
|
+
* @param {Object} object - Scene object
|
|
17510
|
+
* @returns {{min: Vector3, max: Vector3}|null} Bounding box or null if no worldBoundingBox
|
|
17511
|
+
*/
|
|
17512
|
+
}, {
|
|
17513
|
+
key: "getBoundingBox",
|
|
17514
|
+
value: function getBoundingBox(object) {
|
|
17515
|
+
var _object$userData2;
|
|
17516
|
+
if (!((_object$userData2 = object.userData) !== null && _object$userData2 !== void 0 && _object$userData2.worldBoundingBox)) {
|
|
17517
|
+
console.log("[DEBUG] Object ".concat(object.uuid, " has no worldBoundingBox in userData"));
|
|
17518
|
+
return null;
|
|
17519
|
+
}
|
|
17520
|
+
var _object$userData$worl2 = object.userData.worldBoundingBox,
|
|
17521
|
+
min = _object$userData$worl2.min,
|
|
17522
|
+
max = _object$userData$worl2.max;
|
|
17523
|
+
return {
|
|
17524
|
+
min: new Vector3(min[0], min[1], min[2]),
|
|
17525
|
+
max: new Vector3(max[0], max[1], max[2])
|
|
17526
|
+
};
|
|
17527
|
+
}
|
|
17528
|
+
|
|
17529
|
+
/**
|
|
17530
|
+
* Find an object by UUID in the scene hierarchy
|
|
17531
|
+
* @param {string} uuid - UUID to search for
|
|
17532
|
+
* @returns {Object|null} Found object or null
|
|
17533
|
+
*/
|
|
17534
|
+
}, {
|
|
17535
|
+
key: "findObjectByUUID",
|
|
17536
|
+
value: function findObjectByUUID(uuid) {
|
|
17537
|
+
return this._findObjectByUUIDRecursive(this.getRoot(), uuid);
|
|
17538
|
+
}
|
|
17539
|
+
|
|
17540
|
+
/**
|
|
17541
|
+
* Recursive helper for findObjectByUUID
|
|
17542
|
+
* @private
|
|
17543
|
+
* @param {Object} node - Current node to search
|
|
17544
|
+
* @param {string} uuid - UUID to search for
|
|
17545
|
+
* @returns {Object|null} Found object or null
|
|
17546
|
+
*/
|
|
17547
|
+
}, {
|
|
17548
|
+
key: "_findObjectByUUIDRecursive",
|
|
17549
|
+
value: function _findObjectByUUIDRecursive(node, uuid) {
|
|
17550
|
+
if (node.uuid === uuid) {
|
|
17551
|
+
return node;
|
|
17552
|
+
}
|
|
17553
|
+
if (node.children) {
|
|
17554
|
+
var _iterator = _createForOfIteratorHelper(node.children),
|
|
17555
|
+
_step;
|
|
17556
|
+
try {
|
|
17557
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
17558
|
+
var child = _step.value;
|
|
17559
|
+
var found = this._findObjectByUUIDRecursive(child, uuid);
|
|
17560
|
+
if (found) return found;
|
|
17561
|
+
}
|
|
17562
|
+
} catch (err) {
|
|
17563
|
+
_iterator.e(err);
|
|
17564
|
+
} finally {
|
|
17565
|
+
_iterator.f();
|
|
17566
|
+
}
|
|
17567
|
+
}
|
|
17568
|
+
return null;
|
|
17569
|
+
}
|
|
17570
|
+
|
|
17571
|
+
/**
|
|
17572
|
+
* Find the parent object of a given object in the scene hierarchy
|
|
17573
|
+
* @param {Object} target - Target object to find parent for
|
|
17574
|
+
* @returns {Object|null} Parent object or null if not found or if parent is the scene
|
|
17575
|
+
*/
|
|
17576
|
+
}, {
|
|
17577
|
+
key: "findParentObject",
|
|
17578
|
+
value: function findParentObject(target) {
|
|
17579
|
+
if (target.userData && Array.isArray(target.userData.direction)) {
|
|
17580
|
+
return {
|
|
17581
|
+
isDirectionParent: true
|
|
17582
|
+
};
|
|
17583
|
+
}
|
|
17584
|
+
return this._findParentObjectRecursive(this.getRoot(), target);
|
|
17585
|
+
}
|
|
17586
|
+
|
|
17587
|
+
/**
|
|
17588
|
+
* Recursive helper for findParentObject
|
|
17589
|
+
* @private
|
|
17590
|
+
* @param {Object} root - Root object to search from
|
|
17591
|
+
* @param {Object} target - Target object to find parent for
|
|
17592
|
+
* @returns {Object|null} Parent object or null
|
|
17593
|
+
*/
|
|
17594
|
+
}, {
|
|
17595
|
+
key: "_findParentObjectRecursive",
|
|
17596
|
+
value: function _findParentObjectRecursive(root, target) {
|
|
17597
|
+
if (root.children) {
|
|
17598
|
+
var _iterator2 = _createForOfIteratorHelper(root.children),
|
|
17599
|
+
_step2;
|
|
17600
|
+
try {
|
|
17601
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
17602
|
+
var child = _step2.value;
|
|
17603
|
+
if (child.uuid === target.uuid) {
|
|
17604
|
+
if (root.type === 'Scene') {
|
|
17605
|
+
return null;
|
|
17606
|
+
}
|
|
17607
|
+
return root;
|
|
17608
|
+
}
|
|
17609
|
+
}
|
|
17610
|
+
} catch (err) {
|
|
17611
|
+
_iterator2.e(err);
|
|
17612
|
+
} finally {
|
|
17613
|
+
_iterator2.f();
|
|
17614
|
+
}
|
|
17615
|
+
var _iterator3 = _createForOfIteratorHelper(root.children),
|
|
17616
|
+
_step3;
|
|
17617
|
+
try {
|
|
17618
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
17619
|
+
var _child = _step3.value;
|
|
17620
|
+
var parent = this._findParentObjectRecursive(_child, target);
|
|
17621
|
+
if (parent) {
|
|
17622
|
+
return parent;
|
|
17623
|
+
}
|
|
17624
|
+
}
|
|
17625
|
+
} catch (err) {
|
|
17626
|
+
_iterator3.e(err);
|
|
17627
|
+
} finally {
|
|
17628
|
+
_iterator3.f();
|
|
17629
|
+
}
|
|
17630
|
+
}
|
|
17631
|
+
return null;
|
|
17632
|
+
}
|
|
17633
|
+
|
|
17634
|
+
/**
|
|
17635
|
+
* Check if a voxel is occupied by any mesh object
|
|
17636
|
+
* @param {string} voxelKey - Voxel key to check
|
|
17637
|
+
* @param {number} gridSize - Size of each grid cell
|
|
17638
|
+
* @returns {boolean} True if the voxel is occupied by a mesh object
|
|
17639
|
+
*/
|
|
17640
|
+
}, {
|
|
17641
|
+
key: "isVoxelOccupiedByMesh",
|
|
17642
|
+
value: function isVoxelOccupiedByMesh(voxelKey, gridSize) {
|
|
17643
|
+
var _voxelKey$split$map = voxelKey.split(',').map(Number),
|
|
17644
|
+
_voxelKey$split$map2 = _slicedToArray(_voxelKey$split$map, 3),
|
|
17645
|
+
x = _voxelKey$split$map2[0],
|
|
17646
|
+
y = _voxelKey$split$map2[1],
|
|
17647
|
+
z = _voxelKey$split$map2[2];
|
|
17648
|
+
var worldPos = new Vector3(x * gridSize, y * gridSize, z * gridSize);
|
|
17649
|
+
return this._checkObjectOccupancy(this.getRoot(), worldPos);
|
|
17650
|
+
}
|
|
17651
|
+
|
|
17652
|
+
/**
|
|
17653
|
+
* Recursive helper for isVoxelOccupiedByMesh
|
|
17654
|
+
* @private
|
|
17655
|
+
* @param {Object} object - Object to check
|
|
17656
|
+
* @param {Vector3} worldPos - World position to check
|
|
17657
|
+
* @returns {boolean} True if the position is occupied
|
|
17658
|
+
*/
|
|
17659
|
+
}, {
|
|
17660
|
+
key: "_checkObjectOccupancy",
|
|
17661
|
+
value: function _checkObjectOccupancy(object, worldPos) {
|
|
17662
|
+
if (object.type === 'Mesh') {
|
|
17663
|
+
var bbox = this.getBoundingBox(object);
|
|
17664
|
+
if (bbox) {
|
|
17665
|
+
if (worldPos.x >= bbox.min.x && worldPos.x <= bbox.max.x && worldPos.y >= bbox.min.y && worldPos.y <= bbox.max.y && worldPos.z >= bbox.min.z && worldPos.z <= bbox.max.z) {
|
|
17666
|
+
return true;
|
|
17667
|
+
}
|
|
17668
|
+
}
|
|
17669
|
+
}
|
|
17670
|
+
if (object.children) {
|
|
17671
|
+
var _iterator4 = _createForOfIteratorHelper(object.children),
|
|
17672
|
+
_step4;
|
|
17673
|
+
try {
|
|
17674
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
17675
|
+
var child = _step4.value;
|
|
17676
|
+
if (this._checkObjectOccupancy(child, worldPos)) return true;
|
|
17677
|
+
}
|
|
17678
|
+
} catch (err) {
|
|
17679
|
+
_iterator4.e(err);
|
|
17680
|
+
} finally {
|
|
17681
|
+
_iterator4.f();
|
|
17682
|
+
}
|
|
17683
|
+
}
|
|
17684
|
+
return false;
|
|
17685
|
+
}
|
|
17686
|
+
}]);
|
|
17687
|
+
}();
|
|
17688
|
+
|
|
17689
|
+
/**
|
|
17690
|
+
* Manages grid operations including voxel conversions, neighbor calculations, and distance metrics
|
|
17691
|
+
*/
|
|
17692
|
+
var GridSystem = /*#__PURE__*/function () {
|
|
17693
|
+
/**
|
|
17694
|
+
* Create a new GridSystem instance
|
|
17695
|
+
* @param {number} gridSize - Size of each grid cell in world units
|
|
17696
|
+
* @param {number} safetyMargin - Safety margin around obstacles in world units
|
|
17697
|
+
*/
|
|
17698
|
+
function GridSystem() {
|
|
17699
|
+
var gridSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.5;
|
|
17700
|
+
var safetyMargin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
17701
|
+
_classCallCheck(this, GridSystem);
|
|
17702
|
+
this.gridSize = gridSize;
|
|
17703
|
+
this.safetyMargin = safetyMargin;
|
|
17704
|
+
}
|
|
17705
|
+
|
|
17706
|
+
/**
|
|
17707
|
+
* Convert a position to a voxel key
|
|
17708
|
+
* @param {Vector3|Object} pos - Position to convert
|
|
17709
|
+
* @param {number} pos.x - X coordinate
|
|
17710
|
+
* @param {number} pos.y - Y coordinate
|
|
17711
|
+
* @param {number} pos.z - Z coordinate
|
|
17712
|
+
* @returns {string} Voxel key in format "x,y,z"
|
|
17713
|
+
*/
|
|
17714
|
+
return _createClass(GridSystem, [{
|
|
17715
|
+
key: "voxelKey",
|
|
17716
|
+
value: function voxelKey(pos) {
|
|
17717
|
+
return [Math.round(pos.x / this.gridSize), Math.round(pos.y / this.gridSize), Math.round(pos.z / this.gridSize)].join(',');
|
|
17718
|
+
}
|
|
17719
|
+
|
|
17720
|
+
/**
|
|
17721
|
+
* Convert a voxel key to a Vector3
|
|
17722
|
+
* @param {string} key - Voxel key
|
|
17723
|
+
* @returns {Vector3} Vector3 position
|
|
17724
|
+
*/
|
|
17725
|
+
}, {
|
|
17726
|
+
key: "voxelToVec3",
|
|
17727
|
+
value: function voxelToVec3(key) {
|
|
17728
|
+
var _key$split$map = key.split(',').map(Number),
|
|
17729
|
+
_key$split$map2 = _slicedToArray(_key$split$map, 3),
|
|
17730
|
+
x = _key$split$map2[0],
|
|
17731
|
+
y = _key$split$map2[1],
|
|
17732
|
+
z = _key$split$map2[2];
|
|
17733
|
+
return new Vector3(x * this.gridSize, y * this.gridSize, z * this.gridSize);
|
|
17734
|
+
}
|
|
17735
|
+
|
|
17736
|
+
/**
|
|
17737
|
+
* Get neighboring voxels (axis-aligned)
|
|
17738
|
+
* @param {string} vox - Voxel key
|
|
17739
|
+
* @returns {string[]} Array of neighboring voxel keys
|
|
17740
|
+
*/
|
|
17741
|
+
}, {
|
|
17742
|
+
key: "getNeighbors",
|
|
17743
|
+
value: function getNeighbors(vox) {
|
|
17744
|
+
var _vox$split$map = vox.split(',').map(Number),
|
|
17745
|
+
_vox$split$map2 = _slicedToArray(_vox$split$map, 3),
|
|
17746
|
+
x = _vox$split$map2[0],
|
|
17747
|
+
y = _vox$split$map2[1],
|
|
17748
|
+
z = _vox$split$map2[2];
|
|
17749
|
+
return [[x + 1, y, z], [x - 1, y, z], [x, y + 1, z], [x, y - 1, z], [x, y, z + 1], [x, y, z - 1]].map(function (arr) {
|
|
17750
|
+
return arr.join(',');
|
|
17751
|
+
});
|
|
17752
|
+
}
|
|
17753
|
+
|
|
17754
|
+
/**
|
|
17755
|
+
* Calculate Manhattan distance between two voxels
|
|
17756
|
+
* @param {string} a - First voxel key
|
|
17757
|
+
* @param {string} b - Second voxel key
|
|
17758
|
+
* @returns {number} Manhattan distance
|
|
17759
|
+
*/
|
|
17760
|
+
}, {
|
|
17761
|
+
key: "manhattan",
|
|
17762
|
+
value: function manhattan(a, b) {
|
|
17763
|
+
var _a$split$map = a.split(',').map(Number),
|
|
17764
|
+
_a$split$map2 = _slicedToArray(_a$split$map, 3),
|
|
17765
|
+
ax = _a$split$map2[0],
|
|
17766
|
+
ay = _a$split$map2[1],
|
|
17767
|
+
az = _a$split$map2[2];
|
|
17768
|
+
var _b$split$map = b.split(',').map(Number),
|
|
17769
|
+
_b$split$map2 = _slicedToArray(_b$split$map, 3),
|
|
17770
|
+
bx = _b$split$map2[0],
|
|
17771
|
+
by = _b$split$map2[1],
|
|
17772
|
+
bz = _b$split$map2[2];
|
|
17773
|
+
return Math.abs(ax - bx) + Math.abs(ay - by) + Math.abs(az - bz);
|
|
17774
|
+
}
|
|
17775
|
+
|
|
17776
|
+
/**
|
|
17777
|
+
* Calculate the number of voxels needed for a given world distance
|
|
17778
|
+
* @param {number} worldDistance - Distance in world units
|
|
17779
|
+
* @returns {number} Number of voxels
|
|
17780
|
+
*/
|
|
17781
|
+
}, {
|
|
17782
|
+
key: "worldToVoxelDistance",
|
|
17783
|
+
value: function worldToVoxelDistance(worldDistance) {
|
|
17784
|
+
return Math.ceil(worldDistance / this.gridSize);
|
|
17785
|
+
}
|
|
17786
|
+
|
|
17787
|
+
/**
|
|
17788
|
+
* Calculate the world distance for a given number of voxels
|
|
17789
|
+
* @param {number} voxelCount - Number of voxels
|
|
17790
|
+
* @returns {number} Distance in world units
|
|
17791
|
+
*/
|
|
17792
|
+
}, {
|
|
17793
|
+
key: "voxelToWorldDistance",
|
|
17794
|
+
value: function voxelToWorldDistance(voxelCount) {
|
|
17795
|
+
return voxelCount * this.gridSize;
|
|
17796
|
+
}
|
|
17797
|
+
|
|
17798
|
+
/**
|
|
17799
|
+
* Get the safety margin in voxel units
|
|
17800
|
+
* @returns {number} Safety margin in voxels
|
|
17801
|
+
*/
|
|
17802
|
+
}, {
|
|
17803
|
+
key: "getSafetyMarginVoxels",
|
|
17804
|
+
value: function getSafetyMarginVoxels() {
|
|
17805
|
+
return this.worldToVoxelDistance(this.safetyMargin);
|
|
17806
|
+
}
|
|
17807
|
+
|
|
17808
|
+
/**
|
|
17809
|
+
* Check if a voxel is within the safety margin of a bounding box
|
|
17810
|
+
* @param {string} voxelKey - Voxel key to check
|
|
17811
|
+
* @param {Object} bbox - Bounding box
|
|
17812
|
+
* @param {Vector3} bbox.min - Minimum coordinates
|
|
17813
|
+
* @param {Vector3} bbox.max - Maximum coordinates
|
|
17814
|
+
* @returns {boolean} True if the voxel is within the safety margin
|
|
17815
|
+
*/
|
|
17816
|
+
}, {
|
|
17817
|
+
key: "isVoxelInSafetyMargin",
|
|
17818
|
+
value: function isVoxelInSafetyMargin(voxelKey, bbox) {
|
|
17819
|
+
var voxelPos = this.voxelToVec3(voxelKey);
|
|
17820
|
+
var margin = this.safetyMargin;
|
|
17821
|
+
return voxelPos.x >= bbox.min.x - margin && voxelPos.x <= bbox.max.x + margin && voxelPos.y >= bbox.min.y - margin && voxelPos.y <= bbox.max.y + margin && voxelPos.z >= bbox.min.z - margin && voxelPos.z <= bbox.max.z + margin;
|
|
17822
|
+
}
|
|
17823
|
+
|
|
17824
|
+
/**
|
|
17825
|
+
* Get all voxel keys within a bounding box plus safety margin
|
|
17826
|
+
* @param {Object} bbox - Bounding box
|
|
17827
|
+
* @param {Vector3} bbox.min - Minimum coordinates
|
|
17828
|
+
* @param {Vector3} bbox.max - Maximum coordinates
|
|
17829
|
+
* @returns {string[]} Array of voxel keys
|
|
17830
|
+
*/
|
|
17831
|
+
}, {
|
|
17832
|
+
key: "getVoxelsInBoundingBox",
|
|
17833
|
+
value: function getVoxelsInBoundingBox(bbox) {
|
|
17834
|
+
var margin = this.getSafetyMarginVoxels();
|
|
17835
|
+
var min = bbox.min;
|
|
17836
|
+
var max = bbox.max;
|
|
17837
|
+
var voxels = [];
|
|
17838
|
+
for (var x = Math.round(min.x / this.gridSize) - margin; x <= Math.round(max.x / this.gridSize) + margin; x++) {
|
|
17839
|
+
for (var y = Math.round(min.y / this.gridSize) - margin; y <= Math.round(max.y / this.gridSize) + margin; y++) {
|
|
17840
|
+
for (var z = Math.round(min.z / this.gridSize) - margin; z <= Math.round(max.z / this.gridSize) + margin; z++) {
|
|
17841
|
+
voxels.push("".concat(x, ",").concat(y, ",").concat(z));
|
|
17842
|
+
}
|
|
17843
|
+
}
|
|
17844
|
+
}
|
|
17845
|
+
return voxels;
|
|
17846
|
+
}
|
|
17847
|
+
}]);
|
|
17848
|
+
}();
|
|
17849
|
+
|
|
17850
|
+
/**
|
|
17851
|
+
* Manages connector-related operations for the pathfinding system
|
|
17852
|
+
* @class ConnectorManager
|
|
17853
|
+
*/
|
|
17854
|
+
var ConnectorManager = /*#__PURE__*/function () {
|
|
17855
|
+
/**
|
|
17856
|
+
* Create a new ConnectorManager instance
|
|
17857
|
+
* @param {Object} config - The configuration object
|
|
17858
|
+
* @param {Array<Object>} config.connections - Array of connections between objects
|
|
17859
|
+
* @param {string} config.connections[].from - UUID of the source object
|
|
17860
|
+
* @param {string} config.connections[].to - UUID of the target object
|
|
17861
|
+
* @param {number} minSegmentLength - Minimum length for straight pipe segments in world units
|
|
17862
|
+
* @param {SceneManager} sceneManager - Instance of SceneManager for scene operations
|
|
17863
|
+
* @param {GridSystem} gridSystem - Instance of GridSystem for grid operations
|
|
17864
|
+
*/
|
|
17865
|
+
function ConnectorManager(config, minSegmentLength, sceneManager, gridSystem) {
|
|
17866
|
+
_classCallCheck(this, ConnectorManager);
|
|
17867
|
+
this.config = config;
|
|
17868
|
+
this.MIN_SEGMENT_LENGTH = minSegmentLength;
|
|
17869
|
+
this.sceneManager = sceneManager;
|
|
17870
|
+
this.gridSystem = gridSystem;
|
|
17871
|
+
}
|
|
17872
|
+
|
|
17873
|
+
/**
|
|
17874
|
+
* Check if an object is a connector by checking if it's mentioned in connections
|
|
17875
|
+
* @param {Object} object - Scene object
|
|
17876
|
+
* @returns {boolean} True if the object is a connector
|
|
17877
|
+
*/
|
|
17878
|
+
return _createClass(ConnectorManager, [{
|
|
17879
|
+
key: "isConnector",
|
|
17880
|
+
value: function isConnector(object) {
|
|
17881
|
+
if (!this.config.connections) return false;
|
|
17882
|
+
|
|
17883
|
+
// Check if the object's UUID appears in any connection
|
|
17884
|
+
return this.config.connections.some(function (conn) {
|
|
17885
|
+
return conn.from === object.uuid || conn.to === object.uuid;
|
|
17886
|
+
});
|
|
17887
|
+
}
|
|
17888
|
+
|
|
17889
|
+
/**
|
|
17890
|
+
* Calculate direction vector for a connector
|
|
17891
|
+
* @param {Object} connector - Connector object
|
|
17892
|
+
* @returns {Vector3|null} Direction vector or null if no parent or direction
|
|
17893
|
+
*/
|
|
17894
|
+
}, {
|
|
17895
|
+
key: "getConnectorDirection",
|
|
17896
|
+
value: function getConnectorDirection(connector) {
|
|
17897
|
+
// First check if direction is directly specified in userData
|
|
17898
|
+
if (connector.userData && Array.isArray(connector.userData.direction)) {
|
|
17899
|
+
var _connector$userData$d = _slicedToArray(connector.userData.direction, 3),
|
|
17900
|
+
x = _connector$userData$d[0],
|
|
17901
|
+
y = _connector$userData$d[1],
|
|
17902
|
+
z = _connector$userData$d[2];
|
|
17903
|
+
return new Vector3(x, y, z);
|
|
17904
|
+
}
|
|
17905
|
+
|
|
17906
|
+
// If no direction in userData and no parent, return null
|
|
17907
|
+
if (!connector.parent) {
|
|
17908
|
+
return null;
|
|
17909
|
+
}
|
|
17910
|
+
|
|
17911
|
+
// For backward compatibility, calculate direction from parent if no userData.direction
|
|
17912
|
+
console.log("[WARNING] No direction in userData for ".concat(connector.name || connector.uuid, " - using parent-based calculation (legacy mode)"));
|
|
17913
|
+
|
|
17914
|
+
// Get world position of the connector
|
|
17915
|
+
var connectorPos = this.sceneManager.getWorldPosition(connector);
|
|
17916
|
+
|
|
17917
|
+
// For the parent, use the center of its bounding box if available
|
|
17918
|
+
var parentPos;
|
|
17919
|
+
var parentBBox = this.sceneManager.getBoundingBox(connector.parent);
|
|
17920
|
+
if (parentBBox) {
|
|
17921
|
+
// Calculate the center of the parent's bounding box
|
|
17922
|
+
parentPos = new Vector3((parentBBox.min.x + parentBBox.max.x) / 2, (parentBBox.min.y + parentBBox.max.y) / 2, (parentBBox.min.z + parentBBox.max.z) / 2);
|
|
17923
|
+
} else {
|
|
17924
|
+
// Fall back to parent's position if bounding box is not available
|
|
17925
|
+
parentPos = this.sceneManager.getWorldPosition(connector.parent);
|
|
17926
|
+
}
|
|
17927
|
+
|
|
17928
|
+
// Calculate the direction vector from parent to connector
|
|
17929
|
+
var direction = new Vector3(connectorPos.x - parentPos.x, connectorPos.y - parentPos.y, connectorPos.z - parentPos.z).normalize();
|
|
17930
|
+
|
|
17931
|
+
// Enforce orthogonality by aligning with the dominant axis
|
|
17932
|
+
var absX = Math.abs(direction.x);
|
|
17933
|
+
var absY = Math.abs(direction.y);
|
|
17934
|
+
var absZ = Math.abs(direction.z);
|
|
17935
|
+
if (absX >= absY && absX >= absZ) {
|
|
17936
|
+
// X is dominant
|
|
17937
|
+
direction.y = 0;
|
|
17938
|
+
direction.z = 0;
|
|
17939
|
+
direction.x = Math.sign(direction.x);
|
|
17940
|
+
} else if (absY >= absX && absY >= absZ) {
|
|
17941
|
+
// Y is dominant
|
|
17942
|
+
direction.x = 0;
|
|
17943
|
+
direction.z = 0;
|
|
17944
|
+
direction.y = Math.sign(direction.y);
|
|
17945
|
+
} else {
|
|
17946
|
+
// Z is dominant
|
|
17947
|
+
direction.x = 0;
|
|
17948
|
+
direction.y = 0;
|
|
17949
|
+
direction.z = Math.sign(direction.z);
|
|
17950
|
+
}
|
|
17951
|
+
return direction;
|
|
17952
|
+
}
|
|
17953
|
+
|
|
17954
|
+
/**
|
|
17955
|
+
* Create a virtual segment for a connector
|
|
17956
|
+
* @param {Object} connector - Connector object
|
|
17957
|
+
* @param {Vector3} connectorPos - World position of the connector
|
|
17958
|
+
* @returns {Object|null} Virtual segment info or null if no parent
|
|
17959
|
+
*/
|
|
17960
|
+
}, {
|
|
17961
|
+
key: "createVirtualSegment",
|
|
17962
|
+
value: function createVirtualSegment(connector, connectorPos) {
|
|
17963
|
+
var direction = this.getConnectorDirection(connector);
|
|
17964
|
+
if (!direction) {
|
|
17965
|
+
return null;
|
|
17966
|
+
}
|
|
17967
|
+
|
|
17968
|
+
// Create a virtual segment starting from the connector position
|
|
17969
|
+
// and extending in the direction vector for MIN_SEGMENT_LENGTH
|
|
17970
|
+
var endPos = new Vector3(connectorPos.x + direction.x * this.MIN_SEGMENT_LENGTH, connectorPos.y + direction.y * this.MIN_SEGMENT_LENGTH, connectorPos.z + direction.z * this.MIN_SEGMENT_LENGTH);
|
|
17971
|
+
|
|
17972
|
+
// Convert to voxel keys
|
|
17973
|
+
var startKey = this.gridSystem.voxelKey(connectorPos);
|
|
17974
|
+
var endKey = this.gridSystem.voxelKey(endPos);
|
|
17975
|
+
return {
|
|
17976
|
+
startPos: connectorPos,
|
|
17977
|
+
endPos: endPos,
|
|
17978
|
+
direction: direction,
|
|
17979
|
+
startKey: startKey,
|
|
17980
|
+
endKey: endKey
|
|
17981
|
+
};
|
|
17982
|
+
}
|
|
17983
|
+
|
|
17984
|
+
/**
|
|
17985
|
+
* Process all connectors in the scene and mark their virtual segments as occupied
|
|
17986
|
+
* @param {Object} sceneRoot - Root scene object
|
|
17987
|
+
* @param {Set<string>} pathOccupied - Set of occupied voxel keys
|
|
17988
|
+
* @param {string} excludeUUID1 - UUID of first object to exclude
|
|
17989
|
+
* @param {string} excludeUUID2 - UUID of second object to exclude
|
|
17990
|
+
*/
|
|
17991
|
+
}, {
|
|
17992
|
+
key: "processConnectors",
|
|
17993
|
+
value: function processConnectors(sceneRoot, pathOccupied, excludeUUID1, excludeUUID2) {
|
|
17994
|
+
this._processConnectorsRecursive(sceneRoot, pathOccupied, excludeUUID1, excludeUUID2);
|
|
17995
|
+
}
|
|
17996
|
+
|
|
17997
|
+
/**
|
|
17998
|
+
* Recursive helper for processConnectors
|
|
17999
|
+
* @private
|
|
18000
|
+
* @param {Object} object - Current object to process
|
|
18001
|
+
* @param {Set<string>} pathOccupied - Set of occupied voxel keys
|
|
18002
|
+
* @param {string} excludeUUID1 - UUID of first object to exclude
|
|
18003
|
+
* @param {string} excludeUUID2 - UUID of second object to exclude
|
|
18004
|
+
*/
|
|
18005
|
+
}, {
|
|
18006
|
+
key: "_processConnectorsRecursive",
|
|
18007
|
+
value: function _processConnectorsRecursive(object, pathOccupied, excludeUUID1, excludeUUID2) {
|
|
18008
|
+
// Process current object if it's a mesh
|
|
18009
|
+
if (object.type === 'Mesh') {
|
|
18010
|
+
// Skip the excluded objects
|
|
18011
|
+
if (object.uuid === excludeUUID1 || object.uuid === excludeUUID2) {
|
|
18012
|
+
return;
|
|
18013
|
+
}
|
|
18014
|
+
var connectorPos = this.sceneManager.getWorldPosition(object);
|
|
18015
|
+
var segment = this.createVirtualSegment(object, connectorPos);
|
|
18016
|
+
if (segment) {
|
|
18017
|
+
this._markVirtualSegmentAsOccupied(segment, connectorPos, pathOccupied);
|
|
18018
|
+
}
|
|
18019
|
+
}
|
|
18020
|
+
|
|
18021
|
+
// Process children recursively
|
|
18022
|
+
if (object.children) {
|
|
18023
|
+
var _iterator = _createForOfIteratorHelper(object.children),
|
|
18024
|
+
_step;
|
|
18025
|
+
try {
|
|
18026
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
18027
|
+
var child = _step.value;
|
|
18028
|
+
this._processConnectorsRecursive(child, pathOccupied, excludeUUID1, excludeUUID2);
|
|
18029
|
+
}
|
|
18030
|
+
} catch (err) {
|
|
18031
|
+
_iterator.e(err);
|
|
18032
|
+
} finally {
|
|
18033
|
+
_iterator.f();
|
|
18034
|
+
}
|
|
18035
|
+
}
|
|
18036
|
+
}
|
|
18037
|
+
|
|
18038
|
+
/**
|
|
18039
|
+
* Mark voxels in a virtual segment as occupied
|
|
18040
|
+
* @private
|
|
18041
|
+
* @param {Object} segment - Virtual segment info
|
|
18042
|
+
* @param {Vector3} connectorPos - Position of the connector
|
|
18043
|
+
* @param {Set<string>} pathOccupied - Set of occupied voxel keys
|
|
18044
|
+
*/
|
|
18045
|
+
}, {
|
|
18046
|
+
key: "_markVirtualSegmentAsOccupied",
|
|
18047
|
+
value: function _markVirtualSegmentAsOccupied(segment, connectorPos, pathOccupied) {
|
|
18048
|
+
var direction = segment.direction;
|
|
18049
|
+
var distance = this.gridSystem.worldToVoxelDistance(this.MIN_SEGMENT_LENGTH + this.gridSystem.safetyMargin * 2);
|
|
18050
|
+
for (var i = 0; i <= distance; i++) {
|
|
18051
|
+
var x = Math.round(connectorPos.x / this.gridSystem.gridSize + direction.x * i);
|
|
18052
|
+
var y = Math.round(connectorPos.y / this.gridSystem.gridSize + direction.y * i);
|
|
18053
|
+
var z = Math.round(connectorPos.z / this.gridSystem.gridSize + direction.z * i);
|
|
18054
|
+
var key = "".concat(x, ",").concat(y, ",").concat(z);
|
|
18055
|
+
pathOccupied.add(key);
|
|
18056
|
+
}
|
|
18057
|
+
}
|
|
18058
|
+
|
|
18059
|
+
/**
|
|
18060
|
+
* Cluster connections by shared objects
|
|
18061
|
+
* @param {Array<Object>} connections - Array of connections between objects
|
|
18062
|
+
* @returns {Array<Object>} Array of clusters
|
|
18063
|
+
*/
|
|
18064
|
+
}, {
|
|
18065
|
+
key: "clusterConnections",
|
|
18066
|
+
value: function clusterConnections(connections) {
|
|
18067
|
+
var _this = this;
|
|
18068
|
+
var clusters = new Map(); // Map of object UUID to its cluster
|
|
18069
|
+
var clusterMap = new Map(); // Map of cluster ID to set of object UUIDs
|
|
18070
|
+
var nextClusterId = 0;
|
|
18071
|
+
|
|
18072
|
+
// First pass: create initial clusters for each object
|
|
18073
|
+
connections.forEach(function (conn) {
|
|
18074
|
+
var from = conn.from,
|
|
18075
|
+
to = conn.to;
|
|
18076
|
+
|
|
18077
|
+
// If neither object is in a cluster, create new cluster
|
|
18078
|
+
if (!clusters.has(from) && !clusters.has(to)) {
|
|
18079
|
+
var clusterId = nextClusterId++;
|
|
18080
|
+
clusters.set(from, clusterId);
|
|
18081
|
+
clusters.set(to, clusterId);
|
|
18082
|
+
clusterMap.set(clusterId, new Set([from, to]));
|
|
18083
|
+
}
|
|
18084
|
+
// If only 'from' is in a cluster, add 'to' to that cluster
|
|
18085
|
+
else if (clusters.has(from) && !clusters.has(to)) {
|
|
18086
|
+
var _clusterId = clusters.get(from);
|
|
18087
|
+
clusters.set(to, _clusterId);
|
|
18088
|
+
clusterMap.get(_clusterId).add(to);
|
|
18089
|
+
}
|
|
18090
|
+
// If only 'to' is in a cluster, add 'from' to that cluster
|
|
18091
|
+
else if (!clusters.has(from) && clusters.has(to)) {
|
|
18092
|
+
var _clusterId2 = clusters.get(to);
|
|
18093
|
+
clusters.set(from, _clusterId2);
|
|
18094
|
+
clusterMap.get(_clusterId2).add(from);
|
|
18095
|
+
}
|
|
18096
|
+
// If both are in different clusters, merge the clusters
|
|
18097
|
+
else if (clusters.has(from) && clusters.has(to)) {
|
|
18098
|
+
var fromCluster = clusters.get(from);
|
|
18099
|
+
var toCluster = clusters.get(to);
|
|
18100
|
+
if (fromCluster !== toCluster) {
|
|
18101
|
+
// Merge toCluster into fromCluster
|
|
18102
|
+
var toClusterObjects = clusterMap.get(toCluster);
|
|
18103
|
+
toClusterObjects.forEach(function (objId) {
|
|
18104
|
+
clusters.set(objId, fromCluster);
|
|
18105
|
+
clusterMap.get(fromCluster).add(objId);
|
|
18106
|
+
});
|
|
18107
|
+
clusterMap.delete(toCluster);
|
|
18108
|
+
}
|
|
18109
|
+
}
|
|
18110
|
+
});
|
|
18111
|
+
|
|
18112
|
+
// Convert clusters to array format
|
|
18113
|
+
var clustersArray = Array.from(clusterMap.entries()).map(function (_ref) {
|
|
18114
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
18115
|
+
clusterId = _ref2[0],
|
|
18116
|
+
objects = _ref2[1];
|
|
18117
|
+
return {
|
|
18118
|
+
clusterId: clusterId,
|
|
18119
|
+
objects: Array.from(objects)
|
|
18120
|
+
};
|
|
18121
|
+
});
|
|
18122
|
+
|
|
18123
|
+
// Filter out clusters containing objects with "GATEWAY" in their UUID
|
|
18124
|
+
var filteredClusters = clustersArray.filter(function (cluster) {
|
|
18125
|
+
return !cluster.objects.some(function (uuid) {
|
|
18126
|
+
return uuid.includes('GATEWAY');
|
|
18127
|
+
});
|
|
18128
|
+
});
|
|
18129
|
+
|
|
18130
|
+
// Enrich clusters with point and direction information
|
|
18131
|
+
filteredClusters.forEach(function (cluster) {
|
|
18132
|
+
cluster.objectPoints = cluster.objects.map(function (uuid) {
|
|
18133
|
+
var object = _this.sceneManager.findObjectByUUID(uuid);
|
|
18134
|
+
if (object && object.userData.worldBoundingBox) {
|
|
18135
|
+
var center = _this.sceneManager.getWorldPosition(object);
|
|
18136
|
+
return {
|
|
18137
|
+
uuid: uuid,
|
|
18138
|
+
point: center,
|
|
18139
|
+
direction: object.userData.direction ? _construct(Vector3, _toConsumableArray(object.userData.direction)) : null
|
|
18140
|
+
};
|
|
18141
|
+
}
|
|
18142
|
+
return null;
|
|
18143
|
+
}).filter(function (point) {
|
|
18144
|
+
return point !== null;
|
|
18145
|
+
});
|
|
18146
|
+
|
|
18147
|
+
// Add displaced points to each cluster
|
|
18148
|
+
cluster.displacedPoints = cluster.objectPoints.map(function (objPoint) {
|
|
18149
|
+
var displacedPoint = objPoint.direction ? objPoint.point.clone().add(objPoint.direction.multiplyScalar(0.5)) : objPoint.point.clone();
|
|
18150
|
+
return {
|
|
18151
|
+
uuid: objPoint.uuid,
|
|
18152
|
+
originalPoint: objPoint.point,
|
|
18153
|
+
displacedPoint: displacedPoint,
|
|
18154
|
+
direction: objPoint.direction
|
|
18155
|
+
};
|
|
18156
|
+
});
|
|
18157
|
+
});
|
|
18158
|
+
return filteredClusters;
|
|
18159
|
+
}
|
|
18160
|
+
}]);
|
|
18161
|
+
}();
|
|
18162
|
+
|
|
18163
|
+
/**
|
|
18164
|
+
* Manages path-related operations for the pathfinding system
|
|
18165
|
+
* @class PathManager
|
|
18166
|
+
*/
|
|
18167
|
+
var PathManager = /*#__PURE__*/function () {
|
|
18168
|
+
/**
|
|
18169
|
+
* Create a new PathManager instance
|
|
18170
|
+
* @param {SceneManager} sceneManager - Instance of SceneManager for scene operations
|
|
18171
|
+
* @param {GridSystem} gridSystem - Instance of GridSystem for grid operations
|
|
18172
|
+
* @param {ConnectorManager} connectorManager - Instance of ConnectorManager for connector operations
|
|
18173
|
+
* @param {number} minSegmentLength - Minimum length for straight pipe segments in world units
|
|
18174
|
+
* @param {number} astarTimeout - Timeout for A* pathfinding in milliseconds
|
|
18175
|
+
*/
|
|
18176
|
+
function PathManager(sceneManager, gridSystem, connectorManager, minSegmentLength, astarTimeout) {
|
|
18177
|
+
_classCallCheck(this, PathManager);
|
|
18178
|
+
this.sceneManager = sceneManager;
|
|
18179
|
+
this.gridSystem = gridSystem;
|
|
18180
|
+
this.connectorManager = connectorManager;
|
|
18181
|
+
this.MIN_SEGMENT_LENGTH = minSegmentLength;
|
|
18182
|
+
this.ASTAR_TIMEOUT = astarTimeout;
|
|
18183
|
+
}
|
|
18184
|
+
|
|
18185
|
+
/**
|
|
18186
|
+
* A* pathfinding algorithm
|
|
18187
|
+
* @private
|
|
18188
|
+
* @param {string} start - Start voxel key
|
|
18189
|
+
* @param {string} goal - Goal voxel key
|
|
18190
|
+
* @param {Set<string>} occupied - Set of occupied voxel keys
|
|
18191
|
+
* @returns {string[]|null} Path as array of voxel keys or null if no path found
|
|
18192
|
+
*/
|
|
18193
|
+
return _createClass(PathManager, [{
|
|
18194
|
+
key: "astar",
|
|
18195
|
+
value: function astar(start, goal, occupied) {
|
|
18196
|
+
var open = new Set([start]);
|
|
18197
|
+
var cameFrom = {};
|
|
18198
|
+
var gScore = _defineProperty({}, start, 0);
|
|
18199
|
+
var fScore = _defineProperty({}, start, this.gridSystem.manhattan(start, goal));
|
|
18200
|
+
|
|
18201
|
+
// Add timeout to prevent infinite loops
|
|
18202
|
+
var startTime = Date.now();
|
|
18203
|
+
while (open.size > 0) {
|
|
18204
|
+
// Check for timeout
|
|
18205
|
+
if (Date.now() - startTime > this.ASTAR_TIMEOUT) {
|
|
18206
|
+
console.log('[Warning] Pathfinding timed out');
|
|
18207
|
+
return null;
|
|
18208
|
+
}
|
|
18209
|
+
|
|
18210
|
+
// Get node in open with lowest fScore
|
|
18211
|
+
var current = null;
|
|
18212
|
+
var minF = Infinity;
|
|
18213
|
+
var _iterator = _createForOfIteratorHelper(open),
|
|
18214
|
+
_step;
|
|
18215
|
+
try {
|
|
18216
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
18217
|
+
var node = _step.value;
|
|
18218
|
+
if (fScore[node] < minF) {
|
|
18219
|
+
minF = fScore[node];
|
|
18220
|
+
current = node;
|
|
18221
|
+
}
|
|
18222
|
+
}
|
|
18223
|
+
} catch (err) {
|
|
18224
|
+
_iterator.e(err);
|
|
18225
|
+
} finally {
|
|
18226
|
+
_iterator.f();
|
|
18227
|
+
}
|
|
18228
|
+
if (current === goal) {
|
|
18229
|
+
// Reconstruct path
|
|
18230
|
+
var path = [current];
|
|
18231
|
+
while (cameFrom[current]) {
|
|
18232
|
+
current = cameFrom[current];
|
|
18233
|
+
path.unshift(current);
|
|
18234
|
+
}
|
|
18235
|
+
return path;
|
|
18236
|
+
}
|
|
18237
|
+
open.delete(current);
|
|
18238
|
+
var _iterator2 = _createForOfIteratorHelper(this.gridSystem.getNeighbors(current)),
|
|
18239
|
+
_step2;
|
|
18240
|
+
try {
|
|
18241
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
18242
|
+
var _gScore$neighbor;
|
|
18243
|
+
var neighbor = _step2.value;
|
|
18244
|
+
if (occupied.has(neighbor)) continue;
|
|
18245
|
+
var tentativeG = gScore[current] + 1;
|
|
18246
|
+
if (tentativeG < ((_gScore$neighbor = gScore[neighbor]) !== null && _gScore$neighbor !== void 0 ? _gScore$neighbor : Infinity)) {
|
|
18247
|
+
cameFrom[neighbor] = current;
|
|
18248
|
+
gScore[neighbor] = tentativeG;
|
|
18249
|
+
fScore[neighbor] = tentativeG + this.gridSystem.manhattan(neighbor, goal);
|
|
18250
|
+
open.add(neighbor);
|
|
18251
|
+
}
|
|
18252
|
+
}
|
|
18253
|
+
} catch (err) {
|
|
18254
|
+
_iterator2.e(err);
|
|
18255
|
+
} finally {
|
|
18256
|
+
_iterator2.f();
|
|
18257
|
+
}
|
|
18258
|
+
}
|
|
18259
|
+
return null;
|
|
18260
|
+
}
|
|
18261
|
+
|
|
18262
|
+
/**
|
|
18263
|
+
* Find a path respecting virtual segments
|
|
18264
|
+
* @private
|
|
18265
|
+
* @param {string} startKey - Start voxel key
|
|
18266
|
+
* @param {string} endKey - End voxel key
|
|
18267
|
+
* @param {Set<string>} occupied - Set of occupied voxel keys
|
|
18268
|
+
* @param {Object} startSegment - Virtual segment for start connector (optional)
|
|
18269
|
+
* @param {Object} endSegment - Virtual segment for end connector (optional)
|
|
18270
|
+
* @returns {string[]|null} Path as array of voxel keys or null if no path found
|
|
18271
|
+
*/
|
|
18272
|
+
}, {
|
|
18273
|
+
key: "findPathWithVirtualSegments",
|
|
18274
|
+
value: function findPathWithVirtualSegments(startKey, endKey, occupied, startSegment, endSegment) {
|
|
18275
|
+
// If we have virtual segments, we need to ensure the path starts and ends with them
|
|
18276
|
+
var actualStartKey = startKey;
|
|
18277
|
+
var actualEndKey = endKey;
|
|
18278
|
+
|
|
18279
|
+
// Create a copy of occupied set to avoid modifying the original
|
|
18280
|
+
var pathOccupied = new Set(occupied);
|
|
18281
|
+
|
|
18282
|
+
// If we have a start segment, use its end as the actual start for pathfinding
|
|
18283
|
+
// and mark the segment as occupied
|
|
18284
|
+
if (startSegment) {
|
|
18285
|
+
actualStartKey = startSegment.endKey;
|
|
18286
|
+
// Mark all voxels in the start segment as occupied
|
|
18287
|
+
var startPos = startSegment.startPos;
|
|
18288
|
+
var direction = startSegment.direction;
|
|
18289
|
+
var distance = this.gridSystem.worldToVoxelDistance(this.MIN_SEGMENT_LENGTH);
|
|
18290
|
+
// Note: we go up to distance-1 to exclude the connecting end point
|
|
18291
|
+
for (var i = 0; i < distance; i++) {
|
|
18292
|
+
var x = Math.round(startPos.x / this.gridSystem.gridSize + direction.x * i);
|
|
18293
|
+
var y = Math.round(startPos.y / this.gridSystem.gridSize + direction.y * i);
|
|
18294
|
+
var z = Math.round(startPos.z / this.gridSystem.gridSize + direction.z * i);
|
|
18295
|
+
var key = "".concat(x, ",").concat(y, ",").concat(z);
|
|
18296
|
+
pathOccupied.add(key);
|
|
18297
|
+
}
|
|
18298
|
+
}
|
|
18299
|
+
|
|
18300
|
+
// If we have an end segment, use its end as the actual end for pathfinding
|
|
18301
|
+
// and mark the segment as occupied
|
|
18302
|
+
if (endSegment) {
|
|
18303
|
+
actualEndKey = endSegment.endKey;
|
|
18304
|
+
// Mark all voxels in the end segment as occupied
|
|
18305
|
+
var endPos = endSegment.startPos;
|
|
18306
|
+
var _direction = endSegment.direction;
|
|
18307
|
+
var _distance = this.gridSystem.worldToVoxelDistance(this.MIN_SEGMENT_LENGTH);
|
|
18308
|
+
// Note: we go up to distance-1 to exclude the connecting end point
|
|
18309
|
+
for (var _i = 0; _i < _distance; _i++) {
|
|
18310
|
+
var _x = Math.round(endPos.x / this.gridSystem.gridSize + _direction.x * _i);
|
|
18311
|
+
var _y = Math.round(endPos.y / this.gridSystem.gridSize + _direction.y * _i);
|
|
18312
|
+
var _z = Math.round(endPos.z / this.gridSystem.gridSize + _direction.z * _i);
|
|
18313
|
+
var _key = "".concat(_x, ",").concat(_y, ",").concat(_z);
|
|
18314
|
+
pathOccupied.add(_key);
|
|
18315
|
+
}
|
|
18316
|
+
}
|
|
18317
|
+
|
|
18318
|
+
// Find a path between the actual start and end
|
|
18319
|
+
var middlePath = this.astar(actualStartKey, actualEndKey, pathOccupied);
|
|
18320
|
+
if (!middlePath) {
|
|
18321
|
+
return null;
|
|
18322
|
+
}
|
|
18323
|
+
|
|
18324
|
+
// Construct the full path
|
|
18325
|
+
var fullPath = [];
|
|
18326
|
+
|
|
18327
|
+
// Add the start segment if we have one
|
|
18328
|
+
if (startSegment) {
|
|
18329
|
+
fullPath.push(startSegment.startKey);
|
|
18330
|
+
}
|
|
18331
|
+
|
|
18332
|
+
// Add the middle path
|
|
18333
|
+
fullPath = fullPath.concat(middlePath);
|
|
18334
|
+
|
|
18335
|
+
// Add the end segment if we have one
|
|
18336
|
+
if (endSegment) {
|
|
18337
|
+
fullPath.push(endSegment.startKey);
|
|
18338
|
+
}
|
|
18339
|
+
return fullPath;
|
|
18340
|
+
}
|
|
18341
|
+
|
|
18342
|
+
/**
|
|
18343
|
+
* Mark all mesh objects' voxels as occupied in the scene
|
|
18344
|
+
* @private
|
|
18345
|
+
* @param {Object} sceneRoot - Root scene object
|
|
18346
|
+
* @returns {Object} Object containing occupied sets and maps
|
|
18347
|
+
*/
|
|
18348
|
+
}, {
|
|
18349
|
+
key: "markAllMeshesAsOccupiedVoxels",
|
|
18350
|
+
value: function markAllMeshesAsOccupiedVoxels(sceneRoot) {
|
|
18351
|
+
var _this = this;
|
|
18352
|
+
var occupied = new Set();
|
|
18353
|
+
var occupiedByUUID = new Map();
|
|
18354
|
+
var _processObject = function processObject(object) {
|
|
18355
|
+
// Skip non-mesh objects
|
|
18356
|
+
if (object.type !== 'Mesh') return;
|
|
18357
|
+
|
|
18358
|
+
// Get object's bounding box
|
|
18359
|
+
var bbox = _this.sceneManager.getBoundingBox(object);
|
|
18360
|
+
if (!bbox) return;
|
|
18361
|
+
|
|
18362
|
+
// Get all voxels in the bounding box plus safety margin
|
|
18363
|
+
var voxels = _this.gridSystem.getVoxelsInBoundingBox(bbox);
|
|
18364
|
+
|
|
18365
|
+
// Create a set for this object's occupied voxels
|
|
18366
|
+
var objectOccupied = new Set(voxels);
|
|
18367
|
+
|
|
18368
|
+
// Add all voxels to the global occupied set
|
|
18369
|
+
var _iterator3 = _createForOfIteratorHelper(voxels),
|
|
18370
|
+
_step3;
|
|
18371
|
+
try {
|
|
18372
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
18373
|
+
var key = _step3.value;
|
|
18374
|
+
occupied.add(key);
|
|
18375
|
+
}
|
|
18376
|
+
|
|
18377
|
+
// Store the object's occupied voxels in the map
|
|
18378
|
+
} catch (err) {
|
|
18379
|
+
_iterator3.e(err);
|
|
18380
|
+
} finally {
|
|
18381
|
+
_iterator3.f();
|
|
18382
|
+
}
|
|
18383
|
+
occupiedByUUID.set(object.uuid, objectOccupied);
|
|
18384
|
+
|
|
18385
|
+
// Process children recursively
|
|
18386
|
+
if (object.children) {
|
|
18387
|
+
var _iterator4 = _createForOfIteratorHelper(object.children),
|
|
18388
|
+
_step4;
|
|
18389
|
+
try {
|
|
18390
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
18391
|
+
var child = _step4.value;
|
|
18392
|
+
_processObject(child);
|
|
18393
|
+
}
|
|
18394
|
+
} catch (err) {
|
|
18395
|
+
_iterator4.e(err);
|
|
18396
|
+
} finally {
|
|
18397
|
+
_iterator4.f();
|
|
18398
|
+
}
|
|
18399
|
+
}
|
|
18400
|
+
};
|
|
18401
|
+
|
|
18402
|
+
// Process all objects in the scene's children array
|
|
18403
|
+
if (sceneRoot.children) {
|
|
18404
|
+
var _iterator5 = _createForOfIteratorHelper(sceneRoot.children),
|
|
18405
|
+
_step5;
|
|
18406
|
+
try {
|
|
18407
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
18408
|
+
var object = _step5.value;
|
|
18409
|
+
_processObject(object);
|
|
18410
|
+
}
|
|
18411
|
+
} catch (err) {
|
|
18412
|
+
_iterator5.e(err);
|
|
18413
|
+
} finally {
|
|
18414
|
+
_iterator5.f();
|
|
18415
|
+
}
|
|
18416
|
+
}
|
|
18417
|
+
return {
|
|
18418
|
+
occupied: occupied,
|
|
18419
|
+
occupiedByUUID: occupiedByUUID
|
|
18420
|
+
};
|
|
18421
|
+
}
|
|
18422
|
+
|
|
18423
|
+
/**
|
|
18424
|
+
* Process a single connection and find its path
|
|
18425
|
+
* @private
|
|
18426
|
+
* @param {Object} connection - Connection object
|
|
18427
|
+
* @param {Set<string>} occupied - Set of occupied voxel keys
|
|
18428
|
+
* @param {Map<string, Set<string>>} occupiedByUUID - Map of occupied voxels by UUID
|
|
18429
|
+
* @returns {Object|null} Path result object or null if connection is invalid
|
|
18430
|
+
*/
|
|
18431
|
+
}, {
|
|
18432
|
+
key: "processConnection",
|
|
18433
|
+
value: function processConnection(connection, occupied, occupiedByUUID) {
|
|
18434
|
+
var _this2 = this;
|
|
18435
|
+
var fromObject = this.sceneManager.findObjectByUUID(connection.from);
|
|
18436
|
+
var toObject = this.sceneManager.findObjectByUUID(connection.to);
|
|
18437
|
+
if (!fromObject || !toObject) {
|
|
18438
|
+
console.log("[ERROR] Could not find objects for connection ".concat(connection.from, " - ").concat(connection.to));
|
|
18439
|
+
return null;
|
|
18440
|
+
}
|
|
18441
|
+
|
|
18442
|
+
// Verify that both objects are meshes
|
|
18443
|
+
if (fromObject.type !== 'Mesh' || toObject.type !== 'Mesh') {
|
|
18444
|
+
console.log("[ERROR] Connection endpoints must be meshes: ".concat(fromObject.type, " - ").concat(toObject.type));
|
|
18445
|
+
return null;
|
|
18446
|
+
}
|
|
18447
|
+
|
|
18448
|
+
// Store the parent for each object to access later
|
|
18449
|
+
fromObject.parent = this.sceneManager.findParentObject(fromObject);
|
|
18450
|
+
toObject.parent = this.sceneManager.findParentObject(toObject);
|
|
18451
|
+
|
|
18452
|
+
// Get world positions for both objects
|
|
18453
|
+
var worldPos1 = this.sceneManager.getWorldPosition(fromObject);
|
|
18454
|
+
var worldPos2 = this.sceneManager.getWorldPosition(toObject);
|
|
18455
|
+
|
|
18456
|
+
// Create virtual segments for both connectors
|
|
18457
|
+
var startSegment = this.connectorManager.createVirtualSegment(fromObject, worldPos1);
|
|
18458
|
+
var endSegment = this.connectorManager.createVirtualSegment(toObject, worldPos2);
|
|
18459
|
+
|
|
18460
|
+
// Create a copy of occupied set for this path
|
|
18461
|
+
var pathOccupied = new Set(occupied);
|
|
18462
|
+
|
|
18463
|
+
// Debug copy 1: Initial state after copying from global occupied
|
|
18464
|
+
var debugOccupiedInitial = Array.from(pathOccupied).map(function (key) {
|
|
18465
|
+
return _this2.gridSystem.voxelToVec3(key);
|
|
18466
|
+
});
|
|
18467
|
+
|
|
18468
|
+
// Get bounding boxes for the two objects
|
|
18469
|
+
var fromBbox = this.sceneManager.getBoundingBox(fromObject);
|
|
18470
|
+
var toBbox = this.sceneManager.getBoundingBox(toObject);
|
|
18471
|
+
if (!fromBbox || !toBbox) return null;
|
|
18472
|
+
|
|
18473
|
+
// Clear voxels in bounding boxes only for objects that do NOT have virtual segments
|
|
18474
|
+
if (!startSegment) {
|
|
18475
|
+
var voxels = this.gridSystem.getVoxelsInBoundingBox(fromBbox);
|
|
18476
|
+
var _iterator6 = _createForOfIteratorHelper(voxels),
|
|
18477
|
+
_step6;
|
|
18478
|
+
try {
|
|
18479
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
18480
|
+
var key = _step6.value;
|
|
18481
|
+
pathOccupied.delete(key);
|
|
18482
|
+
}
|
|
18483
|
+
} catch (err) {
|
|
18484
|
+
_iterator6.e(err);
|
|
18485
|
+
} finally {
|
|
18486
|
+
_iterator6.f();
|
|
18487
|
+
}
|
|
18488
|
+
}
|
|
18489
|
+
if (!endSegment) {
|
|
18490
|
+
var _voxels = this.gridSystem.getVoxelsInBoundingBox(toBbox);
|
|
18491
|
+
var _iterator7 = _createForOfIteratorHelper(_voxels),
|
|
18492
|
+
_step7;
|
|
18493
|
+
try {
|
|
18494
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
18495
|
+
var _key2 = _step7.value;
|
|
18496
|
+
pathOccupied.delete(_key2);
|
|
18497
|
+
}
|
|
18498
|
+
} catch (err) {
|
|
18499
|
+
_iterator7.e(err);
|
|
18500
|
+
} finally {
|
|
18501
|
+
_iterator7.f();
|
|
18502
|
+
}
|
|
18503
|
+
}
|
|
18504
|
+
|
|
18505
|
+
// Also clear the voxels for the virtual segments if they exist
|
|
18506
|
+
if (startSegment) {
|
|
18507
|
+
var direction = startSegment.direction;
|
|
18508
|
+
var distance = this.gridSystem.worldToVoxelDistance(this.MIN_SEGMENT_LENGTH + this.gridSystem.safetyMargin * 2);
|
|
18509
|
+
for (var i = 0; i <= distance; i++) {
|
|
18510
|
+
var x = Math.round(worldPos1.x / this.gridSystem.gridSize + direction.x * i);
|
|
18511
|
+
var y = Math.round(worldPos1.y / this.gridSystem.gridSize + direction.y * i);
|
|
18512
|
+
var z = Math.round(worldPos1.z / this.gridSystem.gridSize + direction.z * i);
|
|
18513
|
+
pathOccupied.delete("".concat(x, ",").concat(y, ",").concat(z));
|
|
18514
|
+
}
|
|
18515
|
+
}
|
|
18516
|
+
if (endSegment) {
|
|
18517
|
+
var _direction2 = endSegment.direction;
|
|
18518
|
+
var _distance2 = this.gridSystem.worldToVoxelDistance(this.MIN_SEGMENT_LENGTH + this.gridSystem.safetyMargin * 2);
|
|
18519
|
+
for (var _i2 = 0; _i2 <= _distance2; _i2++) {
|
|
18520
|
+
var _x2 = Math.round(worldPos2.x / this.gridSystem.gridSize + _direction2.x * _i2);
|
|
18521
|
+
var _y2 = Math.round(worldPos2.y / this.gridSystem.gridSize + _direction2.y * _i2);
|
|
18522
|
+
var _z2 = Math.round(worldPos2.z / this.gridSystem.gridSize + _direction2.z * _i2);
|
|
18523
|
+
pathOccupied.delete("".concat(_x2, ",").concat(_y2, ",").concat(_z2));
|
|
18524
|
+
}
|
|
18525
|
+
}
|
|
18526
|
+
|
|
18527
|
+
// Process all other connectors in the scene
|
|
18528
|
+
this.connectorManager.processConnectors(this.sceneManager.getRoot(), pathOccupied, fromObject.uuid, toObject.uuid);
|
|
18529
|
+
|
|
18530
|
+
// Debug copy 3: After clearing virtual segments and adding back previous paths
|
|
18531
|
+
var debugOccupiedAfterSegments = Array.from(pathOccupied).map(function (key) {
|
|
18532
|
+
return _this2.gridSystem.voxelToVec3(key);
|
|
18533
|
+
});
|
|
18534
|
+
|
|
18535
|
+
// Get start and end voxel keys
|
|
18536
|
+
var startKey = this.gridSystem.voxelKey(worldPos1);
|
|
18537
|
+
var endKey = this.gridSystem.voxelKey(worldPos2);
|
|
18538
|
+
|
|
18539
|
+
// Find a path with virtual segments
|
|
18540
|
+
var pathKeys = this.findPathWithVirtualSegments(startKey, endKey, pathOccupied, startSegment, endSegment);
|
|
18541
|
+
var occupiedVoxels = Array.from(pathOccupied).map(function (key) {
|
|
18542
|
+
return _this2.gridSystem.voxelToVec3(key);
|
|
18543
|
+
});
|
|
18544
|
+
if (pathKeys) {
|
|
18545
|
+
var path = pathKeys.map(function (key) {
|
|
18546
|
+
return _this2.gridSystem.voxelToVec3(key);
|
|
18547
|
+
});
|
|
18548
|
+
|
|
18549
|
+
// Create a set for this path's occupied voxels
|
|
18550
|
+
var _pathOccupied = new Set();
|
|
18551
|
+
|
|
18552
|
+
// Mark path points as occupied for next routes
|
|
18553
|
+
var _iterator8 = _createForOfIteratorHelper(path),
|
|
18554
|
+
_step8;
|
|
18555
|
+
try {
|
|
18556
|
+
for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
|
|
18557
|
+
var p = _step8.value;
|
|
18558
|
+
var _key3 = this.gridSystem.voxelKey(p);
|
|
18559
|
+
occupied.add(_key3);
|
|
18560
|
+
_pathOccupied.add(_key3);
|
|
18561
|
+
}
|
|
18562
|
+
|
|
18563
|
+
// Store the path's occupied voxels in the map with a special key
|
|
18564
|
+
} catch (err) {
|
|
18565
|
+
_iterator8.e(err);
|
|
18566
|
+
} finally {
|
|
18567
|
+
_iterator8.f();
|
|
18568
|
+
}
|
|
18569
|
+
var pathKey = "path_".concat(connection.from, "_").concat(connection.to);
|
|
18570
|
+
occupiedByUUID.set(pathKey, _pathOccupied);
|
|
18571
|
+
return {
|
|
18572
|
+
from: connection.from,
|
|
18573
|
+
to: connection.to,
|
|
18574
|
+
path: path,
|
|
18575
|
+
occupied: occupiedVoxels,
|
|
18576
|
+
debug: {
|
|
18577
|
+
initial: debugOccupiedInitial,
|
|
18578
|
+
afterSegments: debugOccupiedAfterSegments
|
|
18579
|
+
},
|
|
18580
|
+
occupiedByUUID: occupiedByUUID // Include the map in the result
|
|
18581
|
+
};
|
|
18582
|
+
} else {
|
|
18583
|
+
console.log("[ERROR] No orthogonal path found for ".concat(connection.from, "-").concat(connection.to));
|
|
18584
|
+
return {
|
|
18585
|
+
from: connection.from,
|
|
18586
|
+
to: connection.to,
|
|
18587
|
+
path: null,
|
|
18588
|
+
start: worldPos1,
|
|
18589
|
+
end: worldPos2,
|
|
18590
|
+
occupied: occupiedVoxels,
|
|
18591
|
+
debug: {
|
|
18592
|
+
initial: debugOccupiedInitial,
|
|
18593
|
+
afterSegments: debugOccupiedAfterSegments
|
|
18594
|
+
},
|
|
18595
|
+
occupiedByUUID: occupiedByUUID // Include the map in the result
|
|
18596
|
+
};
|
|
18597
|
+
}
|
|
18598
|
+
}
|
|
18599
|
+
|
|
18600
|
+
/**
|
|
18601
|
+
* Find paths for all connections
|
|
18602
|
+
* @param {Array<Object>} connections - Array of connections to process
|
|
18603
|
+
* @returns {Array<Object>} Array of path results
|
|
18604
|
+
*/
|
|
18605
|
+
}, {
|
|
18606
|
+
key: "findPaths",
|
|
18607
|
+
value: function findPaths(connections) {
|
|
18608
|
+
console.log('[DEBUG] Starting findPaths()');
|
|
18609
|
+
|
|
18610
|
+
// Validate scene structure
|
|
18611
|
+
if (!this.sceneManager.getRoot()) {
|
|
18612
|
+
console.log('[ERROR] Invalid scene structure: missing scene root');
|
|
18613
|
+
return [];
|
|
18614
|
+
}
|
|
18615
|
+
|
|
18616
|
+
// Process all objects in the scene
|
|
18617
|
+
var _this$markAllMeshesAs = this.markAllMeshesAsOccupiedVoxels(this.sceneManager.getRoot()),
|
|
18618
|
+
occupied = _this$markAllMeshesAs.occupied,
|
|
18619
|
+
occupiedByUUID = _this$markAllMeshesAs.occupiedByUUID;
|
|
18620
|
+
var paths = [];
|
|
18621
|
+
|
|
18622
|
+
// For each connection in the config, find a path
|
|
18623
|
+
var _iterator9 = _createForOfIteratorHelper(connections),
|
|
18624
|
+
_step9;
|
|
18625
|
+
try {
|
|
18626
|
+
for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
|
|
18627
|
+
var connection = _step9.value;
|
|
18628
|
+
var result = this.processConnection(connection, occupied, occupiedByUUID);
|
|
18629
|
+
if (result) {
|
|
18630
|
+
paths.push(result);
|
|
18631
|
+
}
|
|
18632
|
+
}
|
|
18633
|
+
} catch (err) {
|
|
18634
|
+
_iterator9.e(err);
|
|
18635
|
+
} finally {
|
|
18636
|
+
_iterator9.f();
|
|
18637
|
+
}
|
|
18638
|
+
return paths;
|
|
18639
|
+
}
|
|
18640
|
+
}]);
|
|
18641
|
+
}();
|
|
18642
|
+
|
|
18643
|
+
/**
|
|
18644
|
+
* Manages tree path calculations and Minimum Spanning Tree (MST) operations
|
|
18645
|
+
* @class TreePathManager
|
|
18646
|
+
*/
|
|
18647
|
+
var TreePathManager = /*#__PURE__*/function () {
|
|
18648
|
+
function TreePathManager() {
|
|
18649
|
+
var gridSystem = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
|
18650
|
+
var sceneManager = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
18651
|
+
_classCallCheck(this, TreePathManager);
|
|
18652
|
+
this.gridSystem = gridSystem;
|
|
18653
|
+
this.sceneManager = sceneManager;
|
|
18654
|
+
}
|
|
18655
|
+
|
|
18656
|
+
/**
|
|
18657
|
+
* Calculate distance between two points
|
|
18658
|
+
* @param {Vector3} p1 - First point
|
|
18659
|
+
* @param {Vector3} p2 - Second point
|
|
18660
|
+
* @returns {number} Distance between points
|
|
18661
|
+
*/
|
|
18662
|
+
return _createClass(TreePathManager, [{
|
|
18663
|
+
key: "distance",
|
|
18664
|
+
value: function distance(p1, p2) {
|
|
18665
|
+
var dx = p2.x - p1.x;
|
|
18666
|
+
var dy = p2.y - p1.y;
|
|
18667
|
+
var dz = p2.z - p1.z;
|
|
18668
|
+
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
18669
|
+
}
|
|
18670
|
+
|
|
18671
|
+
/**
|
|
18672
|
+
* Find Minimum Spanning Tree using Prim's algorithm
|
|
18673
|
+
* @param {Array<Vector3>} points - Array of points to connect
|
|
18674
|
+
* @returns {Array<Array<number>>} Array of edges in the MST
|
|
18675
|
+
*/
|
|
18676
|
+
}, {
|
|
18677
|
+
key: "findMST",
|
|
18678
|
+
value: function findMST(points) {
|
|
18679
|
+
var n = points.length;
|
|
18680
|
+
var mst = [];
|
|
18681
|
+
var visited = new Set();
|
|
18682
|
+
|
|
18683
|
+
// Start with the first point
|
|
18684
|
+
visited.add(0);
|
|
18685
|
+
while (visited.size < n) {
|
|
18686
|
+
var minDist = Infinity;
|
|
18687
|
+
var minEdge = null;
|
|
18688
|
+
|
|
18689
|
+
// Find the minimum edge from visited to unvisited
|
|
18690
|
+
var _iterator = _createForOfIteratorHelper(visited),
|
|
18691
|
+
_step;
|
|
18692
|
+
try {
|
|
18693
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
18694
|
+
var i = _step.value;
|
|
18695
|
+
for (var j = 0; j < n; j++) {
|
|
18696
|
+
if (!visited.has(j)) {
|
|
18697
|
+
var dist = this.distance(points[i], points[j]);
|
|
18698
|
+
if (dist < minDist) {
|
|
18699
|
+
minDist = dist;
|
|
18700
|
+
minEdge = [i, j];
|
|
18701
|
+
}
|
|
18702
|
+
}
|
|
18703
|
+
}
|
|
18704
|
+
}
|
|
18705
|
+
} catch (err) {
|
|
18706
|
+
_iterator.e(err);
|
|
18707
|
+
} finally {
|
|
18708
|
+
_iterator.f();
|
|
18709
|
+
}
|
|
18710
|
+
if (minEdge) {
|
|
18711
|
+
mst.push(minEdge);
|
|
18712
|
+
visited.add(minEdge[1]);
|
|
18713
|
+
} else {
|
|
18714
|
+
break; // Break if we can't find any more edges
|
|
18715
|
+
}
|
|
18716
|
+
}
|
|
18717
|
+
return mst;
|
|
18718
|
+
}
|
|
18719
|
+
|
|
18720
|
+
/**
|
|
18721
|
+
* Find the nearest free voxel to a given position
|
|
18722
|
+
* @param {Vector3} position - Position to find free voxel near
|
|
18723
|
+
* @param {number} maxSearchRadius - Maximum search radius in voxel units
|
|
18724
|
+
* @returns {Vector3|null} Nearest free position or null if none found
|
|
18725
|
+
*/
|
|
18726
|
+
}, {
|
|
18727
|
+
key: "findNearestFreeVoxel",
|
|
18728
|
+
value: function findNearestFreeVoxel(position) {
|
|
18729
|
+
var maxSearchRadius = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5;
|
|
18730
|
+
if (!this.gridSystem || !this.sceneManager) {
|
|
18731
|
+
return position; // Return original position if systems not available
|
|
18732
|
+
}
|
|
18733
|
+
var originalVoxelKey = this.gridSystem.voxelKey(position);
|
|
18734
|
+
|
|
18735
|
+
// Check if original position is free
|
|
18736
|
+
if (!this.sceneManager.isVoxelOccupiedByMesh(originalVoxelKey, this.gridSystem.gridSize)) {
|
|
18737
|
+
return position;
|
|
18738
|
+
}
|
|
18739
|
+
|
|
18740
|
+
// Search in expanding rings around the position
|
|
18741
|
+
for (var radius = 1; radius <= maxSearchRadius; radius++) {
|
|
18742
|
+
var _originalVoxelKey$spl = originalVoxelKey.split(',').map(Number),
|
|
18743
|
+
_originalVoxelKey$spl2 = _slicedToArray(_originalVoxelKey$spl, 3),
|
|
18744
|
+
x = _originalVoxelKey$spl2[0],
|
|
18745
|
+
y = _originalVoxelKey$spl2[1],
|
|
18746
|
+
z = _originalVoxelKey$spl2[2];
|
|
18747
|
+
|
|
18748
|
+
// Generate all voxels at this radius
|
|
18749
|
+
var candidates = [];
|
|
18750
|
+
|
|
18751
|
+
// Generate all combinations of offsets at this radius
|
|
18752
|
+
for (var dx = -radius; dx <= radius; dx++) {
|
|
18753
|
+
for (var dy = -radius; dy <= radius; dy++) {
|
|
18754
|
+
for (var dz = -radius; dz <= radius; dz++) {
|
|
18755
|
+
// Only consider voxels exactly at this radius
|
|
18756
|
+
if (Math.abs(dx) + Math.abs(dy) + Math.abs(dz) === radius) {
|
|
18757
|
+
candidates.push([x + dx, y + dy, z + dz]);
|
|
18758
|
+
}
|
|
18759
|
+
}
|
|
18760
|
+
}
|
|
18761
|
+
}
|
|
18762
|
+
|
|
18763
|
+
// Check each candidate
|
|
18764
|
+
for (var _i = 0, _candidates = candidates; _i < _candidates.length; _i++) {
|
|
18765
|
+
var _candidates$_i = _slicedToArray(_candidates[_i], 3),
|
|
18766
|
+
cx = _candidates$_i[0],
|
|
18767
|
+
cy = _candidates$_i[1],
|
|
18768
|
+
cz = _candidates$_i[2];
|
|
18769
|
+
var candidateKey = "".concat(cx, ",").concat(cy, ",").concat(cz);
|
|
18770
|
+
if (!this.sceneManager.isVoxelOccupiedByMesh(candidateKey, this.gridSystem.gridSize)) {
|
|
18771
|
+
return this.gridSystem.voxelToVec3(candidateKey);
|
|
18772
|
+
}
|
|
18773
|
+
}
|
|
18774
|
+
}
|
|
18775
|
+
return null;
|
|
18776
|
+
}
|
|
18777
|
+
|
|
18778
|
+
/**
|
|
18779
|
+
* Find joint point
|
|
18780
|
+
* @param {Array<Vector3>} points - Array of points to connect
|
|
18781
|
+
* @returns {Vector3|null} Joint point or null if not possible
|
|
18782
|
+
*/
|
|
18783
|
+
}, {
|
|
18784
|
+
key: "findJointPoint",
|
|
18785
|
+
value: function findJointPoint(points) {
|
|
18786
|
+
if (points.length <= 2) {
|
|
18787
|
+
return null;
|
|
18788
|
+
}
|
|
18789
|
+
|
|
18790
|
+
// Find MST first
|
|
18791
|
+
var mst = this.findMST(points);
|
|
18792
|
+
if (mst.length === 0) {
|
|
18793
|
+
return null;
|
|
18794
|
+
}
|
|
18795
|
+
|
|
18796
|
+
// Find the best edge in MST
|
|
18797
|
+
var bestEdge = null;
|
|
18798
|
+
var maxScore = -1;
|
|
18799
|
+
mst.forEach(function (_ref, edgeIndex) {
|
|
18800
|
+
var _ref2 = _slicedToArray(_ref, 2),
|
|
18801
|
+
i = _ref2[0],
|
|
18802
|
+
j = _ref2[1];
|
|
18803
|
+
var pointA = points[i];
|
|
18804
|
+
var pointB = points[j];
|
|
18805
|
+
|
|
18806
|
+
// Calculate edge components
|
|
18807
|
+
var dx = Math.abs(pointB.x - pointA.x);
|
|
18808
|
+
var dy = Math.abs(pointB.y - pointA.y);
|
|
18809
|
+
var dz = Math.abs(pointB.z - pointA.z);
|
|
18810
|
+
|
|
18811
|
+
// Calculate total length
|
|
18812
|
+
var totalLength = dx + dy + dz;
|
|
18813
|
+
if (totalLength > 0) {
|
|
18814
|
+
// Calculate score
|
|
18815
|
+
// Higher score = more orthogonal (closer to being axis-aligned) relative to the total length of the edge
|
|
18816
|
+
var maxComponent = Math.max(dx, dy, dz);
|
|
18817
|
+
var score = maxComponent / totalLength / totalLength;
|
|
18818
|
+
|
|
18819
|
+
// Check if this edge has a better orthogonality score
|
|
18820
|
+
if (score > maxScore) {
|
|
18821
|
+
maxScore = score;
|
|
18822
|
+
bestEdge = [pointA, pointB];
|
|
18823
|
+
}
|
|
18824
|
+
}
|
|
18825
|
+
});
|
|
18826
|
+
if (!bestEdge) {
|
|
18827
|
+
return null;
|
|
18828
|
+
}
|
|
18829
|
+
|
|
18830
|
+
// Place joint point at the midpoint of the most orthogonal edge
|
|
18831
|
+
var jointPoint = new Vector3((bestEdge[0].x + bestEdge[1].x) * 0.5, (bestEdge[0].y + bestEdge[1].y) * 0.5, (bestEdge[0].z + bestEdge[1].z) * 0.5);
|
|
18832
|
+
|
|
18833
|
+
// Snap to 0.5 grid
|
|
18834
|
+
var snapToGrid = function snapToGrid(value) {
|
|
18835
|
+
return Math.round(value * 2) / 2;
|
|
18836
|
+
};
|
|
18837
|
+
jointPoint.x = snapToGrid(jointPoint.x);
|
|
18838
|
+
jointPoint.y = snapToGrid(jointPoint.y);
|
|
18839
|
+
jointPoint.z = snapToGrid(jointPoint.z);
|
|
18840
|
+
|
|
18841
|
+
// Check if the joint point is in an occupied voxel and move it if necessary
|
|
18842
|
+
var freeJointPoint = this.findNearestFreeVoxel(jointPoint);
|
|
18843
|
+
if (freeJointPoint) {
|
|
18844
|
+
return freeJointPoint;
|
|
18845
|
+
} else {
|
|
18846
|
+
return jointPoint; // Return original if no free position found
|
|
18847
|
+
}
|
|
18848
|
+
}
|
|
18849
|
+
}]);
|
|
18850
|
+
}();
|
|
18851
|
+
|
|
18852
|
+
/**
|
|
18853
|
+
* A 3D pathfinding system that finds orthogonal paths between objects
|
|
18854
|
+
* @class Pathfinder
|
|
18855
|
+
*/
|
|
18856
|
+
var Pathfinder = /*#__PURE__*/function () {
|
|
18857
|
+
/**
|
|
18858
|
+
* Create a new Pathfinding instance
|
|
18859
|
+
* @param {Object} [config] - Optional configuration object
|
|
18860
|
+
* @param {Object} [config.grid] - Grid system configuration
|
|
18861
|
+
* @param {number} [config.grid.size=0.5] - Size of each grid cell in world units
|
|
18862
|
+
* @param {number} [config.grid.safetyMargin=0] - Safety margin around obstacles in world units
|
|
18863
|
+
* @param {number} [config.grid.minSegmentLength=0.5] - Minimum length for straight pipe segments in world units
|
|
18864
|
+
* @param {number} [config.grid.timeout=1000] - Timeout for A* pathfinding in milliseconds
|
|
18865
|
+
*/
|
|
18866
|
+
function Pathfinder() {
|
|
18867
|
+
var _gridConfig$size, _gridConfig$safetyMar, _gridConfig$minSegmen, _gridConfig$timeout;
|
|
18868
|
+
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
18869
|
+
_classCallCheck(this, Pathfinder);
|
|
18870
|
+
this.config = config;
|
|
18871
|
+
|
|
18872
|
+
// Grid system settings with defaults
|
|
18873
|
+
var gridConfig = config.grid || {};
|
|
18874
|
+
this.gridSystem = new GridSystem((_gridConfig$size = gridConfig.size) !== null && _gridConfig$size !== void 0 ? _gridConfig$size : 0.5, (_gridConfig$safetyMar = gridConfig.safetyMargin) !== null && _gridConfig$safetyMar !== void 0 ? _gridConfig$safetyMar : 0);
|
|
18875
|
+
this.MIN_SEGMENT_LENGTH = (_gridConfig$minSegmen = gridConfig.minSegmentLength) !== null && _gridConfig$minSegmen !== void 0 ? _gridConfig$minSegmen : 0.5;
|
|
18876
|
+
this.ASTAR_TIMEOUT = (_gridConfig$timeout = gridConfig.timeout) !== null && _gridConfig$timeout !== void 0 ? _gridConfig$timeout : 1000;
|
|
18877
|
+
|
|
18878
|
+
// Initialize connector manager
|
|
18879
|
+
this.connectorManager = new ConnectorManager({
|
|
18880
|
+
grid: gridConfig
|
|
18881
|
+
},
|
|
18882
|
+
// Only pass grid config
|
|
18883
|
+
this.MIN_SEGMENT_LENGTH, null,
|
|
18884
|
+
// sceneManager will be set in findPaths
|
|
18885
|
+
this.gridSystem);
|
|
18886
|
+
|
|
18887
|
+
// Initialize path manager
|
|
18888
|
+
this.pathManager = new PathManager(null,
|
|
18889
|
+
// sceneManager will be set in findPaths
|
|
18890
|
+
this.gridSystem, this.connectorManager, this.MIN_SEGMENT_LENGTH, this.ASTAR_TIMEOUT);
|
|
18891
|
+
|
|
18892
|
+
// Initialize tree path manager
|
|
18893
|
+
this.treePathManager = new TreePathManager(this.gridSystem, null);
|
|
18894
|
+
}
|
|
18895
|
+
|
|
18896
|
+
/**
|
|
18897
|
+
* Find paths for all connections
|
|
18898
|
+
* @param {Object} scene - The scene configuration
|
|
18899
|
+
* @param {Object} scene.object - The scene object containing children
|
|
18900
|
+
* @param {string} scene.object.uuid - Unique identifier for the scene object
|
|
18901
|
+
* @param {string} scene.object.type - Type of the scene object (typically "Scene")
|
|
18902
|
+
* @param {Array<Object>} scene.object.children - Array of scene objects
|
|
18903
|
+
* @param {string} scene.object.children[].uuid - Unique identifier for the child object
|
|
18904
|
+
* @param {string} scene.object.children[].type - Type of the child object (must be "Mesh")
|
|
18905
|
+
* @param {Object} scene.object.children[].userData - User data for the child object
|
|
18906
|
+
* @param {Object} scene.object.children[].userData.worldBoundingBox - Bounding box data
|
|
18907
|
+
* @param {Array<number>} scene.object.children[].userData.worldBoundingBox.min - Minimum coordinates [x,y,z]
|
|
18908
|
+
* @param {Array<number>} scene.object.children[].userData.worldBoundingBox.max - Maximum coordinates [x,y,z]
|
|
18909
|
+
* @param {Array<number>} [scene.object.children[].userData.direction] - Optional direction vector [x,y,z]
|
|
18910
|
+
* @param {Array<Object>} connections - Array of connections between objects
|
|
18911
|
+
* @param {string} connections[].from - UUID of the source object
|
|
18912
|
+
* @param {string} connections[].to - UUID of the target object
|
|
18913
|
+
* @returns {Object} Result object containing paths, rewired connections, and gateways
|
|
18914
|
+
* @property {Array<Object>} paths - Array of path results
|
|
18915
|
+
* @property {string} paths[].from - Source object UUID
|
|
18916
|
+
* @property {string} paths[].to - Target object UUID
|
|
18917
|
+
* @property {Array<Vector3>|null} paths[].path - Array of path points or null if no path found
|
|
18918
|
+
* @property {Array<Vector3>} [paths[].occupied] - Array of occupied points
|
|
18919
|
+
* @property {Vector3} [paths[].start] - Start position (if no path found)
|
|
18920
|
+
* @property {Vector3} [paths[].end] - End position (if no path found)
|
|
18921
|
+
* @property {Array<Object>} rewiredConnections - Array of connections after gateway optimization
|
|
18922
|
+
* @property {string} rewiredConnections[].from - Source object UUID
|
|
18923
|
+
* @property {string} rewiredConnections[].to - Target object UUID
|
|
18924
|
+
* @property {Array<Object>} gateways - Array of gateway information
|
|
18925
|
+
* @property {string} gateways[].clusterId - ID of the cluster this gateway belongs to
|
|
18926
|
+
* @property {number} gateways[].id - Unique identifier for the gateway
|
|
18927
|
+
* @property {Vector3} gateways[].position - Position of the gateway in 3D space
|
|
18928
|
+
* @property {Object} gateways[].connections - Connection mapping information
|
|
18929
|
+
* @property {Array<Object>} gateways[].connections.removed - Array of original connections that were removed
|
|
18930
|
+
* @property {string} gateways[].connections.removed[].from - Source object UUID
|
|
18931
|
+
* @property {string} gateways[].connections.removed[].to - Target object UUID
|
|
18932
|
+
* @property {Array<Object>} gateways[].connections.added - Array of new connections that were added
|
|
18933
|
+
* @property {string} gateways[].connections.added[].from - Source object UUID
|
|
18934
|
+
* @property {string} gateways[].connections.added[].to - Target object UUID
|
|
18935
|
+
*/
|
|
18936
|
+
return _createClass(Pathfinder, [{
|
|
18937
|
+
key: "findPaths",
|
|
18938
|
+
value: function findPaths(scene, connections) {
|
|
18939
|
+
var _this = this;
|
|
18940
|
+
// Create scene manager with the provided scene
|
|
18941
|
+
var sceneManager = new SceneManager(scene);
|
|
18942
|
+
|
|
18943
|
+
// Update scene manager references
|
|
18944
|
+
this.connectorManager.sceneManager = sceneManager;
|
|
18945
|
+
this.pathManager.sceneManager = sceneManager;
|
|
18946
|
+
this.treePathManager.sceneManager = sceneManager;
|
|
18947
|
+
|
|
18948
|
+
// Cluster the connections
|
|
18949
|
+
var clusters = this.connectorManager.clusterConnections(connections);
|
|
18950
|
+
|
|
18951
|
+
// Filter clusters to only include those with more than 2 objects
|
|
18952
|
+
var filteredClusters = clusters.filter(function (cluster) {
|
|
18953
|
+
return cluster.objects.length > 2;
|
|
18954
|
+
});
|
|
18955
|
+
|
|
18956
|
+
// Calculate joint points for each cluster
|
|
18957
|
+
filteredClusters.forEach(function (cluster, index) {
|
|
18958
|
+
var points = cluster.displacedPoints.map(function (p) {
|
|
18959
|
+
return p.displacedPoint;
|
|
18960
|
+
});
|
|
18961
|
+
cluster.jointPoint = _this.treePathManager.findJointPoint(points);
|
|
18962
|
+
});
|
|
18963
|
+
var gatewayMap = new Map();
|
|
18964
|
+
filteredClusters.forEach(function (cluster) {
|
|
18965
|
+
if (cluster.jointPoint) {
|
|
18966
|
+
// Generate a shorter unique ID (8 characters)
|
|
18967
|
+
var uuid = crypto.randomUUID().replace(/-/g, '').substring(0, 8);
|
|
18968
|
+
var gatewayId = "Gateway-".concat(uuid);
|
|
18969
|
+
gatewayMap.set(cluster.clusterId, gatewayId);
|
|
18970
|
+
}
|
|
18971
|
+
});
|
|
18972
|
+
|
|
18973
|
+
// Create virtual gateway objects in the scene
|
|
18974
|
+
filteredClusters.forEach(function (cluster) {
|
|
18975
|
+
if (cluster.jointPoint) {
|
|
18976
|
+
var gatewayId = gatewayMap.get(cluster.clusterId);
|
|
18977
|
+
var gatewayObject = {
|
|
18978
|
+
uuid: gatewayId,
|
|
18979
|
+
type: 'Mesh',
|
|
18980
|
+
userData: {
|
|
18981
|
+
worldBoundingBox: {
|
|
18982
|
+
min: [cluster.jointPoint.x - 0.25, cluster.jointPoint.y - 0.25, cluster.jointPoint.z - 0.25],
|
|
18983
|
+
max: [cluster.jointPoint.x + 0.25, cluster.jointPoint.y + 0.25, cluster.jointPoint.z + 0.25]
|
|
18984
|
+
}
|
|
18985
|
+
}
|
|
18986
|
+
};
|
|
18987
|
+
scene.object.children.push(gatewayObject);
|
|
18988
|
+
}
|
|
18989
|
+
});
|
|
18990
|
+
|
|
18991
|
+
// Rewire connections through gateways
|
|
18992
|
+
var rewiredConnections = [];
|
|
18993
|
+
var connectionSet = new Set(); // Track unique connections
|
|
18994
|
+
var gatewayConnectionMappings = new Map(); // Track which original connections are replaced by which gateway connections
|
|
18995
|
+
|
|
18996
|
+
// Find direct connections (not part of clusters with >2 objects)
|
|
18997
|
+
var directConnections = connections.filter(function (conn) {
|
|
18998
|
+
var fromCluster = clusters.find(function (cluster) {
|
|
18999
|
+
return cluster.objects.includes(conn.from);
|
|
19000
|
+
});
|
|
19001
|
+
var toCluster = clusters.find(function (cluster) {
|
|
19002
|
+
return cluster.objects.includes(conn.to);
|
|
19003
|
+
});
|
|
19004
|
+
return !fromCluster || !toCluster || fromCluster.objects.length <= 2 || toCluster.objects.length <= 2;
|
|
19005
|
+
});
|
|
19006
|
+
|
|
19007
|
+
// First add direct connections
|
|
19008
|
+
directConnections.forEach(function (conn) {
|
|
19009
|
+
if (!connectionSet.has(JSON.stringify(conn))) {
|
|
19010
|
+
rewiredConnections.push(conn);
|
|
19011
|
+
connectionSet.add(JSON.stringify(conn));
|
|
19012
|
+
}
|
|
19013
|
+
});
|
|
19014
|
+
|
|
19015
|
+
// Then add gateway connections
|
|
19016
|
+
var gatewayConnections = [];
|
|
19017
|
+
connections.forEach(function (conn) {
|
|
19018
|
+
var _clusters$find, _clusters$find2;
|
|
19019
|
+
var fromCluster = (_clusters$find = clusters.find(function (cluster) {
|
|
19020
|
+
return cluster.objects.includes(conn.from);
|
|
19021
|
+
})) === null || _clusters$find === void 0 ? void 0 : _clusters$find.clusterId;
|
|
19022
|
+
var toCluster = (_clusters$find2 = clusters.find(function (cluster) {
|
|
19023
|
+
return cluster.objects.includes(conn.to);
|
|
19024
|
+
})) === null || _clusters$find2 === void 0 ? void 0 : _clusters$find2.clusterId;
|
|
19025
|
+
if (fromCluster !== undefined && toCluster !== undefined) {
|
|
19026
|
+
var fromGateway = gatewayMap.get(fromCluster);
|
|
19027
|
+
var toGateway = gatewayMap.get(toCluster);
|
|
19028
|
+
if (fromGateway !== undefined && toGateway !== undefined) {
|
|
19029
|
+
var fromGatewayId = fromGateway;
|
|
19030
|
+
var toGatewayId = toGateway;
|
|
19031
|
+
|
|
19032
|
+
// Track the original connection that will be replaced
|
|
19033
|
+
var originalConnection = {
|
|
19034
|
+
from: conn.from,
|
|
19035
|
+
to: conn.to
|
|
19036
|
+
};
|
|
19037
|
+
var addedConnections = [];
|
|
19038
|
+
|
|
19039
|
+
// If both objects are in the same cluster, connect through their gateway
|
|
19040
|
+
if (fromCluster === toCluster) {
|
|
19041
|
+
var conn1 = {
|
|
19042
|
+
from: conn.from,
|
|
19043
|
+
to: fromGatewayId
|
|
19044
|
+
};
|
|
19045
|
+
var conn2 = {
|
|
19046
|
+
from: fromGatewayId,
|
|
19047
|
+
to: conn.to
|
|
19048
|
+
};
|
|
19049
|
+
|
|
19050
|
+
// Only add if not already present
|
|
19051
|
+
if (!connectionSet.has(JSON.stringify(conn1))) {
|
|
19052
|
+
gatewayConnections.push(conn1);
|
|
19053
|
+
connectionSet.add(JSON.stringify(conn1));
|
|
19054
|
+
addedConnections.push(conn1);
|
|
19055
|
+
}
|
|
19056
|
+
if (!connectionSet.has(JSON.stringify(conn2))) {
|
|
19057
|
+
gatewayConnections.push(conn2);
|
|
19058
|
+
connectionSet.add(JSON.stringify(conn2));
|
|
19059
|
+
addedConnections.push(conn2);
|
|
19060
|
+
}
|
|
19061
|
+
} else {
|
|
19062
|
+
// If objects are in different clusters, connect through both gateways
|
|
19063
|
+
var _conn = {
|
|
19064
|
+
from: conn.from,
|
|
19065
|
+
to: fromGatewayId
|
|
19066
|
+
};
|
|
19067
|
+
var _conn2 = {
|
|
19068
|
+
from: fromGatewayId,
|
|
19069
|
+
to: toGatewayId
|
|
19070
|
+
};
|
|
19071
|
+
var conn3 = {
|
|
19072
|
+
from: toGatewayId,
|
|
19073
|
+
to: conn.to
|
|
19074
|
+
};
|
|
19075
|
+
|
|
19076
|
+
// Only add if not already present
|
|
19077
|
+
if (!connectionSet.has(JSON.stringify(_conn))) {
|
|
19078
|
+
gatewayConnections.push(_conn);
|
|
19079
|
+
connectionSet.add(JSON.stringify(_conn));
|
|
19080
|
+
addedConnections.push(_conn);
|
|
19081
|
+
}
|
|
19082
|
+
if (!connectionSet.has(JSON.stringify(_conn2))) {
|
|
19083
|
+
gatewayConnections.push(_conn2);
|
|
19084
|
+
connectionSet.add(JSON.stringify(_conn2));
|
|
19085
|
+
addedConnections.push(_conn2);
|
|
19086
|
+
}
|
|
19087
|
+
if (!connectionSet.has(JSON.stringify(conn3))) {
|
|
19088
|
+
gatewayConnections.push(conn3);
|
|
19089
|
+
connectionSet.add(JSON.stringify(conn3));
|
|
19090
|
+
addedConnections.push(conn3);
|
|
19091
|
+
}
|
|
19092
|
+
}
|
|
19093
|
+
|
|
19094
|
+
// Store the mapping for this connection
|
|
19095
|
+
if (addedConnections.length > 0) {
|
|
19096
|
+
gatewayConnectionMappings.set(JSON.stringify(originalConnection), {
|
|
19097
|
+
removed: [originalConnection],
|
|
19098
|
+
added: addedConnections
|
|
19099
|
+
});
|
|
19100
|
+
}
|
|
19101
|
+
}
|
|
19102
|
+
}
|
|
19103
|
+
});
|
|
19104
|
+
|
|
19105
|
+
// Sort gateway connections by edge length
|
|
19106
|
+
gatewayConnections.sort(function (a, b) {
|
|
19107
|
+
var objA1 = sceneManager.findObjectByUUID(a.from);
|
|
19108
|
+
var objA2 = sceneManager.findObjectByUUID(a.to);
|
|
19109
|
+
var objB1 = sceneManager.findObjectByUUID(b.from);
|
|
19110
|
+
var objB2 = sceneManager.findObjectByUUID(b.to);
|
|
19111
|
+
if (!objA1 || !objA2 || !objB1 || !objB2) return 0;
|
|
19112
|
+
var distA = _this.treePathManager.distance(sceneManager.getWorldPosition(objA1), sceneManager.getWorldPosition(objA2));
|
|
19113
|
+
var distB = _this.treePathManager.distance(sceneManager.getWorldPosition(objB1), sceneManager.getWorldPosition(objB2));
|
|
19114
|
+
return distA - distB;
|
|
19115
|
+
});
|
|
19116
|
+
|
|
19117
|
+
// Add sorted gateway connections to rewiredConnections
|
|
19118
|
+
rewiredConnections.push.apply(rewiredConnections, gatewayConnections);
|
|
19119
|
+
var paths = this.pathManager.findPaths(rewiredConnections || []);
|
|
19120
|
+
|
|
19121
|
+
// Aggregate connection mappings by gateway
|
|
19122
|
+
var gatewayConnectionsMap = new Map();
|
|
19123
|
+
|
|
19124
|
+
// Initialize connection mappings for each gateway
|
|
19125
|
+
Array.from(gatewayMap.entries()).forEach(function (_ref) {
|
|
19126
|
+
var _ref2 = _slicedToArray(_ref, 2);
|
|
19127
|
+
_ref2[0];
|
|
19128
|
+
var gatewayId = _ref2[1];
|
|
19129
|
+
gatewayConnectionsMap.set(gatewayId, {
|
|
19130
|
+
removed: [],
|
|
19131
|
+
added: []
|
|
19132
|
+
});
|
|
19133
|
+
});
|
|
19134
|
+
|
|
19135
|
+
// Populate connection mappings
|
|
19136
|
+
gatewayConnectionMappings.forEach(function (mapping, connectionKey) {
|
|
19137
|
+
var _clusters$find3, _clusters$find4;
|
|
19138
|
+
var originalConnection = JSON.parse(connectionKey);
|
|
19139
|
+
var fromCluster = (_clusters$find3 = clusters.find(function (cluster) {
|
|
19140
|
+
return cluster.objects.includes(originalConnection.from);
|
|
19141
|
+
})) === null || _clusters$find3 === void 0 ? void 0 : _clusters$find3.clusterId;
|
|
19142
|
+
var toCluster = (_clusters$find4 = clusters.find(function (cluster) {
|
|
19143
|
+
return cluster.objects.includes(originalConnection.to);
|
|
19144
|
+
})) === null || _clusters$find4 === void 0 ? void 0 : _clusters$find4.clusterId;
|
|
19145
|
+
if (fromCluster !== undefined && toCluster !== undefined) {
|
|
19146
|
+
var fromGateway = gatewayMap.get(fromCluster);
|
|
19147
|
+
var toGateway = gatewayMap.get(toCluster);
|
|
19148
|
+
if (fromGateway !== undefined && toGateway !== undefined) {
|
|
19149
|
+
// Add to both gateways if they're different
|
|
19150
|
+
if (fromGateway === toGateway) {
|
|
19151
|
+
var _gatewayConnections$a;
|
|
19152
|
+
// Same gateway
|
|
19153
|
+
var _gatewayConnections = gatewayConnectionsMap.get(fromGateway);
|
|
19154
|
+
_gatewayConnections.removed.push(originalConnection);
|
|
19155
|
+
(_gatewayConnections$a = _gatewayConnections.added).push.apply(_gatewayConnections$a, _toConsumableArray(mapping.added));
|
|
19156
|
+
} else {
|
|
19157
|
+
// Different gateways - split the connections
|
|
19158
|
+
var fromGatewayConnections = gatewayConnectionsMap.get(fromGateway);
|
|
19159
|
+
var toGatewayConnections = gatewayConnectionsMap.get(toGateway);
|
|
19160
|
+
|
|
19161
|
+
// Add the original connection to both gateways' removed list
|
|
19162
|
+
fromGatewayConnections.removed.push(originalConnection);
|
|
19163
|
+
toGatewayConnections.removed.push(originalConnection);
|
|
19164
|
+
|
|
19165
|
+
// Split added connections by gateway
|
|
19166
|
+
mapping.added.forEach(function (conn) {
|
|
19167
|
+
if (conn.from === originalConnection.from || conn.to === fromGateway) {
|
|
19168
|
+
fromGatewayConnections.added.push(conn);
|
|
19169
|
+
}
|
|
19170
|
+
if (conn.from === toGateway || conn.to === originalConnection.to) {
|
|
19171
|
+
toGatewayConnections.added.push(conn);
|
|
19172
|
+
}
|
|
19173
|
+
});
|
|
19174
|
+
}
|
|
19175
|
+
}
|
|
19176
|
+
}
|
|
19177
|
+
});
|
|
19178
|
+
return {
|
|
19179
|
+
paths: paths,
|
|
19180
|
+
rewiredConnections: rewiredConnections,
|
|
19181
|
+
gateways: Array.from(gatewayMap.entries()).map(function (_ref3) {
|
|
19182
|
+
var _clusters$find5;
|
|
19183
|
+
var _ref4 = _slicedToArray(_ref3, 2),
|
|
19184
|
+
clusterId = _ref4[0],
|
|
19185
|
+
gatewayId = _ref4[1];
|
|
19186
|
+
return {
|
|
19187
|
+
clusterId: clusterId,
|
|
19188
|
+
id: gatewayId,
|
|
19189
|
+
position: (_clusters$find5 = clusters.find(function (c) {
|
|
19190
|
+
return c.clusterId === clusterId;
|
|
19191
|
+
})) === null || _clusters$find5 === void 0 ? void 0 : _clusters$find5.jointPoint,
|
|
19192
|
+
connections: gatewayConnectionsMap.get(gatewayId) || {
|
|
19193
|
+
removed: [],
|
|
19194
|
+
added: []
|
|
19195
|
+
}
|
|
19196
|
+
};
|
|
19197
|
+
})
|
|
19198
|
+
};
|
|
19199
|
+
}
|
|
19200
|
+
}]);
|
|
19201
|
+
}();
|
|
19202
|
+
|
|
17365
19203
|
var PathfindingManager = /*#__PURE__*/function () {
|
|
17366
19204
|
function PathfindingManager(sceneViewer) {
|
|
17367
19205
|
_classCallCheck(this, PathfindingManager);
|
|
@@ -17492,7 +19330,7 @@ var PathfindingManager = /*#__PURE__*/function () {
|
|
|
17492
19330
|
return this.logPathfinderVersion(context);
|
|
17493
19331
|
case 1:
|
|
17494
19332
|
// Create pathfinder instance with configuration only
|
|
17495
|
-
this.pathfinder = new
|
|
19333
|
+
this.pathfinder = new Pathfinder(this.pathfinderConfig);
|
|
17496
19334
|
this.sceneViewer.pathfinder = this.pathfinder;
|
|
17497
19335
|
|
|
17498
19336
|
// Add debugging for pathfinder input
|