@2112-lab/central-plant 0.3.48 → 0.3.50
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 +836 -264
- package/dist/cjs/src/core/centralPlant.js +119 -6
- package/dist/cjs/src/index.js +2 -0
- package/dist/cjs/src/managers/controls/cameraControlsManager.js +353 -7
- package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +285 -145
- package/dist/cjs/src/managers/scene/sceneExportManager.js +19 -37
- package/dist/cjs/src/managers/scene/sceneInitializationManager.js +2 -1
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +35 -3
- package/dist/esm/src/core/centralPlant.js +99 -6
- package/dist/esm/src/index.js +1 -1
- package/dist/esm/src/managers/controls/cameraControlsManager.js +333 -9
- package/dist/esm/src/managers/pathfinding/pathfindingManager.js +286 -146
- package/dist/esm/src/managers/scene/sceneExportManager.js +20 -36
- package/dist/esm/src/managers/scene/sceneInitializationManager.js +2 -1
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +35 -3
- package/dist/esm/src/utils/boundingBoxUtils.js +1 -1
- package/package.json +1 -1
|
@@ -3,13 +3,34 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
|
|
6
|
-
require('three');
|
|
6
|
+
var THREE = require('three');
|
|
7
7
|
var baseDisposable = require('./baseDisposable.js');
|
|
8
8
|
var DisposalUtilities = require('../utils/DisposalUtilities.js');
|
|
9
9
|
var centralPlantInternals = require('./centralPlantInternals.js');
|
|
10
10
|
require('../rendering/modelPreloader.js');
|
|
11
11
|
var behaviorSceneUtils = require('../utils/behaviorSceneUtils.js');
|
|
12
12
|
var behaviorDispatch = require('../utils/behaviorDispatch.js');
|
|
13
|
+
var boundingBoxUtils = require('../utils/boundingBoxUtils.js');
|
|
14
|
+
|
|
15
|
+
function _interopNamespace(e) {
|
|
16
|
+
if (e && e.__esModule) return e;
|
|
17
|
+
var n = Object.create(null);
|
|
18
|
+
if (e) {
|
|
19
|
+
Object.keys(e).forEach(function (k) {
|
|
20
|
+
if (k !== 'default') {
|
|
21
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
22
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () { return e[k]; }
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
n["default"] = e;
|
|
30
|
+
return Object.freeze(n);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
13
34
|
|
|
14
35
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
15
36
|
// Flow-direction compatibility helper (module-level, no class dependency)
|
|
@@ -37,7 +58,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
37
58
|
* Initialize the CentralPlant manager
|
|
38
59
|
*
|
|
39
60
|
* @constructor
|
|
40
|
-
* @version 0.3.
|
|
61
|
+
* @version 0.3.50
|
|
41
62
|
* @updated 2025-10-22
|
|
42
63
|
*
|
|
43
64
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -1913,6 +1934,98 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
1913
1934
|
}
|
|
1914
1935
|
}
|
|
1915
1936
|
|
|
1937
|
+
/**
|
|
1938
|
+
* Get the world-space axis-aligned bounding box for a scene object.
|
|
1939
|
+
* @param {string|THREE.Object3D} objectOrId - The object's UUID/name, or the Three.js object itself
|
|
1940
|
+
* @param {Object} [options={}] - Bounding box options
|
|
1941
|
+
* @param {boolean} [options.filtered=true] - When true, exclude connector and io-device
|
|
1942
|
+
* subtrees so the box reflects the component body footprint. When false, the box
|
|
1943
|
+
* envelops all descendants (equivalent to THREE.Box3.setFromObject).
|
|
1944
|
+
* @param {string[]} [options.excludeTypes] - Override the userData.objectType values to
|
|
1945
|
+
* exclude (defaults to ['io-device', 'connector'] when filtered is true).
|
|
1946
|
+
* @returns {{min: {x,y,z}, max: {x,y,z}, size: {x,y,z}, center: {x,y,z}}|null}
|
|
1947
|
+
* The bounding box descriptor in world space, or null if the object can't be found
|
|
1948
|
+
* or has no geometry.
|
|
1949
|
+
* @description Computes a tight world-space bounding box for a component (or any scene
|
|
1950
|
+
* object). By default the component body is measured independently of its attached
|
|
1951
|
+
* connectors and io-devices, which is useful for layout and spacing operations.
|
|
1952
|
+
* @example
|
|
1953
|
+
* // Component body bounding box (excludes connectors / io-devices)
|
|
1954
|
+
* const bbox = centralPlant.getBoundingBox('PUMP-1');
|
|
1955
|
+
* console.log(bbox.size.x, bbox.size.y, bbox.size.z);
|
|
1956
|
+
*
|
|
1957
|
+
* @example
|
|
1958
|
+
* // Full bounding box including connectors and io-devices
|
|
1959
|
+
* const fullBox = centralPlant.getBoundingBox('PUMP-1', { filtered: false });
|
|
1960
|
+
*
|
|
1961
|
+
* @since 0.3.50
|
|
1962
|
+
*/
|
|
1963
|
+
}, {
|
|
1964
|
+
key: "getBoundingBox",
|
|
1965
|
+
value: function getBoundingBox(objectOrId) {
|
|
1966
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1967
|
+
if (!this.sceneViewer || !this.sceneViewer.scene) {
|
|
1968
|
+
console.warn('⚠️ getBoundingBox(): Scene viewer or scene not available');
|
|
1969
|
+
return null;
|
|
1970
|
+
}
|
|
1971
|
+
var _options$filtered = options.filtered,
|
|
1972
|
+
filtered = _options$filtered === void 0 ? true : _options$filtered,
|
|
1973
|
+
excludeTypes = options.excludeTypes;
|
|
1974
|
+
|
|
1975
|
+
// Resolve the target object
|
|
1976
|
+
var object = objectOrId;
|
|
1977
|
+
if (typeof objectOrId === 'string') {
|
|
1978
|
+
object = this.sceneViewer.scene.getObjectByProperty('uuid', objectOrId) || this.sceneViewer.scene.getObjectByProperty('name', objectOrId);
|
|
1979
|
+
if (!object) {
|
|
1980
|
+
// Fall back to a full traverse (matches translate's lookup by originalUuid)
|
|
1981
|
+
this.sceneViewer.scene.traverse(function (child) {
|
|
1982
|
+
var _child$userData2;
|
|
1983
|
+
if (!object && ((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.originalUuid) === objectOrId) {
|
|
1984
|
+
object = child;
|
|
1985
|
+
}
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
if (!object || typeof object.traverse !== 'function') {
|
|
1990
|
+
console.warn("\u26A0\uFE0F getBoundingBox(): Object '".concat(objectOrId, "' not found in scene"));
|
|
1991
|
+
return null;
|
|
1992
|
+
}
|
|
1993
|
+
try {
|
|
1994
|
+
var typesToExclude = filtered ? excludeTypes || ['io-device', 'connector'] : [];
|
|
1995
|
+
var box = boundingBoxUtils.computeFilteredBoundingBox(object, typesToExclude);
|
|
1996
|
+
if (box.isEmpty()) {
|
|
1997
|
+
return null;
|
|
1998
|
+
}
|
|
1999
|
+
var size = box.getSize(new THREE__namespace.Vector3());
|
|
2000
|
+
var center = box.getCenter(new THREE__namespace.Vector3());
|
|
2001
|
+
return {
|
|
2002
|
+
min: {
|
|
2003
|
+
x: box.min.x,
|
|
2004
|
+
y: box.min.y,
|
|
2005
|
+
z: box.min.z
|
|
2006
|
+
},
|
|
2007
|
+
max: {
|
|
2008
|
+
x: box.max.x,
|
|
2009
|
+
y: box.max.y,
|
|
2010
|
+
z: box.max.z
|
|
2011
|
+
},
|
|
2012
|
+
size: {
|
|
2013
|
+
x: size.x,
|
|
2014
|
+
y: size.y,
|
|
2015
|
+
z: size.z
|
|
2016
|
+
},
|
|
2017
|
+
center: {
|
|
2018
|
+
x: center.x,
|
|
2019
|
+
y: center.y,
|
|
2020
|
+
z: center.z
|
|
2021
|
+
}
|
|
2022
|
+
};
|
|
2023
|
+
} catch (error) {
|
|
2024
|
+
console.error('❌ getBoundingBox(): Error computing bounding box:', error);
|
|
2025
|
+
return null;
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
|
|
1916
2029
|
/**
|
|
1917
2030
|
* Get available component categories
|
|
1918
2031
|
* @returns {Array<Object>} Array of category objects with id, label, icon, and description
|
|
@@ -2147,8 +2260,8 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
2147
2260
|
var componentDictionary = ((_this$managers$compon = this.managers.componentDataManager) === null || _this$managers$compon === void 0 ? void 0 : _this$managers$compon.componentDictionary) || {};
|
|
2148
2261
|
var missingIds = [];
|
|
2149
2262
|
sceneData.scene.children.forEach(function (child) {
|
|
2150
|
-
var _child$
|
|
2151
|
-
var libraryId = (_child$
|
|
2263
|
+
var _child$userData3;
|
|
2264
|
+
var libraryId = (_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.libraryId;
|
|
2152
2265
|
if (libraryId && !componentDictionary[libraryId]) {
|
|
2153
2266
|
// Only add unique IDs
|
|
2154
2267
|
if (!missingIds.includes(libraryId)) {
|
|
@@ -2226,8 +2339,8 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
2226
2339
|
// If still not found, try finding by originalUuid in userData
|
|
2227
2340
|
if (!targetObject) {
|
|
2228
2341
|
this.sceneViewer.scene.traverse(function (child) {
|
|
2229
|
-
var _child$
|
|
2230
|
-
if (((_child$
|
|
2342
|
+
var _child$userData4;
|
|
2343
|
+
if (((_child$userData4 = child.userData) === null || _child$userData4 === void 0 ? void 0 : _child$userData4.originalUuid) === objectId) {
|
|
2231
2344
|
targetObject = child;
|
|
2232
2345
|
return;
|
|
2233
2346
|
}
|
package/dist/cjs/src/index.js
CHANGED
|
@@ -105,6 +105,8 @@ exports.ComponentDataManager = componentDataManager.ComponentDataManager;
|
|
|
105
105
|
exports.createTransformControls = transformControlsManager.createTransformControls;
|
|
106
106
|
exports.KeyboardControlsManager = keyboardControlsManager.KeyboardControlsManager;
|
|
107
107
|
exports.CameraControlsManager = cameraControlsManager.CameraControlsManager;
|
|
108
|
+
exports.DEFAULT_HOME_VIEW_DIRECTION = cameraControlsManager.DEFAULT_HOME_VIEW_DIRECTION;
|
|
109
|
+
exports.HOME_EMPTY_CAMERA_HEIGHT_ABOVE_GROUND = cameraControlsManager.HOME_EMPTY_CAMERA_HEIGHT_ABOVE_GROUND;
|
|
108
110
|
exports.ComponentDragManager = componentDragManager.ComponentDragManager;
|
|
109
111
|
exports.EnvironmentManager = environmentManager.EnvironmentManager;
|
|
110
112
|
exports.loadTextureSetAndCreateMaterial = textureConfig.loadTextureSetAndCreateMaterial;
|
|
@@ -3,12 +3,50 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHelpers.js');
|
|
6
|
+
var THREE = require('three');
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
function _interopNamespace(e) {
|
|
9
|
+
if (e && e.__esModule) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n["default"] = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
|
|
27
|
+
|
|
28
|
+
/** Default horizontal orbit bearing (target → camera, XY plane). */
|
|
29
|
+
var DEFAULT_HOME_VIEW_DIRECTION = {
|
|
30
|
+
x: -8,
|
|
31
|
+
y: -9,
|
|
32
|
+
z: 0
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/** Downward pitch from camera to the bottom-center look-at target (degrees). */
|
|
36
|
+
var HOME_DOWNWARD_PITCH_DEG = 13;
|
|
11
37
|
|
|
38
|
+
/** Minimum camera height above the bbox floor (world units). */
|
|
39
|
+
var HOME_CAMERA_MIN_HEIGHT = 0.8;
|
|
40
|
+
|
|
41
|
+
/** Ground plane height in world space (Z-up). */
|
|
42
|
+
var WORLD_GROUND_Z = 0;
|
|
43
|
+
|
|
44
|
+
/** Camera height above the ground when the scene has no components. */
|
|
45
|
+
var HOME_EMPTY_CAMERA_HEIGHT_ABOVE_GROUND = 2.5;
|
|
46
|
+
|
|
47
|
+
/** Default horizontal distance from world origin when the scene is empty. */
|
|
48
|
+
var HOME_EMPTY_SCENE_DISTANCE = Math.hypot(DEFAULT_HOME_VIEW_DIRECTION.x, DEFAULT_HOME_VIEW_DIRECTION.y);
|
|
49
|
+
var WORLD_ORIGIN = new THREE__namespace.Vector3(0, 0, 0);
|
|
12
50
|
var CameraControlsManager = /*#__PURE__*/function () {
|
|
13
51
|
function CameraControlsManager(component) {
|
|
14
52
|
_rollupPluginBabelHelpers.classCallCheck(this, CameraControlsManager);
|
|
@@ -18,11 +56,317 @@ var CameraControlsManager = /*#__PURE__*/function () {
|
|
|
18
56
|
}
|
|
19
57
|
|
|
20
58
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
59
|
+
* Frame the camera so that every component in the scene fits perfectly in view.
|
|
60
|
+
*
|
|
61
|
+
* Computes the combined bounding box of all scene components, then moves the
|
|
62
|
+
* (perspective) camera along its current viewing direction to the distance
|
|
63
|
+
* required to fit that bounding sphere within the frustum. The orbit target,
|
|
64
|
+
* clipping planes and distance limits are updated to match.
|
|
65
|
+
*
|
|
66
|
+
* @param {Object} [options]
|
|
67
|
+
* @param {number} [options.padding=1.04] - Multiplier on the fit distance (>1 leaves margin).
|
|
68
|
+
* @param {THREE.Vector3|{x:number,y:number,z:number}} [options.direction] - Override viewing
|
|
69
|
+
* direction (target -> camera). When omitted, the current orbit angle is preserved.
|
|
70
|
+
* @param {boolean} [options.groundLevel] - Pin camera low with a downward pitch toward
|
|
71
|
+
* the bottom-center of the assembly. Defaults to true when a home direction is used.
|
|
72
|
+
* @returns {boolean} True if the camera was reframed, false if there was nothing to frame.
|
|
24
73
|
*/
|
|
25
74
|
return _rollupPluginBabelHelpers.createClass(CameraControlsManager, [{
|
|
75
|
+
key: "fitCameraToScene",
|
|
76
|
+
value: function fitCameraToScene() {
|
|
77
|
+
var _options$padding, _options$groundLevel;
|
|
78
|
+
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
79
|
+
var component = this.sceneViewer;
|
|
80
|
+
var camera = component === null || component === void 0 ? void 0 : component.camera;
|
|
81
|
+
var scene = component === null || component === void 0 ? void 0 : component.scene;
|
|
82
|
+
var controls = component === null || component === void 0 ? void 0 : component.controls;
|
|
83
|
+
if (!camera || !scene || !camera.isPerspectiveCamera) {
|
|
84
|
+
console.warn('⚠️ fitCameraToScene: missing perspective camera or scene');
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
var padding = (_options$padding = options.padding) !== null && _options$padding !== void 0 ? _options$padding : 1.04;
|
|
88
|
+
|
|
89
|
+
// Make sure world matrices are current before measuring bounds
|
|
90
|
+
scene.updateMatrixWorld(true);
|
|
91
|
+
var box = this._collectSceneBounds(scene);
|
|
92
|
+
if (!box) {
|
|
93
|
+
return this._aimCameraAtWorldCenter(camera, controls, options);
|
|
94
|
+
}
|
|
95
|
+
var useGroundLevel = (_options$groundLevel = options.groundLevel) !== null && _options$groundLevel !== void 0 ? _options$groundLevel : this._isHomeDirection(options.direction);
|
|
96
|
+
if (useGroundLevel) {
|
|
97
|
+
return this._fitCameraGroundLevel(box, camera, controls, options, padding);
|
|
98
|
+
}
|
|
99
|
+
return this._fitCameraFromCenter(box, camera, controls, options, padding);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Aim the camera at world origin when there are no components to frame.
|
|
104
|
+
* @private
|
|
105
|
+
*/
|
|
106
|
+
}, {
|
|
107
|
+
key: "_aimCameraAtWorldCenter",
|
|
108
|
+
value: function _aimCameraAtWorldCenter(camera, controls) {
|
|
109
|
+
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
110
|
+
var frameTarget = WORLD_ORIGIN.clone();
|
|
111
|
+
var distance = HOME_EMPTY_SCENE_DISTANCE;
|
|
112
|
+
var horizDir = new THREE__namespace.Vector3();
|
|
113
|
+
if (options.direction) {
|
|
114
|
+
horizDir.set(options.direction.x, options.direction.y, 0);
|
|
115
|
+
} else {
|
|
116
|
+
horizDir.set(DEFAULT_HOME_VIEW_DIRECTION.x, DEFAULT_HOME_VIEW_DIRECTION.y, 0);
|
|
117
|
+
}
|
|
118
|
+
if (horizDir.lengthSq() < 1e-6) {
|
|
119
|
+
horizDir.set(DEFAULT_HOME_VIEW_DIRECTION.x, DEFAULT_HOME_VIEW_DIRECTION.y, 0);
|
|
120
|
+
}
|
|
121
|
+
horizDir.normalize();
|
|
122
|
+
var cameraHeight = WORLD_GROUND_Z + HOME_EMPTY_CAMERA_HEIGHT_ABOVE_GROUND;
|
|
123
|
+
var camPos = new THREE__namespace.Vector3(frameTarget.x + horizDir.x * distance, frameTarget.y + horizDir.y * distance, cameraHeight);
|
|
124
|
+
camera.position.copy(camPos);
|
|
125
|
+
camera.near = 0.01;
|
|
126
|
+
camera.far = 1000;
|
|
127
|
+
camera.updateProjectionMatrix();
|
|
128
|
+
camera.lookAt(frameTarget);
|
|
129
|
+
if (controls) {
|
|
130
|
+
controls.target.copy(frameTarget);
|
|
131
|
+
controls.minDistance = 1;
|
|
132
|
+
controls.maxDistance = 20;
|
|
133
|
+
controls.update();
|
|
134
|
+
}
|
|
135
|
+
console.log('🎥 Camera aimed at world origin (empty scene)');
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @private
|
|
141
|
+
*/
|
|
142
|
+
}, {
|
|
143
|
+
key: "_collectSceneBounds",
|
|
144
|
+
value: function _collectSceneBounds(scene) {
|
|
145
|
+
var includeTypes = ['component', 'gateway', 'segment'];
|
|
146
|
+
var box = new THREE__namespace.Box3();
|
|
147
|
+
var found = false;
|
|
148
|
+
scene.traverse(function (obj) {
|
|
149
|
+
var _obj$userData;
|
|
150
|
+
if (includeTypes.includes((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType)) {
|
|
151
|
+
var objBox = new THREE__namespace.Box3().setFromObject(obj);
|
|
152
|
+
if (!objBox.isEmpty()) {
|
|
153
|
+
box.union(objBox);
|
|
154
|
+
found = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
return found && !box.isEmpty() ? box : null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* @private
|
|
163
|
+
*/
|
|
164
|
+
}, {
|
|
165
|
+
key: "_isHomeDirection",
|
|
166
|
+
value: function _isHomeDirection(direction) {
|
|
167
|
+
if (!direction) return false;
|
|
168
|
+
var horiz = Math.hypot(direction.x, direction.y);
|
|
169
|
+
if (horiz < 1e-6) return false;
|
|
170
|
+
var dx = direction.x / horiz - DEFAULT_HOME_VIEW_DIRECTION.x / Math.hypot(DEFAULT_HOME_VIEW_DIRECTION.x, DEFAULT_HOME_VIEW_DIRECTION.y);
|
|
171
|
+
var dy = direction.y / horiz - DEFAULT_HOME_VIEW_DIRECTION.y / Math.hypot(DEFAULT_HOME_VIEW_DIRECTION.x, DEFAULT_HOME_VIEW_DIRECTION.y);
|
|
172
|
+
return Math.hypot(dx, dy) < 0.05 && Math.abs(direction.z) < 0.5;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Ground-hugging camera: horizontal offset with a fixed downward pitch toward
|
|
177
|
+
* the bottom-center of the component group.
|
|
178
|
+
* @private
|
|
179
|
+
*/
|
|
180
|
+
}, {
|
|
181
|
+
key: "_fitCameraGroundLevel",
|
|
182
|
+
value: function _fitCameraGroundLevel(box, camera, controls, options, padding) {
|
|
183
|
+
var size = box.getSize(new THREE__namespace.Vector3());
|
|
184
|
+
var frameTarget = this._getBoxBottomCenter(box);
|
|
185
|
+
var downwardPitch = THREE__namespace.MathUtils.degToRad(HOME_DOWNWARD_PITCH_DEG);
|
|
186
|
+
var horizDir = new THREE__namespace.Vector3();
|
|
187
|
+
if (options.direction) {
|
|
188
|
+
horizDir.set(options.direction.x, options.direction.y, 0);
|
|
189
|
+
} else {
|
|
190
|
+
horizDir.set(DEFAULT_HOME_VIEW_DIRECTION.x, DEFAULT_HOME_VIEW_DIRECTION.y, 0);
|
|
191
|
+
}
|
|
192
|
+
if (horizDir.lengthSq() < 1e-6) {
|
|
193
|
+
horizDir.set(DEFAULT_HOME_VIEW_DIRECTION.x, DEFAULT_HOME_VIEW_DIRECTION.y, 0);
|
|
194
|
+
}
|
|
195
|
+
horizDir.normalize();
|
|
196
|
+
var corners = this._getBoxCorners(box);
|
|
197
|
+
var vFov = THREE__namespace.MathUtils.degToRad(camera.fov);
|
|
198
|
+
var aspect = camera.aspect || 1;
|
|
199
|
+
var tanHalfV = Math.tan(vFov / 2);
|
|
200
|
+
var tanHalfH = tanHalfV * aspect;
|
|
201
|
+
var fitsAtDistance = function fitsAtDistance(distance) {
|
|
202
|
+
var cameraHeight = Math.max(frameTarget.z + distance * Math.tan(downwardPitch), box.min.z + HOME_CAMERA_MIN_HEIGHT);
|
|
203
|
+
var camPos = new THREE__namespace.Vector3(frameTarget.x + horizDir.x * distance, frameTarget.y + horizDir.y * distance, cameraHeight);
|
|
204
|
+
var forward = new THREE__namespace.Vector3().subVectors(frameTarget, camPos).normalize();
|
|
205
|
+
var worldUp = camera.up.clone().normalize();
|
|
206
|
+
var right = new THREE__namespace.Vector3().crossVectors(forward, worldUp);
|
|
207
|
+
if (right.lengthSq() < 1e-6) {
|
|
208
|
+
right = new THREE__namespace.Vector3().crossVectors(forward, new THREE__namespace.Vector3(1, 0, 0));
|
|
209
|
+
}
|
|
210
|
+
right.normalize();
|
|
211
|
+
var up = new THREE__namespace.Vector3().crossVectors(right, forward).normalize();
|
|
212
|
+
var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(corners),
|
|
213
|
+
_step;
|
|
214
|
+
try {
|
|
215
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
216
|
+
var corner = _step.value;
|
|
217
|
+
var rel = new THREE__namespace.Vector3().subVectors(corner, camPos);
|
|
218
|
+
var depth = rel.dot(forward);
|
|
219
|
+
if (depth <= 0.01) return false;
|
|
220
|
+
if (Math.abs(rel.dot(right)) / depth > tanHalfH) return false;
|
|
221
|
+
if (Math.abs(rel.dot(up)) / depth > tanHalfV) return false;
|
|
222
|
+
}
|
|
223
|
+
} catch (err) {
|
|
224
|
+
_iterator.e(err);
|
|
225
|
+
} finally {
|
|
226
|
+
_iterator.f();
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
};
|
|
230
|
+
var fitDistance = 0.5;
|
|
231
|
+
while (!fitsAtDistance(fitDistance) && fitDistance < 500) {
|
|
232
|
+
fitDistance *= 1.15;
|
|
233
|
+
}
|
|
234
|
+
if (fitDistance >= 500) {
|
|
235
|
+
console.warn('⚠️ fitCameraToScene: could not frame scene from ground level');
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Tighten to the closest distance that still fits, then apply padding.
|
|
240
|
+
var lo = 0.01;
|
|
241
|
+
var hi = fitDistance;
|
|
242
|
+
while (hi - lo > 0.1) {
|
|
243
|
+
var mid = (lo + hi) / 2;
|
|
244
|
+
if (fitsAtDistance(mid)) hi = mid;else lo = mid;
|
|
245
|
+
}
|
|
246
|
+
fitDistance = hi * padding;
|
|
247
|
+
var cameraHeight = Math.max(frameTarget.z + fitDistance * Math.tan(downwardPitch), box.min.z + HOME_CAMERA_MIN_HEIGHT);
|
|
248
|
+
var camPos = new THREE__namespace.Vector3(frameTarget.x + horizDir.x * fitDistance, frameTarget.y + horizDir.y * fitDistance, cameraHeight);
|
|
249
|
+
camera.position.copy(camPos);
|
|
250
|
+
var span = size.length();
|
|
251
|
+
camera.near = Math.max(fitDistance / 1000, 0.01);
|
|
252
|
+
camera.far = Math.max(fitDistance + span * 4, 1000);
|
|
253
|
+
camera.updateProjectionMatrix();
|
|
254
|
+
camera.lookAt(frameTarget);
|
|
255
|
+
if (controls) {
|
|
256
|
+
controls.target.copy(frameTarget);
|
|
257
|
+
controls.minDistance = Math.max(span * 0.1, 0.1);
|
|
258
|
+
controls.maxDistance = fitDistance * 4;
|
|
259
|
+
controls.update();
|
|
260
|
+
}
|
|
261
|
+
console.log("\uD83C\uDFA5 Camera framed to scene at ground level (distance: ".concat(fitDistance.toFixed(2), ", height: ").concat(cameraHeight.toFixed(2), ")"));
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Bottom-center of a bounding box (centered in X/Y, at the floor in Z).
|
|
267
|
+
* @private
|
|
268
|
+
*/
|
|
269
|
+
}, {
|
|
270
|
+
key: "_getBoxBottomCenter",
|
|
271
|
+
value: function _getBoxBottomCenter(box) {
|
|
272
|
+
var center = box.getCenter(new THREE__namespace.Vector3());
|
|
273
|
+
return new THREE__namespace.Vector3(center.x, center.y, box.min.z);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* @private
|
|
278
|
+
*/
|
|
279
|
+
}, {
|
|
280
|
+
key: "_getBoxCorners",
|
|
281
|
+
value: function _getBoxCorners(box) {
|
|
282
|
+
var min = box.min,
|
|
283
|
+
max = box.max;
|
|
284
|
+
var corners = [];
|
|
285
|
+
for (var i = 0; i < 8; i++) {
|
|
286
|
+
corners.push(new THREE__namespace.Vector3(i & 1 ? max.x : min.x, i & 2 ? max.y : min.y, i & 4 ? max.z : min.z));
|
|
287
|
+
}
|
|
288
|
+
return corners;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* @private
|
|
293
|
+
*/
|
|
294
|
+
}, {
|
|
295
|
+
key: "_fitCameraFromCenter",
|
|
296
|
+
value: function _fitCameraFromCenter(box, camera, controls, options, padding) {
|
|
297
|
+
var center = box.getCenter(new THREE__namespace.Vector3());
|
|
298
|
+
var target = controls !== null && controls !== void 0 && controls.target ? controls.target.clone() : new THREE__namespace.Vector3();
|
|
299
|
+
var direction = new THREE__namespace.Vector3();
|
|
300
|
+
if (options.direction) {
|
|
301
|
+
direction.set(options.direction.x, options.direction.y, options.direction.z);
|
|
302
|
+
} else {
|
|
303
|
+
direction.subVectors(camera.position, target);
|
|
304
|
+
}
|
|
305
|
+
if (direction.lengthSq() < 1e-6) {
|
|
306
|
+
direction.set(DEFAULT_HOME_VIEW_DIRECTION.x, DEFAULT_HOME_VIEW_DIRECTION.y, DEFAULT_HOME_VIEW_DIRECTION.z);
|
|
307
|
+
}
|
|
308
|
+
direction.normalize();
|
|
309
|
+
var forward = direction.clone().negate();
|
|
310
|
+
var worldUp = camera.up.clone().normalize();
|
|
311
|
+
var right = new THREE__namespace.Vector3().crossVectors(forward, worldUp);
|
|
312
|
+
if (right.lengthSq() < 1e-6) {
|
|
313
|
+
right = new THREE__namespace.Vector3().crossVectors(forward, new THREE__namespace.Vector3(1, 0, 0));
|
|
314
|
+
}
|
|
315
|
+
right.normalize();
|
|
316
|
+
var up = new THREE__namespace.Vector3().crossVectors(right, forward).normalize();
|
|
317
|
+
var vFov = THREE__namespace.MathUtils.degToRad(camera.fov);
|
|
318
|
+
var aspect = camera.aspect || 1;
|
|
319
|
+
var tanHalfV = Math.tan(vFov / 2);
|
|
320
|
+
var tanHalfH = tanHalfV * aspect;
|
|
321
|
+
var min = box.min;
|
|
322
|
+
var max = box.max;
|
|
323
|
+
var fitDistance = 0.01;
|
|
324
|
+
for (var i = 0; i < 8; i++) {
|
|
325
|
+
var v = new THREE__namespace.Vector3(i & 1 ? max.x : min.x, i & 2 ? max.y : min.y, i & 4 ? max.z : min.z).sub(center);
|
|
326
|
+
var vForward = v.dot(forward);
|
|
327
|
+
var vRight = Math.abs(v.dot(right));
|
|
328
|
+
var vUp = Math.abs(v.dot(up));
|
|
329
|
+
var cornerDistance = Math.max(vRight / tanHalfH - vForward, vUp / tanHalfV - vForward, -vForward + 0.01);
|
|
330
|
+
fitDistance = Math.max(fitDistance, cornerDistance);
|
|
331
|
+
}
|
|
332
|
+
fitDistance *= padding;
|
|
333
|
+
camera.position.copy(center).addScaledVector(direction, fitDistance);
|
|
334
|
+
var span = box.getSize(new THREE__namespace.Vector3()).length();
|
|
335
|
+
camera.near = Math.max(fitDistance / 1000, 0.01);
|
|
336
|
+
camera.far = Math.max(fitDistance + span * 4, 1000);
|
|
337
|
+
camera.updateProjectionMatrix();
|
|
338
|
+
camera.lookAt(center);
|
|
339
|
+
if (controls) {
|
|
340
|
+
controls.target.copy(center);
|
|
341
|
+
controls.minDistance = Math.max(span * 0.1, 0.1);
|
|
342
|
+
controls.maxDistance = fitDistance * 4;
|
|
343
|
+
controls.update();
|
|
344
|
+
}
|
|
345
|
+
console.log("\uD83C\uDFA5 Camera framed to scene (distance: ".concat(fitDistance.toFixed(2), ")"));
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Frame the scene using the default low, ground-level home viewing angle.
|
|
351
|
+
* @param {Object} [options] - Passed to fitCameraToScene (padding, etc.)
|
|
352
|
+
* @returns {boolean}
|
|
353
|
+
*/
|
|
354
|
+
}, {
|
|
355
|
+
key: "fitCameraToSceneHome",
|
|
356
|
+
value: function fitCameraToSceneHome() {
|
|
357
|
+
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
358
|
+
return this.fitCameraToScene(_rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, options), {}, {
|
|
359
|
+
direction: DEFAULT_HOME_VIEW_DIRECTION,
|
|
360
|
+
groundLevel: true
|
|
361
|
+
}));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Toggle camera auto-rotation on/off
|
|
366
|
+
*
|
|
367
|
+
* @returns {boolean} The new auto-rotation state
|
|
368
|
+
*/
|
|
369
|
+
}, {
|
|
26
370
|
key: "toggleCameraRotation",
|
|
27
371
|
value: function toggleCameraRotation() {
|
|
28
372
|
var component = this.sceneViewer;
|
|
@@ -81,3 +425,5 @@ var CameraControlsManager = /*#__PURE__*/function () {
|
|
|
81
425
|
}();
|
|
82
426
|
|
|
83
427
|
exports.CameraControlsManager = CameraControlsManager;
|
|
428
|
+
exports.DEFAULT_HOME_VIEW_DIRECTION = DEFAULT_HOME_VIEW_DIRECTION;
|
|
429
|
+
exports.HOME_EMPTY_CAMERA_HEIGHT_ABOVE_GROUND = HOME_EMPTY_CAMERA_HEIGHT_ABOVE_GROUND;
|