bruce-cesium 7.7.4 → 7.7.5
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/bruce-cesium.es5.js +535 -94
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +533 -92
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/entity-render-engine-model3d.js +168 -71
- package/dist/lib/rendering/entity-render-engine-model3d.js.map +1 -1
- package/dist/lib/rendering/xgrids-render-engine.js +363 -19
- package/dist/lib/rendering/xgrids-render-engine.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/xgrids-render-engine.d.ts +24 -0
- package/package.json +1 -1
package/dist/bruce-cesium.umd.js
CHANGED
|
@@ -28110,10 +28110,13 @@
|
|
|
28110
28110
|
})(exports.DataSourceStaticKmlManager || (exports.DataSourceStaticKmlManager = {}));
|
|
28111
28111
|
|
|
28112
28112
|
(function (XGridsRenderEngine) {
|
|
28113
|
+
/*
|
|
28114
|
+
* Loads a scan with optional SDK tuning and per-viewer budget control.
|
|
28115
|
+
*/
|
|
28113
28116
|
function Render(params) {
|
|
28114
|
-
var _a, _b, _c;
|
|
28117
|
+
var _a, _b, _c, _d;
|
|
28115
28118
|
const { api, viewer, tileset } = params;
|
|
28116
|
-
if (
|
|
28119
|
+
if (typeof LCCRender === "undefined" || typeof (LCCRender === null || LCCRender === void 0 ? void 0 : LCCRender.load) !== "function") {
|
|
28117
28120
|
console.warn("[XGridsRenderEngine] Render() LCCRender library not available.");
|
|
28118
28121
|
return null;
|
|
28119
28122
|
}
|
|
@@ -28156,6 +28159,46 @@
|
|
|
28156
28159
|
if (loadUrl.indexOf("?") !== -1) {
|
|
28157
28160
|
loadUrl = loadUrl.split("?")[0];
|
|
28158
28161
|
}
|
|
28162
|
+
let maxSplats = 6000000;
|
|
28163
|
+
/*
|
|
28164
|
+
* Configures optional LOD capabilities once metadata or initial geometry is ready.
|
|
28165
|
+
*/
|
|
28166
|
+
const configure = (object, ready) => {
|
|
28167
|
+
var _a, _b, _c;
|
|
28168
|
+
if (!object || object["_nextspaceLodRemoved"] || object["_nextspaceLodConfigured"] || ((_a = viewer.isDestroyed) === null || _a === void 0 ? void 0 : _a.call(viewer))) {
|
|
28169
|
+
return;
|
|
28170
|
+
}
|
|
28171
|
+
try {
|
|
28172
|
+
if (typeof object.setMaxSplats !== "function") {
|
|
28173
|
+
return;
|
|
28174
|
+
}
|
|
28175
|
+
const lods = typeof object.getLodInfos === "function" ? object.getLodInfos() : undefined;
|
|
28176
|
+
const adaptive = (LCCRender.nextspaceAdaptiveLod === 1 &&
|
|
28177
|
+
typeof object.setNextspaceMetadataCallback === "function" &&
|
|
28178
|
+
Array.isArray(lods) &&
|
|
28179
|
+
typeof object.setVisible === "function" &&
|
|
28180
|
+
typeof object.setLodAutoLevelUp === "function");
|
|
28181
|
+
// Unpatched SDKs still need the legacy clamp to avoid their fixed LOD shortcut.
|
|
28182
|
+
const budget = !adaptive && (lods === null || lods === void 0 ? void 0 : lods[0]) > maxSplats && (lods === null || lods === void 0 ? void 0 : lods[1]) > 0
|
|
28183
|
+
? Math.min(maxSplats, lods[1]) : maxSplats;
|
|
28184
|
+
object.setMaxSplats(budget);
|
|
28185
|
+
// A requested fly-to needs its initial data before off-screen culling can take over.
|
|
28186
|
+
if (adaptive &&
|
|
28187
|
+
(!params.flyTo || ready) &&
|
|
28188
|
+
((_b = viewer.scene.preUpdate) === null || _b === void 0 ? void 0 : _b.addEventListener) &&
|
|
28189
|
+
((_c = viewer.scene.postRender) === null || _c === void 0 ? void 0 : _c.addEventListener)) {
|
|
28190
|
+
const controller = viewer["_nextspaceXGridsLod"] ||
|
|
28191
|
+
(viewer["_nextspaceXGridsLod"] = new AdaptiveLod(viewer));
|
|
28192
|
+
controller.Add(object, maxSplats);
|
|
28193
|
+
controller.Update();
|
|
28194
|
+
}
|
|
28195
|
+
object["_nextspaceLodConfigured"] = !params.flyTo || ready;
|
|
28196
|
+
}
|
|
28197
|
+
catch (error) {
|
|
28198
|
+
// Optional SDK tuning must not abort its metadata parsing or the Cesium render loop.
|
|
28199
|
+
console.warn("[XGridsRenderEngine] Optional LOD setup unavailable.", error);
|
|
28200
|
+
}
|
|
28201
|
+
};
|
|
28159
28202
|
const obj = LCCRender.load({
|
|
28160
28203
|
camera: viewer.camera,
|
|
28161
28204
|
scene: viewer.scene,
|
|
@@ -28169,22 +28212,19 @@
|
|
|
28169
28212
|
// When true it makes the new pieces fade-in.
|
|
28170
28213
|
// The look is similar to sectioning in cesium. Might be a nice setting.
|
|
28171
28214
|
useLoadingEffect: false
|
|
28172
|
-
}, async () => {
|
|
28173
|
-
var _a, _b;
|
|
28174
|
-
|
|
28175
|
-
|
|
28176
|
-
|
|
28177
|
-
|
|
28178
|
-
|
|
28179
|
-
? Math.min(maxSplats, lods[1])
|
|
28180
|
-
: maxSplats;
|
|
28181
|
-
obj.setMaxSplats(lodBudget);
|
|
28215
|
+
}, async (loaded) => {
|
|
28216
|
+
var _a, _b, _c;
|
|
28217
|
+
const object = loaded || obj;
|
|
28218
|
+
if (!object || object["_nextspaceLodRemoved"] || ((_a = viewer.isDestroyed) === null || _a === void 0 ? void 0 : _a.call(viewer))) {
|
|
28219
|
+
return;
|
|
28220
|
+
}
|
|
28221
|
+
configure(object, true);
|
|
28182
28222
|
// Auto fly to.
|
|
28183
28223
|
if (params.flyTo) {
|
|
28184
|
-
const pos3d =
|
|
28224
|
+
const pos3d = typeof object.getBounds === "function" ? (_b = object.getBounds()) === null || _b === void 0 ? void 0 : _b.origin : undefined;
|
|
28185
28225
|
if (pos3d && BModels.Cartes.ValidateCartes3(pos3d)) {
|
|
28186
28226
|
const altered = await exports.DrawingUtils.RaisePos3d(viewer, pos3d, 300);
|
|
28187
|
-
if (altered && BModels.Cartes.ValidateCartes3(altered)) {
|
|
28227
|
+
if (!object["_nextspaceLodRemoved"] && !((_c = viewer.isDestroyed) === null || _c === void 0 ? void 0 : _c.call(viewer)) && altered && BModels.Cartes.ValidateCartes3(altered)) {
|
|
28188
28228
|
viewer.scene.camera.flyTo({
|
|
28189
28229
|
destination: altered,
|
|
28190
28230
|
orientation: {
|
|
@@ -28199,13 +28239,32 @@
|
|
|
28199
28239
|
}
|
|
28200
28240
|
}
|
|
28201
28241
|
});
|
|
28242
|
+
if (!obj) {
|
|
28243
|
+
return null;
|
|
28244
|
+
}
|
|
28245
|
+
try {
|
|
28246
|
+
const sdkBudget = typeof obj.getCurrentConfig === "function" ? (_d = obj.getCurrentConfig()) === null || _d === void 0 ? void 0 : _d.maxLoadSplatCount : undefined;
|
|
28247
|
+
// Preserve the SDK's mobile and weak-GPU limits before applying any temporary startup cap.
|
|
28248
|
+
maxSplats = Number.isFinite(sdkBudget) && sdkBudget > 0 && sdkBudget <= 2000000 ? sdkBudget : 6000000;
|
|
28249
|
+
if (LCCRender.nextspaceMetadataReady === 1 &&
|
|
28250
|
+
typeof obj.setNextspaceMetadataCallback === "function" &&
|
|
28251
|
+
typeof obj.setMaxSplats === "function") {
|
|
28252
|
+
obj.setNextspaceMetadataCallback((object) => configure(object, false));
|
|
28253
|
+
obj.setMaxSplats(Math.min(maxSplats, 1000000));
|
|
28254
|
+
}
|
|
28255
|
+
}
|
|
28256
|
+
catch (error) {
|
|
28257
|
+
console.warn("[XGridsRenderEngine] Optional startup LOD setup unavailable.", error);
|
|
28258
|
+
}
|
|
28202
28259
|
if (typeof (obj === null || obj === void 0 ? void 0 : obj.setRenderState) === "function") {
|
|
28203
28260
|
// Splats must respect nearer meshes already drawn in the same Cesium pass.
|
|
28204
28261
|
obj.setRenderState({
|
|
28205
28262
|
depthTest: {
|
|
28206
28263
|
enabled: true,
|
|
28207
28264
|
func: Cesium.WebGLConstants.LEQUAL
|
|
28208
|
-
}
|
|
28265
|
+
},
|
|
28266
|
+
// Transparent Gaussian edges must not occlude the splats blended behind them.
|
|
28267
|
+
depthMask: false
|
|
28209
28268
|
});
|
|
28210
28269
|
}
|
|
28211
28270
|
if (typeof (obj === null || obj === void 0 ? void 0 : obj.setVisible) === "function") {
|
|
@@ -28213,9 +28272,13 @@
|
|
|
28213
28272
|
}
|
|
28214
28273
|
exports.TilesetRenderEngine.WatchDateRange(viewer, obj, tileset);
|
|
28215
28274
|
// Highest LOD.
|
|
28216
|
-
obj.setStartLod
|
|
28275
|
+
if (typeof obj.setStartLod === "function") {
|
|
28276
|
+
obj.setStartLod(0);
|
|
28277
|
+
}
|
|
28217
28278
|
// Max distance for rendering.
|
|
28218
|
-
obj.setMaxDistance
|
|
28279
|
+
if (typeof obj.setMaxDistance === "function") {
|
|
28280
|
+
obj.setMaxDistance(800);
|
|
28281
|
+
}
|
|
28219
28282
|
// Adjust LODs based on camera distance.
|
|
28220
28283
|
if (typeof obj.setLodAutoLevelUp === "function") {
|
|
28221
28284
|
obj.setLodAutoLevelUp(true);
|
|
@@ -28223,18 +28286,299 @@
|
|
|
28223
28286
|
return obj;
|
|
28224
28287
|
}
|
|
28225
28288
|
XGridsRenderEngine.Render = Render;
|
|
28289
|
+
/*
|
|
28290
|
+
* Detaches optional tuning before unloading the scan.
|
|
28291
|
+
*/
|
|
28226
28292
|
function Remove(viewer, renderObject) {
|
|
28293
|
+
var _a;
|
|
28227
28294
|
if (!renderObject) {
|
|
28228
28295
|
return;
|
|
28229
28296
|
}
|
|
28230
|
-
|
|
28297
|
+
renderObject["_nextspaceLodRemoved"] = true;
|
|
28298
|
+
delete renderObject.nextspaceOnMetadata;
|
|
28299
|
+
(_a = viewer === null || viewer === void 0 ? void 0 : viewer["_nextspaceXGridsLod"]) === null || _a === void 0 ? void 0 : _a.Remove(renderObject);
|
|
28300
|
+
exports.TilesetRenderEngine.UnwatchDateRange(viewer, renderObject);
|
|
28301
|
+
if (typeof LCCRender === "undefined" || typeof (LCCRender === null || LCCRender === void 0 ? void 0 : LCCRender.unload) !== "function") {
|
|
28231
28302
|
console.warn("[XGridsRenderEngine] Remove() LCCRender library not available.");
|
|
28232
28303
|
return;
|
|
28233
28304
|
}
|
|
28234
|
-
exports.TilesetRenderEngine.UnwatchDateRange(viewer, renderObject);
|
|
28235
28305
|
LCCRender.unload(renderObject);
|
|
28236
28306
|
}
|
|
28237
28307
|
XGridsRenderEngine.Remove = Remove;
|
|
28308
|
+
/*
|
|
28309
|
+
* Shares a bounded splat budget across visible scans without overriding layer or timeline visibility.
|
|
28310
|
+
*/
|
|
28311
|
+
class AdaptiveLod {
|
|
28312
|
+
/*
|
|
28313
|
+
* Observes scene updates and rendered frames for this viewer only.
|
|
28314
|
+
*/
|
|
28315
|
+
constructor(viewer) {
|
|
28316
|
+
this.viewer = viewer;
|
|
28317
|
+
this.entries = [];
|
|
28318
|
+
this.removals = [];
|
|
28319
|
+
this.lastUpdate = -Infinity;
|
|
28320
|
+
this.lastAllocation = -Infinity;
|
|
28321
|
+
this.lastFrame = 0;
|
|
28322
|
+
this.lastMove = 0;
|
|
28323
|
+
this.slowSince = 0;
|
|
28324
|
+
this.fastSince = 0;
|
|
28325
|
+
this.lastChange = -Infinity;
|
|
28326
|
+
this.scale = 1;
|
|
28327
|
+
this.position = new Cesium.Cartesian3();
|
|
28328
|
+
this.direction = new Cesium.Cartesian3();
|
|
28329
|
+
this.havePose = false;
|
|
28330
|
+
this.removals.push(viewer.scene.preUpdate.addEventListener(() => {
|
|
28331
|
+
try {
|
|
28332
|
+
this.Update();
|
|
28333
|
+
}
|
|
28334
|
+
catch (error) {
|
|
28335
|
+
console.warn("[XGridsRenderEngine] Optional LOD controller disabled.", error);
|
|
28336
|
+
this.Dispose();
|
|
28337
|
+
}
|
|
28338
|
+
}));
|
|
28339
|
+
this.removals.push(viewer.scene.postRender.addEventListener(() => {
|
|
28340
|
+
const camera = viewer.scene.camera;
|
|
28341
|
+
const moving = this.havePose && (Cesium.Cartesian3.distanceSquared(camera.positionWC, this.position) > 0.000001 ||
|
|
28342
|
+
Cesium.Cartesian3.distanceSquared(camera.directionWC, this.direction) > 0.00000001);
|
|
28343
|
+
Cesium.Cartesian3.clone(camera.positionWC, this.position);
|
|
28344
|
+
Cesium.Cartesian3.clone(camera.directionWC, this.direction);
|
|
28345
|
+
this.havePose = true;
|
|
28346
|
+
this.ObserveFrame(performance.now(), moving);
|
|
28347
|
+
}));
|
|
28348
|
+
}
|
|
28349
|
+
/*
|
|
28350
|
+
* Registers a scan while preserving the caller's visibility intent.
|
|
28351
|
+
*/
|
|
28352
|
+
Add(object, maxBudget) {
|
|
28353
|
+
var _a, _b, _c, _d;
|
|
28354
|
+
if (this.entries.some(entry => entry.object === object)) {
|
|
28355
|
+
return;
|
|
28356
|
+
}
|
|
28357
|
+
if (typeof object.setMaxSplats !== "function") {
|
|
28358
|
+
return;
|
|
28359
|
+
}
|
|
28360
|
+
const lods = typeof object.getLodInfos === "function" ? object.getLodInfos() : undefined;
|
|
28361
|
+
const finest = lods === null || lods === void 0 ? void 0 : lods[0];
|
|
28362
|
+
const coarsest = (lods === null || lods === void 0 ? void 0 : lods.length) > 1 ? lods[lods.length - 1] : 0;
|
|
28363
|
+
const entry = {
|
|
28364
|
+
object, maxBudget,
|
|
28365
|
+
capacity: Number.isFinite(finest) && finest > 0 ? Math.min(maxBudget, finest) : maxBudget,
|
|
28366
|
+
minimum: Number.isFinite(coarsest) && coarsest > 0 ? Math.min(maxBudget, coarsest) : 0,
|
|
28367
|
+
wantedVisible: ((_b = (_a = object.getCurrentConfig) === null || _a === void 0 ? void 0 : _a.call(object)) === null || _b === void 0 ? void 0 : _b.visible) !== false,
|
|
28368
|
+
visible: ((_d = (_c = object.getCurrentConfig) === null || _c === void 0 ? void 0 : _c.call(object)) === null || _d === void 0 ? void 0 : _d.visible) !== false,
|
|
28369
|
+
culled: false, setVisible: object.setVisible, budget: -1, nodeBudget: -1,
|
|
28370
|
+
radiusPixels: Infinity, surfaceDistance: Infinity, weight: 1, near: false
|
|
28371
|
+
};
|
|
28372
|
+
if (typeof entry.setVisible === "function") {
|
|
28373
|
+
object.setVisible = (visible) => {
|
|
28374
|
+
entry.wantedVisible = !!visible;
|
|
28375
|
+
this.applyVisibility(entry);
|
|
28376
|
+
this.lastUpdate = -Infinity;
|
|
28377
|
+
this.lastAllocation = -Infinity;
|
|
28378
|
+
};
|
|
28379
|
+
}
|
|
28380
|
+
this.entries.push(entry);
|
|
28381
|
+
this.lastMove = performance.now();
|
|
28382
|
+
this.lastUpdate = -Infinity;
|
|
28383
|
+
this.lastAllocation = -Infinity;
|
|
28384
|
+
}
|
|
28385
|
+
/*
|
|
28386
|
+
* Combines explicit visibility with temporary camera culling.
|
|
28387
|
+
*/
|
|
28388
|
+
applyVisibility(entry) {
|
|
28389
|
+
const visible = entry.wantedVisible && !entry.culled;
|
|
28390
|
+
if (entry.visible !== visible && typeof entry.setVisible === "function") {
|
|
28391
|
+
entry.visible = visible;
|
|
28392
|
+
entry.setVisible.call(entry.object, visible);
|
|
28393
|
+
this.viewer.scene.requestRender();
|
|
28394
|
+
}
|
|
28395
|
+
}
|
|
28396
|
+
/*
|
|
28397
|
+
* Render pressure uses elapsed wall time because a paused timeline must still adapt.
|
|
28398
|
+
*/
|
|
28399
|
+
ObserveFrame(now, moving) {
|
|
28400
|
+
const gap = now - this.lastFrame;
|
|
28401
|
+
this.lastFrame = now;
|
|
28402
|
+
if (moving) {
|
|
28403
|
+
this.lastMove = now;
|
|
28404
|
+
}
|
|
28405
|
+
if (!moving || gap <= 0 || gap > 1000) {
|
|
28406
|
+
this.slowSince = this.fastSince = 0;
|
|
28407
|
+
return;
|
|
28408
|
+
}
|
|
28409
|
+
this.slowSince = gap > 40 ? this.slowSince || now : 0;
|
|
28410
|
+
this.fastSince = gap < 22 ? this.fastSince || now : 0;
|
|
28411
|
+
if (now - this.lastChange < 4000) {
|
|
28412
|
+
return;
|
|
28413
|
+
}
|
|
28414
|
+
if (this.slowSince && now - this.slowSince >= 1500 && this.scale > 0.25) {
|
|
28415
|
+
this.scale = Math.max(0.25, this.scale * 0.75);
|
|
28416
|
+
this.lastChange = now;
|
|
28417
|
+
this.slowSince = this.fastSince = 0;
|
|
28418
|
+
this.lastUpdate = -Infinity;
|
|
28419
|
+
}
|
|
28420
|
+
else if (this.fastSince && now - this.fastSince >= 6000 && this.scale < 1) {
|
|
28421
|
+
this.scale = Math.min(1, this.scale + 0.125);
|
|
28422
|
+
this.lastChange = now;
|
|
28423
|
+
this.slowSince = this.fastSince = 0;
|
|
28424
|
+
this.lastUpdate = -Infinity;
|
|
28425
|
+
}
|
|
28426
|
+
}
|
|
28427
|
+
/*
|
|
28428
|
+
* Estimates visible screen coverage and distance, failing open for unknown bounds.
|
|
28429
|
+
*/
|
|
28430
|
+
measure(entry) {
|
|
28431
|
+
var _a;
|
|
28432
|
+
entry.weight = 1;
|
|
28433
|
+
entry.radiusPixels = entry.surfaceDistance = Infinity;
|
|
28434
|
+
try {
|
|
28435
|
+
const object = entry.object;
|
|
28436
|
+
const bounds = (_a = object.getBounds) === null || _a === void 0 ? void 0 : _a.call(object);
|
|
28437
|
+
const matrix = object.modelMatrix;
|
|
28438
|
+
const camera = this.viewer.scene.camera;
|
|
28439
|
+
const width = this.viewer.scene.drawingBufferWidth;
|
|
28440
|
+
const height = this.viewer.scene.drawingBufferHeight;
|
|
28441
|
+
if (!(bounds === null || bounds === void 0 ? void 0 : bounds.min) || !(bounds === null || bounds === void 0 ? void 0 : bounds.max) || !matrix || !(width > 0 && height > 0)) {
|
|
28442
|
+
entry.culled = false;
|
|
28443
|
+
return;
|
|
28444
|
+
}
|
|
28445
|
+
const center = Cesium.Cartesian3.midpoint(bounds.min, bounds.max, new Cesium.Cartesian3());
|
|
28446
|
+
Cesium.Matrix4.multiplyByPoint(matrix, center, center);
|
|
28447
|
+
const scale = Cesium.Matrix4.getMaximumScale(matrix);
|
|
28448
|
+
const radius = Cesium.Cartesian3.distance(bounds.min, bounds.max) * scale * 0.55 + 1;
|
|
28449
|
+
const distance = Cesium.Cartesian3.distance(camera.positionWC, center);
|
|
28450
|
+
const pixel = camera.frustum.getPixelDimensions(width, height, Math.max(1, distance), 1, new Cesium.Cartesian2());
|
|
28451
|
+
const pixels = radius / Math.max(pixel.x, pixel.y);
|
|
28452
|
+
if (!Number.isFinite(pixels) || !(radius > 0)) {
|
|
28453
|
+
entry.culled = false;
|
|
28454
|
+
return;
|
|
28455
|
+
}
|
|
28456
|
+
const sphere = new Cesium.BoundingSphere(center, radius);
|
|
28457
|
+
const frustum = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC);
|
|
28458
|
+
const outside = frustum.computeVisibility(sphere) === Cesium.Intersect.OUTSIDE;
|
|
28459
|
+
entry.culled = outside || pixels < (entry.culled ? 1.5 : 0.75);
|
|
28460
|
+
entry.radiusPixels = pixels;
|
|
28461
|
+
entry.weight = Math.pow(Math.min(1, Math.max(0.05, pixels / height)), 2);
|
|
28462
|
+
const local = Cesium.Matrix4.multiplyByPoint(Cesium.Matrix4.inverse(matrix, new Cesium.Matrix4()), camera.positionWC, new Cesium.Cartesian3());
|
|
28463
|
+
const nearest = new Cesium.Cartesian3(Cesium.Math.clamp(local.x, bounds.min.x, bounds.max.x), Cesium.Math.clamp(local.y, bounds.min.y, bounds.max.y), Cesium.Math.clamp(local.z, bounds.min.z, bounds.max.z));
|
|
28464
|
+
entry.surfaceDistance = Cesium.Cartesian3.distance(local, nearest) * scale;
|
|
28465
|
+
}
|
|
28466
|
+
catch {
|
|
28467
|
+
// Unknown bounds or a changed optional SDK must fail open instead of hiding the scan.
|
|
28468
|
+
entry.culled = false;
|
|
28469
|
+
}
|
|
28470
|
+
}
|
|
28471
|
+
/*
|
|
28472
|
+
* Allocates the shared hardware budget across visible scans with hysteresis.
|
|
28473
|
+
*/
|
|
28474
|
+
Update(now = performance.now()) {
|
|
28475
|
+
var _a, _b;
|
|
28476
|
+
if ((_b = (_a = this.viewer).isDestroyed) === null || _b === void 0 ? void 0 : _b.call(_a)) {
|
|
28477
|
+
this.Dispose();
|
|
28478
|
+
return;
|
|
28479
|
+
}
|
|
28480
|
+
if (now - this.lastUpdate < 250) {
|
|
28481
|
+
return;
|
|
28482
|
+
}
|
|
28483
|
+
this.lastUpdate = now;
|
|
28484
|
+
// A still view can recover detail gradually without treating missing frames as a slow GPU.
|
|
28485
|
+
if (now - this.lastMove > 3000 && now - this.lastChange > 6000 && this.scale < 1) {
|
|
28486
|
+
this.scale = Math.min(1, this.scale + 0.125);
|
|
28487
|
+
this.lastChange = now;
|
|
28488
|
+
}
|
|
28489
|
+
for (const entry of this.entries) {
|
|
28490
|
+
this.measure(entry);
|
|
28491
|
+
this.applyVisibility(entry);
|
|
28492
|
+
}
|
|
28493
|
+
const visible = this.entries.filter(entry => entry.wantedVisible && !entry.culled);
|
|
28494
|
+
if (!visible.length || now - this.lastAllocation < 2000) {
|
|
28495
|
+
return;
|
|
28496
|
+
}
|
|
28497
|
+
this.lastAllocation = now;
|
|
28498
|
+
const maximum = Math.max(...visible.map(entry => entry.maxBudget));
|
|
28499
|
+
const minimum = visible.reduce((sum, entry) => sum + Math.min(entry.capacity, entry.minimum), 0);
|
|
28500
|
+
// Preserve authored coarse coverage when it fits; dropping below a whole tile can erase a scan.
|
|
28501
|
+
const reserve = minimum <= maximum;
|
|
28502
|
+
let remaining = Math.max(maximum * this.scale, reserve ? minimum : 0);
|
|
28503
|
+
const allocations = new Map();
|
|
28504
|
+
visible.forEach(entry => {
|
|
28505
|
+
const floor = reserve ? Math.min(entry.capacity, entry.minimum) : 0;
|
|
28506
|
+
allocations.set(entry, floor);
|
|
28507
|
+
remaining -= floor;
|
|
28508
|
+
});
|
|
28509
|
+
let pending = visible.filter(entry => allocations.get(entry) < entry.capacity);
|
|
28510
|
+
while (pending.length) {
|
|
28511
|
+
const totalWeight = pending.reduce((sum, entry) => sum + entry.weight, 0);
|
|
28512
|
+
const capped = pending.filter(entry => remaining * entry.weight / totalWeight >= entry.capacity - allocations.get(entry));
|
|
28513
|
+
if (!capped.length) {
|
|
28514
|
+
pending.forEach(entry => allocations.set(entry, allocations.get(entry) + remaining * entry.weight / totalWeight));
|
|
28515
|
+
break;
|
|
28516
|
+
}
|
|
28517
|
+
capped.forEach(entry => {
|
|
28518
|
+
remaining -= entry.capacity - allocations.get(entry);
|
|
28519
|
+
allocations.set(entry, entry.capacity);
|
|
28520
|
+
});
|
|
28521
|
+
pending = pending.filter(entry => allocations.get(entry) < entry.capacity);
|
|
28522
|
+
}
|
|
28523
|
+
for (const entry of visible) {
|
|
28524
|
+
const allocation = allocations.get(entry);
|
|
28525
|
+
const step = allocation < 250000 ? 10000 : 250000;
|
|
28526
|
+
const budget = allocation >= entry.capacity ? entry.capacity : Math.max(1, reserve ? entry.minimum : 0, Math.floor(allocation / step) * step);
|
|
28527
|
+
const near = entry.surfaceDistance < (entry.near ? 20 : 12) && entry.radiusPixels > (entry.near ? 80 : 120);
|
|
28528
|
+
entry.near = near;
|
|
28529
|
+
const ceiling = entry.maxBudget <= 2000000 ? entry.maxBudget / 2 : near ? 4000000 : 2000000;
|
|
28530
|
+
const nodeBudget = Math.max(1, Math.min(ceiling, entry.capacity <= ceiling ? budget : budget * (near ? 2 / 3 : 1 / 3)));
|
|
28531
|
+
if (entry.budget !== budget) {
|
|
28532
|
+
entry.object.setMaxSplats(budget);
|
|
28533
|
+
entry.budget = budget;
|
|
28534
|
+
this.viewer.scene.requestRender();
|
|
28535
|
+
}
|
|
28536
|
+
if (entry.nodeBudget !== nodeBudget && typeof entry.object.setMaxNodeSplats === "function") {
|
|
28537
|
+
entry.object.setMaxNodeSplats(nodeBudget);
|
|
28538
|
+
entry.nodeBudget = nodeBudget;
|
|
28539
|
+
this.viewer.scene.requestRender();
|
|
28540
|
+
}
|
|
28541
|
+
}
|
|
28542
|
+
}
|
|
28543
|
+
/*
|
|
28544
|
+
* Restores the scan's visibility method and releases unused listeners.
|
|
28545
|
+
*/
|
|
28546
|
+
Remove(object) {
|
|
28547
|
+
const entry = this.entries.find(entry => entry.object === object);
|
|
28548
|
+
if (entry) {
|
|
28549
|
+
object.setVisible = entry.setVisible;
|
|
28550
|
+
this.entries = this.entries.filter(other => other !== entry);
|
|
28551
|
+
this.lastUpdate = -Infinity;
|
|
28552
|
+
this.lastAllocation = -Infinity;
|
|
28553
|
+
}
|
|
28554
|
+
if (!this.entries.length) {
|
|
28555
|
+
this.Dispose();
|
|
28556
|
+
}
|
|
28557
|
+
}
|
|
28558
|
+
/*
|
|
28559
|
+
* Restores visibility intent and releases all controller listeners.
|
|
28560
|
+
*/
|
|
28561
|
+
Dispose() {
|
|
28562
|
+
this.removals.forEach(remove => remove());
|
|
28563
|
+
this.removals = [];
|
|
28564
|
+
this.entries.forEach(entry => {
|
|
28565
|
+
entry.object.setVisible = entry.setVisible;
|
|
28566
|
+
try {
|
|
28567
|
+
if (entry.visible !== entry.wantedVisible && typeof entry.setVisible === "function") {
|
|
28568
|
+
entry.setVisible.call(entry.object, entry.wantedVisible);
|
|
28569
|
+
}
|
|
28570
|
+
}
|
|
28571
|
+
catch {
|
|
28572
|
+
// A disposed or replaced optional SDK must not break viewer cleanup.
|
|
28573
|
+
}
|
|
28574
|
+
});
|
|
28575
|
+
this.entries = [];
|
|
28576
|
+
if (this.viewer["_nextspaceXGridsLod"] === this) {
|
|
28577
|
+
delete this.viewer["_nextspaceXGridsLod"];
|
|
28578
|
+
}
|
|
28579
|
+
}
|
|
28580
|
+
}
|
|
28581
|
+
XGridsRenderEngine.AdaptiveLod = AdaptiveLod;
|
|
28238
28582
|
/**
|
|
28239
28583
|
* Applies position, rotation, and scale to a live XGrids render object.
|
|
28240
28584
|
*/
|
|
@@ -49481,88 +49825,103 @@
|
|
|
49481
49825
|
});
|
|
49482
49826
|
cEntity.show = true;
|
|
49483
49827
|
}
|
|
49484
|
-
const
|
|
49485
|
-
|
|
49486
|
-
|
|
49487
|
-
|
|
49488
|
-
|
|
49489
|
-
|
|
49490
|
-
|
|
49491
|
-
|
|
49492
|
-
|
|
49493
|
-
|
|
49494
|
-
|
|
49495
|
-
|
|
49496
|
-
|
|
49497
|
-
|
|
49828
|
+
const model = cEntity.model;
|
|
49829
|
+
model._radiusLoaded = false;
|
|
49830
|
+
/*
|
|
49831
|
+
* Retains bounds measurement for hosts that cannot expose the displayed model.
|
|
49832
|
+
*/
|
|
49833
|
+
const measureTemporaryModelBounds = () => {
|
|
49834
|
+
const fileRadiusKey = `model3d_${BModels.UrlUtils.RemoveSignature(params.lodUrl)}_${scale * styleScale}_radius`;
|
|
49835
|
+
let heightProm = _fileRadiusCache.Get(fileRadiusKey);
|
|
49836
|
+
if (!heightProm) {
|
|
49837
|
+
heightProm = new Promise(async (res) => {
|
|
49838
|
+
try {
|
|
49839
|
+
// The fallback needs a temporary primitive until its bounds become available.
|
|
49840
|
+
const modelPrim = await getModelEntity(params.lodUrl, scale * styleScale);
|
|
49841
|
+
/*
|
|
49842
|
+
* Copies bounds before releasing the temporary primitive.
|
|
49843
|
+
*/
|
|
49844
|
+
const onReady = () => {
|
|
49845
|
+
readyEventRemoval === null || readyEventRemoval === void 0 ? void 0 : readyEventRemoval();
|
|
49846
|
+
readyEventRemoval = null;
|
|
49847
|
+
/*
|
|
49848
|
+
* Releases the temporary primitive even if the viewer was destroyed.
|
|
49849
|
+
*/
|
|
49850
|
+
const kill = () => {
|
|
49851
|
+
if (params.viewer && !params.viewer.isDestroyed() && params.viewer.scene.primitives.contains(modelPrim)) {
|
|
49852
|
+
params.viewer.scene.primitives.remove(modelPrim);
|
|
49853
|
+
}
|
|
49854
|
+
if (!modelPrim.isDestroyed()) {
|
|
49855
|
+
modelPrim.destroy();
|
|
49856
|
+
}
|
|
49857
|
+
};
|
|
49858
|
+
if (!cEntity || !(modelPrim === null || modelPrim === void 0 ? void 0 : modelPrim.boundingSphere)) {
|
|
49859
|
+
kill();
|
|
49860
|
+
res(null);
|
|
49861
|
+
return;
|
|
49498
49862
|
}
|
|
49499
|
-
|
|
49500
|
-
|
|
49863
|
+
let radius = modelPrim.boundingSphere.radius;
|
|
49864
|
+
let centerOffset = modelPrim.boundingSphere.center;
|
|
49865
|
+
const bounds = {
|
|
49866
|
+
center: centerOffset ? Cesium.Cartesian3.clone(centerOffset) : Cesium.Cartesian3.ZERO.clone(),
|
|
49867
|
+
radius: modelPrim.boundingSphere.radius
|
|
49868
|
+
};
|
|
49869
|
+
if (centerOffset) {
|
|
49870
|
+
// Include the offset so origin-based culling contains the full model.
|
|
49871
|
+
const magnitude = Cesium.Cartesian3.magnitude(centerOffset);
|
|
49872
|
+
radius += magnitude;
|
|
49873
|
+
// Preserve extra culling padding for models with large origin offsets.
|
|
49874
|
+
if (magnitude > 100) {
|
|
49875
|
+
radius += 100;
|
|
49876
|
+
}
|
|
49501
49877
|
}
|
|
49502
|
-
};
|
|
49503
|
-
if (!cEntity || !(modelPrim === null || modelPrim === void 0 ? void 0 : modelPrim.boundingSphere)) {
|
|
49504
49878
|
kill();
|
|
49505
|
-
res(
|
|
49506
|
-
return;
|
|
49507
|
-
}
|
|
49508
|
-
let radius = modelPrim.boundingSphere.radius;
|
|
49509
|
-
let centerOffset = modelPrim.boundingSphere.center;
|
|
49510
|
-
const bounds = {
|
|
49511
|
-
center: centerOffset ? Cesium.Cartesian3.clone(centerOffset) : Cesium.Cartesian3.ZERO.clone(),
|
|
49512
|
-
radius: modelPrim.boundingSphere.radius
|
|
49879
|
+
res({ radius, bounds });
|
|
49513
49880
|
};
|
|
49514
|
-
|
|
49515
|
-
|
|
49516
|
-
|
|
49517
|
-
|
|
49518
|
-
|
|
49519
|
-
|
|
49520
|
-
|
|
49521
|
-
|
|
49522
|
-
|
|
49881
|
+
let readyEventRemoval = null;
|
|
49882
|
+
// Prefer the ready event when the host exposes it.
|
|
49883
|
+
if (modelPrim["readyEvent"]) {
|
|
49884
|
+
modelPrim["readyEvent"].addEventListener(onReady);
|
|
49885
|
+
}
|
|
49886
|
+
// Retain compatibility with promise-based hosts.
|
|
49887
|
+
else if (modelPrim["readyPromise"]) {
|
|
49888
|
+
modelPrim["readyPromise"].then(() => {
|
|
49889
|
+
onReady();
|
|
49890
|
+
}).catch((e) => {
|
|
49891
|
+
console.error(e);
|
|
49892
|
+
res(null);
|
|
49893
|
+
});
|
|
49523
49894
|
}
|
|
49524
|
-
|
|
49525
|
-
|
|
49526
|
-
|
|
49527
|
-
|
|
49528
|
-
|
|
49529
|
-
|
|
49530
|
-
|
|
49531
|
-
|
|
49532
|
-
|
|
49533
|
-
|
|
49534
|
-
|
|
49535
|
-
|
|
49536
|
-
|
|
49537
|
-
|
|
49538
|
-
|
|
49539
|
-
|
|
49895
|
+
params.viewer.scene.primitives.add(modelPrim);
|
|
49896
|
+
}
|
|
49897
|
+
catch (e) {
|
|
49898
|
+
console.error(e);
|
|
49899
|
+
res(null);
|
|
49900
|
+
}
|
|
49901
|
+
});
|
|
49902
|
+
_fileRadiusCache.Set(fileRadiusKey, heightProm);
|
|
49903
|
+
}
|
|
49904
|
+
heightProm.then((measured) => {
|
|
49905
|
+
if (model) {
|
|
49906
|
+
model._radius = measured ? measured.radius : null;
|
|
49907
|
+
model._bounds = measured ? measured.bounds : null;
|
|
49908
|
+
model._radiusLoaded = true;
|
|
49909
|
+
if (params.viewer && params.viewer.scene && !params.viewer.isDestroyed()) {
|
|
49910
|
+
exports.VisualRegisterCuller.MarkShouldRecheck(params.viewer);
|
|
49540
49911
|
}
|
|
49541
|
-
params.viewer.scene.primitives.add(modelPrim);
|
|
49542
49912
|
}
|
|
49543
|
-
|
|
49544
|
-
|
|
49545
|
-
|
|
49913
|
+
// Rough estimate on when the model is ready in the scene.
|
|
49914
|
+
if (animateScale) {
|
|
49915
|
+
animateScale.Play();
|
|
49546
49916
|
}
|
|
49547
49917
|
});
|
|
49548
|
-
|
|
49918
|
+
};
|
|
49919
|
+
if (Cesium.Model.fromGltfAsync) {
|
|
49920
|
+
trackRenderedModelBounds(params.viewer, cEntity, model, scale * styleScale, measureTemporaryModelBounds, animateScale);
|
|
49921
|
+
}
|
|
49922
|
+
else {
|
|
49923
|
+
measureTemporaryModelBounds();
|
|
49549
49924
|
}
|
|
49550
|
-
heightProm.then((measured) => {
|
|
49551
|
-
if (model) {
|
|
49552
|
-
model._radius = measured ? measured.radius : null;
|
|
49553
|
-
model._bounds = measured ? measured.bounds : null;
|
|
49554
|
-
model._radiusLoaded = true;
|
|
49555
|
-
if (params.viewer && params.viewer.scene && !params.viewer.isDestroyed()) {
|
|
49556
|
-
exports.VisualRegisterCuller.MarkShouldRecheck(params.viewer);
|
|
49557
|
-
}
|
|
49558
|
-
}
|
|
49559
|
-
// Rough estimate on when the model is ready in the scene.
|
|
49560
|
-
if (animateScale) {
|
|
49561
|
-
animateScale.Play();
|
|
49562
|
-
}
|
|
49563
|
-
});
|
|
49564
|
-
const model = cEntity.model;
|
|
49565
|
-
model._radiusLoaded = false;
|
|
49566
49925
|
model._clientFileId = params.lodClientFileId;
|
|
49567
49926
|
model._entityScale = {
|
|
49568
49927
|
record: scale,
|
|
@@ -49770,6 +50129,88 @@
|
|
|
49770
50129
|
}
|
|
49771
50130
|
EntityRenderEngineModel3d.RenderGroup = RenderGroup;
|
|
49772
50131
|
})(exports.EntityRenderEngineModel3d || (exports.EntityRenderEngineModel3d = {}));
|
|
50132
|
+
/*
|
|
50133
|
+
* Measures bounds from Cesium's displayed model so loading a visual does not also load a temporary model.
|
|
50134
|
+
*/
|
|
50135
|
+
function trackRenderedModelBounds(viewer, entity, model, targetScale, fallback, animateScale) {
|
|
50136
|
+
const key = "_nextspaceRenderedModelBoundsMonitor";
|
|
50137
|
+
let monitor = viewer[key];
|
|
50138
|
+
if (!monitor) {
|
|
50139
|
+
monitor = { pending: new Map() };
|
|
50140
|
+
viewer[key] = monitor;
|
|
50141
|
+
}
|
|
50142
|
+
monitor.pending.set(entity.id, { entity, model, targetScale, fallback, animateScale });
|
|
50143
|
+
if (monitor.removeListener) {
|
|
50144
|
+
return;
|
|
50145
|
+
}
|
|
50146
|
+
monitor.removeListener = viewer.scene.postRender.addEventListener(() => {
|
|
50147
|
+
var _a, _b, _c, _d, _e, _f;
|
|
50148
|
+
if (viewer.isDestroyed()) {
|
|
50149
|
+
monitor.pending.clear();
|
|
50150
|
+
}
|
|
50151
|
+
else {
|
|
50152
|
+
const primitives = viewer.scene.primitives;
|
|
50153
|
+
for (let i = 0; i < primitives.length && monitor.pending.size; i++) {
|
|
50154
|
+
const primitive = primitives.get(i);
|
|
50155
|
+
if (!(primitive instanceof Cesium.Model) || !primitive.ready) {
|
|
50156
|
+
continue;
|
|
50157
|
+
}
|
|
50158
|
+
const task = monitor.pending.get((_a = primitive.id) === null || _a === void 0 ? void 0 : _a.id);
|
|
50159
|
+
if (!task || primitive.id !== task.entity || task.entity.model !== task.model) {
|
|
50160
|
+
continue;
|
|
50161
|
+
}
|
|
50162
|
+
try {
|
|
50163
|
+
const sphere = primitive.boundingSphere;
|
|
50164
|
+
const matrix = primitive.heightReference == null || primitive.heightReference === Cesium.HeightReference.NONE
|
|
50165
|
+
? primitive.modelMatrix
|
|
50166
|
+
: primitive._clampedModelMatrix;
|
|
50167
|
+
if (!sphere || !matrix ||
|
|
50168
|
+
!Number.isFinite(sphere.radius) || sphere.radius < 0 ||
|
|
50169
|
+
!Number.isFinite((_b = sphere.center) === null || _b === void 0 ? void 0 : _b.x) ||
|
|
50170
|
+
!Number.isFinite((_c = sphere.center) === null || _c === void 0 ? void 0 : _c.y) ||
|
|
50171
|
+
!Number.isFinite((_d = sphere.center) === null || _d === void 0 ? void 0 : _d.z)) {
|
|
50172
|
+
throw new Error("Displayed model bounds unavailable");
|
|
50173
|
+
}
|
|
50174
|
+
const inverse = Cesium.Matrix4.inverseTransformation(matrix, new Cesium.Matrix4());
|
|
50175
|
+
const center = Cesium.Matrix4.multiplyByPoint(inverse, sphere.center, new Cesium.Cartesian3());
|
|
50176
|
+
const scaleRatio = task.targetScale / primitive.scale;
|
|
50177
|
+
Cesium.Cartesian3.multiplyByScalar(center, scaleRatio, center);
|
|
50178
|
+
const radius = sphere.radius * scaleRatio;
|
|
50179
|
+
const magnitude = Cesium.Cartesian3.magnitude(center);
|
|
50180
|
+
if (!Number.isFinite(scaleRatio) || scaleRatio <= 0 || !Number.isFinite(magnitude) || !Number.isFinite(radius)) {
|
|
50181
|
+
throw new Error("Displayed model bounds transform invalid");
|
|
50182
|
+
}
|
|
50183
|
+
task.model._bounds = { center, radius };
|
|
50184
|
+
task.model._radius = radius + magnitude + (magnitude > 100 ? 100 : 0);
|
|
50185
|
+
task.model._radiusLoaded = true;
|
|
50186
|
+
(_e = task.animateScale) === null || _e === void 0 ? void 0 : _e.Play();
|
|
50187
|
+
exports.VisualRegisterCuller.MarkShouldRecheck(viewer);
|
|
50188
|
+
}
|
|
50189
|
+
catch (e) {
|
|
50190
|
+
task.fallback();
|
|
50191
|
+
}
|
|
50192
|
+
monitor.pending.delete(task.entity.id);
|
|
50193
|
+
}
|
|
50194
|
+
for (const [id, task] of monitor.pending) {
|
|
50195
|
+
const modelShown = GetCValue(viewer, task.model.show) !== false;
|
|
50196
|
+
if (!task.entity.isShowing || !modelShown) {
|
|
50197
|
+
task.visibleAt = null;
|
|
50198
|
+
}
|
|
50199
|
+
else if (task.visibleAt == null) {
|
|
50200
|
+
task.visibleAt = performance.now();
|
|
50201
|
+
}
|
|
50202
|
+
else if (performance.now() - task.visibleAt > 60000) {
|
|
50203
|
+
task.fallback();
|
|
50204
|
+
monitor.pending.delete(id);
|
|
50205
|
+
}
|
|
50206
|
+
}
|
|
50207
|
+
}
|
|
50208
|
+
if (!monitor.pending.size) {
|
|
50209
|
+
(_f = monitor.removeListener) === null || _f === void 0 ? void 0 : _f.call(monitor);
|
|
50210
|
+
monitor.removeListener = null;
|
|
50211
|
+
}
|
|
50212
|
+
});
|
|
50213
|
+
}
|
|
49773
50214
|
async function getName$1(api, entity, offline) {
|
|
49774
50215
|
var _a;
|
|
49775
50216
|
const ownName = GetUsableEntityName(entity);
|
|
@@ -57122,7 +57563,7 @@ void main() {
|
|
|
57122
57563
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
57123
57564
|
})(exports.StyleUtils || (exports.StyleUtils = {}));
|
|
57124
57565
|
|
|
57125
|
-
const VERSION = "7.7.
|
|
57566
|
+
const VERSION = "7.7.5";
|
|
57126
57567
|
/**
|
|
57127
57568
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
57128
57569
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|