bruce-cesium 7.4.5 → 7.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/bruce-cesium.es5.js +303 -34
  2. package/dist/bruce-cesium.es5.js.map +1 -1
  3. package/dist/bruce-cesium.umd.js +301 -32
  4. package/dist/bruce-cesium.umd.js.map +1 -1
  5. package/dist/lib/bruce-cesium.js +1 -1
  6. package/dist/lib/rendering/cesium-animated-property.js +16 -1
  7. package/dist/lib/rendering/cesium-animated-property.js.map +1 -1
  8. package/dist/lib/rendering/entity-render-engine-model3d.js +2 -1
  9. package/dist/lib/rendering/entity-render-engine-model3d.js.map +1 -1
  10. package/dist/lib/rendering/render-managers/common/entity-label.js +24 -2
  11. package/dist/lib/rendering/render-managers/common/entity-label.js.map +1 -1
  12. package/dist/lib/rendering/render-managers/entities/entities-loaded-render-manager.js +12 -4
  13. package/dist/lib/rendering/render-managers/entities/entities-loaded-render-manager.js.map +1 -1
  14. package/dist/lib/rendering/render-managers/entities/entities-render-manager.js +12 -4
  15. package/dist/lib/rendering/render-managers/entities/entities-render-manager.js.map +1 -1
  16. package/dist/lib/rendering/render-managers/tilesets/tileset-arb-render-manager.js +35 -2
  17. package/dist/lib/rendering/render-managers/tilesets/tileset-arb-render-manager.js.map +1 -1
  18. package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js +36 -3
  19. package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js.map +1 -1
  20. package/dist/lib/rendering/render-managers/tilesets/tileset-entities-render-manager.js +36 -3
  21. package/dist/lib/rendering/render-managers/tilesets/tileset-entities-render-manager.js.map +1 -1
  22. package/dist/lib/rendering/render-managers/tilesets/tileset-google-photos-render-manager.js +19 -0
  23. package/dist/lib/rendering/render-managers/tilesets/tileset-google-photos-render-manager.js.map +1 -1
  24. package/dist/lib/rendering/render-managers/tilesets/tileset-osm-render-manager.js +55 -2
  25. package/dist/lib/rendering/render-managers/tilesets/tileset-osm-render-manager.js.map +1 -1
  26. package/dist/lib/rendering/visuals-register.js +48 -9
  27. package/dist/lib/rendering/visuals-register.js.map +1 -1
  28. package/dist/lib/utils/cesium-entity-styler.js +5 -0
  29. package/dist/lib/utils/cesium-entity-styler.js.map +1 -1
  30. package/dist/types/bruce-cesium.d.ts +1 -1
  31. package/dist/types/rendering/render-managers/tilesets/tileset-arb-render-manager.d.ts +1 -0
  32. package/dist/types/rendering/render-managers/tilesets/tileset-cad-render-manager.d.ts +1 -0
  33. package/dist/types/rendering/render-managers/tilesets/tileset-entities-render-manager.d.ts +1 -0
  34. package/dist/types/rendering/render-managers/tilesets/tileset-google-photos-render-manager.d.ts +1 -0
  35. package/dist/types/rendering/render-managers/tilesets/tileset-osm-render-manager.d.ts +2 -0
  36. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  import * as Cesium from 'cesium';
2
- import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, ShaderSource, Cartesian3, Math as Math$1, Ellipsoid, Transforms, Matrix4, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, Cartesian2, Cartesian4, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, JulianDate, Quaternion, HeadingPitchRoll, HeightReference, ConstantPositionProperty, DistanceDisplayCondition, ColorBlendMode, ShadowMode, ClassificationType, Model, HorizontalOrigin, VerticalOrigin, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, ArcType, CornerType, Rectangle, SceneTransforms, FeatureDetection, NearFarScalar, Matrix3, KmlDataSource, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, HeadingPitchRange, Cesium3DTileColorBlendMode, Ion, IonResource, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Cesium3DTileset, OrthographicFrustum, EasingFunction, Intersect, CustomDataSource, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, GeometryInstance, PolygonPipeline, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, ScreenSpaceEventHandler, ScreenSpaceEventType, Fullscreen, CzmlDataSource } from 'cesium';
3
- import { Cartes, LRUCache, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, Entity as Entity$1, EntityLod, EntityTag, EntityType, ObjectUtils, Style, Api, Bounds, ClientFileValueMap, Color as Color$1, Geometry as Geometry$1, Carto, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, BruceEvent, EntityCoords, DataLab, DelayQueue, AccountConcept, RecordChangeFeed, BruceApi, EntityRelation, EntitySource, ProgramKey, ProjectViewLegacyTile, Camera, Account, AccountLimits, Session, UrlUtils, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, ProjectViewBookmarkGroup, EntityRelationType, EntityHistoricData } from 'bruce-models';
2
+ import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, ConstantPositionProperty, HeightReference, DistanceDisplayCondition, Math as Math$1, Cartesian3, JulianDate, Quaternion, Transforms, HeadingPitchRoll, Matrix4, HorizontalOrigin, VerticalOrigin, ClassificationType, ArcType, CornerType, ShadowMode, ColorBlendMode, Model, Ellipsoid, Cartesian2, SceneTransforms, ShaderSource, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, Cartesian4, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, FeatureDetection, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, NearFarScalar, Matrix3, KmlDataSource, GeoJsonDataSource, SceneMode, HeadingPitchRange, Ion, IonResource, Cesium3DTileStyle, Cesium3DTileColorBlendMode, Cesium3DTileset, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, OrthographicFrustum, EasingFunction, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, Intersect, PolygonPipeline, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, CustomDataSource, GeometryInstance, ScreenSpaceEventHandler, ScreenSpaceEventType, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, Fullscreen, CzmlDataSource } from 'cesium';
3
+ import { Cartes, LRUCache, ProjectViewTile, ENVIRONMENT, Api, Calculator, ClientFile, Entity as Entity$1, EntityTag, EntityType, ObjectUtils, Style, Carto, Geometry as Geometry$1, EntityLod, BruceEvent, EntityCoords, MenuItem, Tileset, ClientFileValueMap, Color as Color$1, ProjectView, ProjectViewBookmark, ZoomControl, Bounds, DataLab, DelayQueue, AccountConcept, EntityRelation, BruceApi, RecordChangeFeed, ProgramKey, ProjectViewLegacyTile, EntitySource, Camera, Account, AccountLimits, Session, UrlUtils, ProjectViewBookmarkGroup, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, EntityRelationType, EntityHistoricData } from 'bruce-models';
4
4
 
5
5
  /**
6
6
  * Ensures a number is returned from a given value.
@@ -1517,6 +1517,7 @@ function getPosition(viewer, obj) {
1517
1517
  * @returns
1518
1518
  */
1519
1519
  function isFeatureAlive(viewer, feature) {
1520
+ var _a, _b;
1520
1521
  if (!(viewer === null || viewer === void 0 ? void 0 : viewer.scene) || viewer.isDestroyed()) {
1521
1522
  return false;
1522
1523
  }
@@ -1527,6 +1528,10 @@ function isFeatureAlive(viewer, feature) {
1527
1528
  if (cTileset.isDestroyed() || !viewer.scene.primitives.contains(cTileset)) {
1528
1529
  return false;
1529
1530
  }
1531
+ // A tile unloads its content while the tileset lives on, and the feature's colour is then unreadable.
1532
+ if (feature._bruceUnloaded || ((_b = (_a = feature.content) === null || _a === void 0 ? void 0 : _a.isDestroyed) === null || _b === void 0 ? void 0 : _b.call(_a))) {
1533
+ return false;
1534
+ }
1530
1535
  return true;
1531
1536
  }
1532
1537
  let _lastMark = 0;
@@ -1717,7 +1722,17 @@ var CesiumAnimatedProperty;
1717
1722
  removal = null;
1718
1723
  return;
1719
1724
  }
1720
- if (!assertColorMark(mark, feature.color)) {
1725
+ // A throw here is inside Cesium's frame and stops rendering, so an unreadable feature ends the animation.
1726
+ let current;
1727
+ try {
1728
+ current = feature.color;
1729
+ }
1730
+ catch (e) {
1731
+ removal === null || removal === void 0 ? void 0 : removal();
1732
+ removal = null;
1733
+ return;
1734
+ }
1735
+ if (!assertColorMark(mark, current)) {
1721
1736
  removal === null || removal === void 0 ? void 0 : removal();
1722
1737
  removal = null;
1723
1738
  onDone === null || onDone === void 0 ? void 0 : onDone();
@@ -2936,6 +2951,7 @@ var CesiumAnimatedProperty;
2936
2951
  * @returns
2937
2952
  */
2938
2953
  function isAlive(viewer, visual) {
2954
+ var _a, _b;
2939
2955
  if (!(viewer === null || viewer === void 0 ? void 0 : viewer.scene) || viewer.isDestroyed()) {
2940
2956
  return false;
2941
2957
  }
@@ -2953,6 +2969,10 @@ function isAlive(viewer, visual) {
2953
2969
  if (cTileset.isDestroyed() || !viewer.scene.primitives.contains(cTileset)) {
2954
2970
  return false;
2955
2971
  }
2972
+ // Its tile unloaded, so reading or writing the feature's colour throws.
2973
+ if (visual._bruceUnloaded || ((_b = (_a = visual.content) === null || _a === void 0 ? void 0 : _a.isDestroyed) === null || _b === void 0 ? void 0 : _b.call(_a))) {
2974
+ return false;
2975
+ }
2956
2976
  return true;
2957
2977
  }
2958
2978
  return false;
@@ -5805,6 +5825,8 @@ var EntityLabel;
5805
5825
  this.element = document.createElement("div");
5806
5826
  this.coordinates = { x: 0, y: 0, scaleX: 1, scaleY: 1 };
5807
5827
  this.participants = new Set();
5828
+ // Participants whose failure has been logged, so a label that throws every frame logs once.
5829
+ this.failed = new WeakSet();
5808
5830
  this.placementMemory = new PlacementMemory();
5809
5831
  this.forwardingWheel = false;
5810
5832
  this.pendingDrag = null;
@@ -6005,15 +6027,35 @@ var EntityLabel;
6005
6027
  x: (pointer.x - rect.left) * this.viewer.canvas.clientWidth / rect.width,
6006
6028
  y: (pointer.y - rect.top) * this.viewer.canvas.clientHeight / rect.height
6007
6029
  } : undefined;
6030
+ // This runs inside Cesium's frame, where one throwing label would stop rendering for the whole scene.
6008
6031
  const projected = new Map();
6009
6032
  for (const participant of this.participants) {
6010
- projected.set(participant, participant.project());
6033
+ let frame = null;
6034
+ try {
6035
+ frame = participant.project();
6036
+ }
6037
+ catch (e) {
6038
+ this.logFailure(participant, e);
6039
+ }
6040
+ projected.set(participant, frame);
6011
6041
  }
6012
6042
  const placements = new Map(Layout(Array.from(projected.values()).filter(Boolean), this.placementMemory).map(item => [item.frame.id, item]));
6013
6043
  for (const [participant, frame] of projected) {
6014
- participant.apply(frame ? placements.get(frame.id) : undefined);
6044
+ try {
6045
+ participant.apply(frame ? placements.get(frame.id) : undefined);
6046
+ }
6047
+ catch (e) {
6048
+ this.logFailure(participant, e);
6049
+ }
6015
6050
  }
6016
6051
  }
6052
+ logFailure(participant, error) {
6053
+ if (this.failed.has(participant)) {
6054
+ return;
6055
+ }
6056
+ this.failed.add(participant);
6057
+ console.error("EntityLabel: a label failed to update and is skipped this frame.", error);
6058
+ }
6017
6059
  }
6018
6060
  let nextLabelId = 0;
6019
6061
  class Label {
@@ -9285,6 +9327,7 @@ var VisualRegisterCuller;
9285
9327
  })(VisualRegisterCuller || (VisualRegisterCuller = {}));
9286
9328
 
9287
9329
  function isTilesetFeatureAlive(visual) {
9330
+ var _a, _b;
9288
9331
  const cTileset = visual === null || visual === void 0 ? void 0 : visual.tileset;
9289
9332
  if (!cTileset) {
9290
9333
  return false;
@@ -9295,8 +9338,32 @@ function isTilesetFeatureAlive(visual) {
9295
9338
  else if (visual.primitive && visual.primitive.isDestroyed()) {
9296
9339
  return false;
9297
9340
  }
9341
+ // A tile unloads its content while the tileset lives on, and every read through the feature then throws.
9342
+ else if (visual._bruceUnloaded || ((_b = (_a = visual.content) === null || _a === void 0 ? void 0 : _a.isDestroyed) === null || _b === void 0 ? void 0 : _b.call(_a))) {
9343
+ return false;
9344
+ }
9298
9345
  return true;
9299
9346
  }
9347
+ /*
9348
+ * Returns if a visual is currently shown, reading a tileset feature only while its tile is loaded.
9349
+ */
9350
+ function isVisualShown(visual) {
9351
+ if (!visual) {
9352
+ return true;
9353
+ }
9354
+ if (visual instanceof Cesium3DTileFeature) {
9355
+ if (!isTilesetFeatureAlive(visual)) {
9356
+ return false;
9357
+ }
9358
+ try {
9359
+ return visual.show !== false;
9360
+ }
9361
+ catch (e) {
9362
+ return false;
9363
+ }
9364
+ }
9365
+ return visual.show !== false;
9366
+ }
9300
9367
  /**
9301
9368
  * Returns if a given visual is alive and in the scene.
9302
9369
  * @param viewer
@@ -9304,6 +9371,7 @@ function isTilesetFeatureAlive(visual) {
9304
9371
  * @returns
9305
9372
  */
9306
9373
  function isAlive$1(viewer, visual) {
9374
+ var _a, _b;
9307
9375
  if (!(viewer === null || viewer === void 0 ? void 0 : viewer.scene) || viewer.isDestroyed()) {
9308
9376
  return false;
9309
9377
  }
@@ -9324,6 +9392,10 @@ function isAlive$1(viewer, visual) {
9324
9392
  else if (visual.primitive && visual.primitive.isDestroyed()) {
9325
9393
  return false;
9326
9394
  }
9395
+ // Its tile unloaded, so every read through the feature throws.
9396
+ else if (visual._bruceUnloaded || ((_b = (_a = visual.content) === null || _a === void 0 ? void 0 : _a.isDestroyed) === null || _b === void 0 ? void 0 : _b.call(_a))) {
9397
+ return false;
9398
+ }
9327
9399
  return true;
9328
9400
  }
9329
9401
  return false;
@@ -9786,6 +9858,13 @@ var VisualsRegister;
9786
9858
  // Adding is asynchronous, so ordering has to wait until it is actually in the collection.
9787
9859
  Promise.resolve(this.viewer.dataSources.add(source))
9788
9860
  .then(() => {
9861
+ // Released or disposed before the add landed, when the remove found nothing to take out.
9862
+ if (this.menuItemSources.get(menuItemId) !== record) {
9863
+ if (!this.viewer.isDestroyed() && this.viewer.dataSources.contains(source)) {
9864
+ this.viewer.dataSources.remove(source, true);
9865
+ }
9866
+ return;
9867
+ }
9789
9868
  record.added = true;
9790
9869
  this.applySourceOrder();
9791
9870
  })
@@ -9822,7 +9901,9 @@ var VisualsRegister;
9822
9901
  if (this.disposed || !this.sourceOrderDirty || !((_a = this.viewer) === null || _a === void 0 ? void 0 : _a.dataSources)) {
9823
9902
  return;
9824
9903
  }
9825
- const records = Array.from(this.menuItemSources.values()).filter(x => x.added);
9904
+ // raiseToTop throws for a source the collection does not hold.
9905
+ const dataSources = this.viewer.dataSources;
9906
+ const records = Array.from(this.menuItemSources.values()).filter(x => x.added && dataSources.contains(x.source));
9826
9907
  if (records.length < 2) {
9827
9908
  // Nothing to order against yet, so leave the flag set for when there is.
9828
9909
  return;
@@ -9832,7 +9913,7 @@ var VisualsRegister;
9832
9913
  records.sort((a, b) => a.maxZIndex - b.maxZIndex);
9833
9914
  for (const record of records) {
9834
9915
  try {
9835
- this.viewer.dataSources.raiseToTop(record.source);
9916
+ dataSources.raiseToTop(record.source);
9836
9917
  }
9837
9918
  catch (e) {
9838
9919
  console.error(e);
@@ -12172,7 +12253,7 @@ var VisualsRegister;
12172
12253
  return (hover === null || hover === void 0 ? void 0 : hover.entityId) === entityId && (hover.menuItemId == null || hover.menuItemId === menuItemId) ? hover.position : undefined;
12173
12254
  }
12174
12255
  SyncLabelHover() {
12175
- var _a, _b, _c, _d;
12256
+ var _a, _b, _c;
12176
12257
  const hover = this.labelHover;
12177
12258
  if (!hover || this.disposed) {
12178
12259
  return;
@@ -12197,7 +12278,7 @@ var VisualsRegister;
12197
12278
  }
12198
12279
  const existing = rego && EntityLabel.GetLabel({ rego });
12199
12280
  const state = this.GetState(hover);
12200
- if ((!rego && !group) || state.hidden || ((_b = rego === null || rego === void 0 ? void 0 : rego.visual) === null || _b === void 0 ? void 0 : _b.show) === false ||
12281
+ if ((!rego && !group) || state.hidden || ((rego === null || rego === void 0 ? void 0 : rego.visual) && !isVisualShown(rego.visual)) ||
12201
12282
  (this.GetIsIsolatedAny() && !state.isolated && this.GetIsolationOpacity() == null) ||
12202
12283
  (existing && existing !== this.hoverLabel && existing.HasText) ||
12203
12284
  (group && group.options.presentation !== "icon")) {
@@ -12209,7 +12290,7 @@ var VisualsRegister;
12209
12290
  return;
12210
12291
  }
12211
12292
  // Query-only icon groups have coordinates but no registered scene visual to attach to.
12212
- if (!rego && group && [group.item.longitude, group.item.latitude, (_c = group.item.altitude) !== null && _c !== void 0 ? _c : 0].every(Number.isFinite)) {
12293
+ if (!rego && group && [group.item.longitude, group.item.latitude, (_b = group.item.altitude) !== null && _b !== void 0 ? _b : 0].every(Number.isFinite)) {
12213
12294
  rego = {
12214
12295
  entityId: hover.entityId,
12215
12296
  menuItemId: hover.menuItemId,
@@ -12231,7 +12312,7 @@ var VisualsRegister;
12231
12312
  rego,
12232
12313
  viewer: this.viewer,
12233
12314
  visualRegister: this,
12234
- api: (_d = this.ApiGetters) === null || _d === void 0 ? void 0 : _d.GetBruceApi(),
12315
+ api: (_c = this.ApiGetters) === null || _c === void 0 ? void 0 : _c.GetBruceApi(),
12235
12316
  persistent: false,
12236
12317
  transient: true,
12237
12318
  hoverRingState: this.hoverRingState,
@@ -12241,10 +12322,10 @@ var VisualsRegister;
12241
12322
  selectOnClick: false
12242
12323
  },
12243
12324
  visible: () => {
12244
- var _a, _b;
12325
+ var _a;
12245
12326
  const current = this.GetState(hover);
12246
- return (!this.disposed && !current.hidden && ((_a = rego.visual) === null || _a === void 0 ? void 0 : _a.show) !== false &&
12247
- Boolean(this.GetRego(hover) || ((_b = this.labelGroups) === null || _b === void 0 ? void 0 : _b.Has(hover.entityId, hover.menuItemId))) &&
12327
+ return (!this.disposed && !current.hidden && isVisualShown(rego.visual) &&
12328
+ Boolean(this.GetRego(hover) || ((_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.Has(hover.entityId, hover.menuItemId))) &&
12248
12329
  (!this.GetIsIsolatedAny() || current.isolated || this.GetIsolationOpacity() != null));
12249
12330
  }
12250
12331
  };
@@ -14864,12 +14945,20 @@ var EntitiesRenderManager;
14864
14945
  strokeWidth: lineWidthPx,
14865
14946
  clampToGround: lineWidthPx <= 0 && polygonsClamped
14866
14947
  });
14867
- this.viewer.dataSources.add(source);
14868
- this.sources.push(source);
14869
- if (this.disposed) {
14870
- this.doDispose();
14948
+ // Dispose already cleared what was added before this, and this one has not been added.
14949
+ if (this.disposed || this.viewer.isDestroyed()) {
14871
14950
  return;
14872
14951
  }
14952
+ const viewer = this.viewer;
14953
+ this.sources.push(source);
14954
+ // The add lands asynchronously, so a dispose in between removes nothing and would orphan the source.
14955
+ Promise.resolve(viewer.dataSources.add(source)).then(() => {
14956
+ if (this.disposed && !viewer.isDestroyed() && viewer.dataSources.contains(source)) {
14957
+ viewer.dataSources.remove(source);
14958
+ }
14959
+ }).catch((e) => {
14960
+ console.error(e);
14961
+ });
14873
14962
  const groups = [];
14874
14963
  /**
14875
14964
  * Applies individual styling to a rendered entity.
@@ -15911,12 +16000,20 @@ var EntitiesLoadedRenderManager;
15911
16000
  strokeWidth: lineWidthPx,
15912
16001
  clampToGround: lineWidthPx <= 0 && polygonsClamped
15913
16002
  });
15914
- this.viewer.dataSources.add(source);
15915
- this.sources.push(source);
15916
- if (this.disposed) {
15917
- this.doDispose();
16003
+ // Dispose already cleared what was added before this, and this one has not been added.
16004
+ if (this.disposed || this.viewer.isDestroyed()) {
15918
16005
  return;
15919
16006
  }
16007
+ const viewer = this.viewer;
16008
+ this.sources.push(source);
16009
+ // The add lands asynchronously, so a dispose in between removes nothing and would orphan the source.
16010
+ Promise.resolve(viewer.dataSources.add(source)).then(() => {
16011
+ if (this.disposed && !viewer.isDestroyed() && viewer.dataSources.contains(source)) {
16012
+ viewer.dataSources.remove(source);
16013
+ }
16014
+ }).catch((e) => {
16015
+ console.error(e);
16016
+ });
15920
16017
  const groups = [];
15921
16018
  /**
15922
16019
  * Applies individual styling to a rendered entity.
@@ -19611,7 +19708,7 @@ var TilesetCadRenderManager;
19611
19708
  });
19612
19709
  this.tileUnloadRemoval = cTileset.tileUnload.addEventListener((tile) => {
19613
19710
  try {
19614
- this.queueTile(tile, false);
19711
+ this.unloadTile(tile);
19615
19712
  }
19616
19713
  catch (e) {
19617
19714
  console.error(e);
@@ -19795,7 +19892,7 @@ var TilesetCadRenderManager;
19795
19892
  });
19796
19893
  this.tileUnloadRemoval = this.cTileset.tileUnload.addEventListener((tile) => {
19797
19894
  try {
19798
- this.queueTile(tile, false);
19895
+ this.unloadTile(tile);
19799
19896
  }
19800
19897
  catch (e) {
19801
19898
  console.error(e);
@@ -19860,6 +19957,35 @@ var TilesetCadRenderManager;
19860
19957
  }
19861
19958
  this.pingFeatureQueue();
19862
19959
  }
19960
+ /*
19961
+ * Removes a tile's regos and marks its features dead, while the tile's content can still be read.
19962
+ */
19963
+ unloadTile(tile) {
19964
+ const content = tile === null || tile === void 0 ? void 0 : tile.content;
19965
+ if (!content) {
19966
+ return;
19967
+ }
19968
+ const features = [];
19969
+ for (let i = 0; i < content.featuresLength; i++) {
19970
+ const feature = content.getFeature(i);
19971
+ // Drops a load still queued for it, the batch skips anything marked.
19972
+ this.featureQueueStates.delete(feature);
19973
+ feature._bruceUnloaded = true;
19974
+ features.push(feature);
19975
+ }
19976
+ if (!features.length) {
19977
+ return;
19978
+ }
19979
+ const { removedEntityIds } = this.visualsManager.RemoveRegosByVisuals({
19980
+ visuals: features,
19981
+ requestRender: false,
19982
+ menuItemId: this.item.id,
19983
+ doRemove: false
19984
+ });
19985
+ for (const entityId of removedEntityIds) {
19986
+ delete this.loadedCesiumEntities[entityId];
19987
+ }
19988
+ }
19863
19989
  /**
19864
19990
  * Pings the feature queue to process any queued features.
19865
19991
  * Does nothing if we're already processing.
@@ -19876,7 +20002,7 @@ var TilesetCadRenderManager;
19876
20002
  return;
19877
20003
  }
19878
20004
  this.processFeatureQueueBatch();
19879
- if (!this.featureQueue) {
20005
+ if (!this.featureQueue.length) {
19880
20006
  clearInterval(this.featureQueueInterval);
19881
20007
  this.featureQueueInterval = null;
19882
20008
  }
@@ -19908,6 +20034,10 @@ var TilesetCadRenderManager;
19908
20034
  const regosToStyle = new Map();
19909
20035
  const featuresToRemove = [];
19910
20036
  for (const feature of batch) {
20037
+ // Its tile unloaded while it waited, unloadTile already removed whatever it registered.
20038
+ if (feature._bruceUnloaded) {
20039
+ continue;
20040
+ }
19911
20041
  const load = this.featureQueueStates.get(feature);
19912
20042
  this.featureQueueStates.delete(feature);
19913
20043
  if (!load) {
@@ -23080,6 +23210,7 @@ var TilesetOsmRenderManager;
23080
23210
  this.processingQueue = 0;
23081
23211
  this._osmIdToBruceId = {};
23082
23212
  this.tileLoadRemoval = null;
23213
+ this.tileUnloadRemoval = null;
23083
23214
  const { viewer, register: visualsManager, getters: apiGetter, monitor, item } = params;
23084
23215
  this.viewer = viewer;
23085
23216
  this.getters = apiGetter;
@@ -23088,7 +23219,7 @@ var TilesetOsmRenderManager;
23088
23219
  this.monitor = monitor;
23089
23220
  }
23090
23221
  Dispose() {
23091
- var _a;
23222
+ var _a, _b;
23092
23223
  if (this.disposed) {
23093
23224
  return;
23094
23225
  }
@@ -23096,6 +23227,8 @@ var TilesetOsmRenderManager;
23096
23227
  clearInterval(this.queueCheckInterval);
23097
23228
  (_a = this.tileLoadRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
23098
23229
  this.tileLoadRemoval = null;
23230
+ (_b = this.tileUnloadRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
23231
+ this.tileUnloadRemoval = null;
23099
23232
  if (this.cTileset) {
23100
23233
  const viewer = this.viewer;
23101
23234
  if (!(viewer === null || viewer === void 0 ? void 0 : viewer.isDestroyed()) && this.viewer.scene.primitives.contains(this.cTileset)) {
@@ -23191,6 +23324,14 @@ var TilesetOsmRenderManager;
23191
23324
  console.error(e);
23192
23325
  }
23193
23326
  });
23327
+ this.tileUnloadRemoval = this.cTileset.tileUnload.addEventListener((tile) => {
23328
+ try {
23329
+ this.unloadTile(tile);
23330
+ }
23331
+ catch (e) {
23332
+ console.error(e);
23333
+ }
23334
+ });
23194
23335
  this.queueCheckInterval = setInterval(() => {
23195
23336
  if (this.featureQueue.length > 0) {
23196
23337
  this.processQueue();
@@ -23227,6 +23368,34 @@ var TilesetOsmRenderManager;
23227
23368
  this.processQueue();
23228
23369
  }
23229
23370
  }
23371
+ /*
23372
+ * Removes a tile's regos and marks its features dead, while the tile's content can still be read.
23373
+ */
23374
+ unloadTile(tile) {
23375
+ const content = tile === null || tile === void 0 ? void 0 : tile.content;
23376
+ if (!content) {
23377
+ return;
23378
+ }
23379
+ const features = [];
23380
+ for (let i = 0; i < content.featuresLength; i++) {
23381
+ const feature = content.getFeature(i);
23382
+ feature._bruceUnloaded = true;
23383
+ features.push(feature);
23384
+ }
23385
+ if (!features.length) {
23386
+ return;
23387
+ }
23388
+ this.featureQueue = this.featureQueue.filter(x => !x._bruceUnloaded);
23389
+ const { removedEntityIds } = this.visualsManager.RemoveRegosByVisuals({
23390
+ visuals: features,
23391
+ requestRender: false,
23392
+ menuItemId: this.item.id,
23393
+ doRemove: false
23394
+ });
23395
+ for (const entityId of removedEntityIds) {
23396
+ delete this._loadedCesiumEntities[entityId];
23397
+ }
23398
+ }
23230
23399
  async processQueue() {
23231
23400
  if (this.processingQueue >= MAX_BATCHES) {
23232
23401
  return;
@@ -23359,6 +23528,10 @@ var TilesetOsmRenderManager;
23359
23528
  bruceId = ObjectUtils.UId();
23360
23529
  }
23361
23530
  const feature = featureMap[i];
23531
+ // Its tile unloaded while the ID lookup was in flight.
23532
+ if (feature._bruceUnloaded) {
23533
+ continue;
23534
+ }
23362
23535
  if (this.item.ghostLoading == true) {
23363
23536
  feature.color = feature._orgColor;
23364
23537
  }
@@ -23450,7 +23623,7 @@ var TilesetOsmRenderManager;
23450
23623
  return `osm:${sourceId}:${entityTypeId}`;
23451
23624
  }
23452
23625
  PrepareHandoff() {
23453
- var _a;
23626
+ var _a, _b;
23454
23627
  if (this.disposed || !this.cTileset || this.cTileset.isDestroyed()) {
23455
23628
  return null;
23456
23629
  }
@@ -23458,6 +23631,8 @@ var TilesetOsmRenderManager;
23458
23631
  this.queueCheckInterval = null;
23459
23632
  (_a = this.tileLoadRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
23460
23633
  this.tileLoadRemoval = null;
23634
+ (_b = this.tileUnloadRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
23635
+ this.tileUnloadRemoval = null;
23461
23636
  const payload = {
23462
23637
  cTileset: this.cTileset,
23463
23638
  loadedCesiumEntities: this._loadedCesiumEntities,
@@ -23505,6 +23680,14 @@ var TilesetOsmRenderManager;
23505
23680
  console.error(e);
23506
23681
  }
23507
23682
  });
23683
+ this.tileUnloadRemoval = this.cTileset.tileUnload.addEventListener((tile) => {
23684
+ try {
23685
+ this.unloadTile(tile);
23686
+ }
23687
+ catch (e) {
23688
+ console.error(e);
23689
+ }
23690
+ });
23508
23691
  this.queueCheckInterval = setInterval(() => {
23509
23692
  if (this.featureQueue.length > 0) {
23510
23693
  this.processQueue();
@@ -23695,7 +23878,7 @@ var TilesetEntitiesRenderManager;
23695
23878
  });
23696
23879
  this.tileUnloadRemoval = cTileset.tileUnload.addEventListener((tile) => {
23697
23880
  try {
23698
- this.queueTile(tile, false);
23881
+ this.unloadTile(tile);
23699
23882
  }
23700
23883
  catch (e) {
23701
23884
  console.error(e);
@@ -23741,6 +23924,35 @@ var TilesetEntitiesRenderManager;
23741
23924
  }
23742
23925
  this.pingFeatureQueue();
23743
23926
  }
23927
+ /*
23928
+ * Removes a tile's regos and marks its features dead, while the tile's content can still be read.
23929
+ */
23930
+ unloadTile(tile) {
23931
+ const content = tile === null || tile === void 0 ? void 0 : tile.content;
23932
+ if (!content) {
23933
+ return;
23934
+ }
23935
+ const features = [];
23936
+ for (let i = 0; i < content.featuresLength; i++) {
23937
+ const feature = content.getFeature(i);
23938
+ // Drops a load still queued for it, the batch skips anything marked.
23939
+ this.featureQueueStates.delete(feature);
23940
+ feature._bruceUnloaded = true;
23941
+ features.push(feature);
23942
+ }
23943
+ if (!features.length) {
23944
+ return;
23945
+ }
23946
+ const { removedEntityIds } = this.visualsManager.RemoveRegosByVisuals({
23947
+ visuals: features,
23948
+ requestRender: false,
23949
+ menuItemId: this.item.id,
23950
+ doRemove: false
23951
+ });
23952
+ for (const entityId of removedEntityIds) {
23953
+ delete this.loadedCesiumEntities[entityId];
23954
+ }
23955
+ }
23744
23956
  /**
23745
23957
  * Pings the feature queue to process any queued features.
23746
23958
  * Does nothing if we're already processing.
@@ -23757,7 +23969,7 @@ var TilesetEntitiesRenderManager;
23757
23969
  return;
23758
23970
  }
23759
23971
  this.processFeatureQueueBatch();
23760
- if (!this.featureQueue) {
23972
+ if (!this.featureQueue.length) {
23761
23973
  clearInterval(this.featureQueueInterval);
23762
23974
  this.featureQueueInterval = null;
23763
23975
  }
@@ -23775,6 +23987,10 @@ var TilesetEntitiesRenderManager;
23775
23987
  const regosToStyle = new Map();
23776
23988
  const featuresToRemove = [];
23777
23989
  for (const feature of batch) {
23990
+ // Its tile unloaded while it waited, unloadTile already removed whatever it registered.
23991
+ if (feature._bruceUnloaded) {
23992
+ continue;
23993
+ }
23778
23994
  const load = this.featureQueueStates.get(feature);
23779
23995
  this.featureQueueStates.delete(feature);
23780
23996
  if (!load) {
@@ -23980,7 +24196,7 @@ var TilesetEntitiesRenderManager;
23980
24196
  });
23981
24197
  this.tileUnloadRemoval = this.cTileset.tileUnload.addEventListener((tile) => {
23982
24198
  try {
23983
- this.queueTile(tile, false);
24199
+ this.unloadTile(tile);
23984
24200
  }
23985
24201
  catch (e) {
23986
24202
  console.error(e);
@@ -24941,7 +25157,7 @@ var TilesetArbRenderManager;
24941
25157
  });
24942
25158
  this.cTileset.tileUnload.addEventListener((tile) => {
24943
25159
  try {
24944
- this.queueTile(tile, false);
25160
+ this.unloadTile(tile);
24945
25161
  }
24946
25162
  catch (e) {
24947
25163
  console.error(e);
@@ -24969,6 +25185,35 @@ var TilesetArbRenderManager;
24969
25185
  }
24970
25186
  this.pingFeatureQueue();
24971
25187
  }
25188
+ /*
25189
+ * Removes a tile's regos and marks its features dead, while the tile's content can still be read.
25190
+ */
25191
+ unloadTile(tile) {
25192
+ const content = tile === null || tile === void 0 ? void 0 : tile.content;
25193
+ if (!content) {
25194
+ return;
25195
+ }
25196
+ const features = [];
25197
+ for (let i = 0; i < content.featuresLength; i++) {
25198
+ const feature = content.getFeature(i);
25199
+ // Drops a load still queued for it, the batch skips anything marked.
25200
+ this.featureQueueStates.delete(feature);
25201
+ feature._bruceUnloaded = true;
25202
+ features.push(feature);
25203
+ }
25204
+ if (!features.length) {
25205
+ return;
25206
+ }
25207
+ const { removedEntityIds } = this.visualsManager.RemoveRegosByVisuals({
25208
+ visuals: features,
25209
+ requestRender: false,
25210
+ menuItemId: this.item.id,
25211
+ doRemove: false
25212
+ });
25213
+ for (const entityId of removedEntityIds) {
25214
+ delete this.loadedCesiumEntities[entityId];
25215
+ }
25216
+ }
24972
25217
  /**
24973
25218
  * Pings the feature queue to process any queued features.
24974
25219
  * Does nothing if we're already processing.
@@ -24985,7 +25230,7 @@ var TilesetArbRenderManager;
24985
25230
  return;
24986
25231
  }
24987
25232
  this.processFeatureQueueBatch();
24988
- if (!this.featureQueue) {
25233
+ if (!this.featureQueue.length) {
24989
25234
  clearInterval(this.featureQueueInterval);
24990
25235
  this.featureQueueInterval = null;
24991
25236
  }
@@ -25003,6 +25248,10 @@ var TilesetArbRenderManager;
25003
25248
  const regosToStyle = new Map();
25004
25249
  const featuresToRemove = [];
25005
25250
  for (const feature of batch) {
25251
+ // Its tile unloaded while it waited, unloadTile already removed whatever it registered.
25252
+ if (feature._bruceUnloaded) {
25253
+ continue;
25254
+ }
25006
25255
  const load = this.featureQueueStates.get(feature);
25007
25256
  this.featureQueueStates.delete(feature);
25008
25257
  if (!load) {
@@ -25621,6 +25870,8 @@ var TilesetGooglePhotosRenderManager;
25621
25870
  constructor(params) {
25622
25871
  this.disposed = false;
25623
25872
  this.cTileset = null;
25873
+ // Set while a tileset is being created, so a second Init in the meantime cannot add another.
25874
+ this.initializing = false;
25624
25875
  const { viewer, item, getters } = params;
25625
25876
  this.viewer = viewer;
25626
25877
  this.item = item;
@@ -25641,6 +25892,10 @@ var TilesetGooglePhotosRenderManager;
25641
25892
  this.viewer.scene.primitives.remove(this.cTileset);
25642
25893
  this.viewer.scene.requestRender();
25643
25894
  }
25895
+ // Disposed before it was added, so nothing else will ever destroy it.
25896
+ else if (!this.cTileset.isDestroyed()) {
25897
+ this.cTileset.destroy();
25898
+ }
25644
25899
  this.cTileset = null;
25645
25900
  }
25646
25901
  }
@@ -25659,6 +25914,11 @@ var TilesetGooglePhotosRenderManager;
25659
25914
  this.viewer.scene.requestRender();
25660
25915
  return;
25661
25916
  }
25917
+ // The creation in flight applies the latest item's colour mask when it lands.
25918
+ if (this.initializing) {
25919
+ return;
25920
+ }
25921
+ this.initializing = true;
25662
25922
  try {
25663
25923
  const api = this.getters.GetBruceApi();
25664
25924
  await api.Loading;
@@ -25744,6 +26004,14 @@ var TilesetGooglePhotosRenderManager;
25744
26004
  console.error("Failed to load Google Photorealistic 3D tileset:", e);
25745
26005
  return;
25746
26006
  }
26007
+ finally {
26008
+ this.initializing = false;
26009
+ }
26010
+ // Creation can come back empty, and the viewer can go while it loads.
26011
+ if (this.disposed || !this.cTileset || this.cTileset.isDestroyed() || !this.viewer || this.viewer.isDestroyed()) {
26012
+ this.doDispose();
26013
+ return;
26014
+ }
25747
26015
  this.viewer.scene.primitives.add(this.cTileset);
25748
26016
  this.applyColorMask();
25749
26017
  this.viewer.scene.requestRender();
@@ -43234,7 +43502,8 @@ var EntityRenderEngineModel3d;
43234
43502
  const hpr = new HeadingPitchRoll(Math$1.toRadians(heading), Math$1.toRadians(pitch), Math$1.toRadians(roll));
43235
43503
  getOrient = new CallbackProperty(() => {
43236
43504
  const currentPos = position ? GetCValue(params.viewer, position) : pos3d;
43237
- return Transforms.headingPitchRollQuaternion(currentPos, hpr);
43505
+ // A live position can read as null mid-update, and throwing here would stop Cesium's frame.
43506
+ return Transforms.headingPitchRollQuaternion(currentPos || pos3d, hpr);
43238
43507
  }, false);
43239
43508
  }
43240
43509
  cEntity = new Entity({
@@ -50574,7 +50843,7 @@ var StyleUtils;
50574
50843
  StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
50575
50844
  })(StyleUtils || (StyleUtils = {}));
50576
50845
 
50577
- const VERSION = "7.4.5";
50846
+ const VERSION = "7.4.6";
50578
50847
  /**
50579
50848
  * Updates the environment instance used by bruce-cesium to one specified.
50580
50849
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.