bruce-cesium 7.4.5 → 7.4.7

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 +344 -35
  2. package/dist/bruce-cesium.es5.js.map +1 -1
  3. package/dist/bruce-cesium.umd.js +342 -33
  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 +65 -3
  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, 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, HeightReference, ColorBlendMode, HeadingPitchRoll, ShadowMode, ClassificationType, Model, HorizontalOrigin, VerticalOrigin, ConstantPositionProperty, ArcType, CornerType, JulianDate, Quaternion, ImageMaterialProperty, DistanceDisplayCondition, PolygonHierarchy, PolylineGraphics, Rectangle, SceneTransforms, NearFarScalar, Matrix3, KmlDataSource, FeatureDetection, SceneMode, GeoJsonDataSource, Ion, IonResource, Cesium3DTileStyle, HeadingPitchRange, Cesium3DTileset, OrthographicFrustum, EasingFunction, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Cesium3DTileColorBlendMode, Intersect, PolygonPipeline, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, ScreenSpaceEventHandler, ScreenSpaceEventType, GeometryInstance, Fullscreen, CustomDataSource, CzmlDataSource } from 'cesium';
3
+ import { Cartes, LRUCache, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, Entity as Entity$1, EntityLod, EntityTag, EntityType, ObjectUtils, Style, Api, Carto, Geometry as Geometry$1, ClientFileValueMap, Color as Color$1, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, BruceEvent, EntityCoords, Bounds, DataLab, DelayQueue, AccountConcept, EntityRelation, BruceApi, RecordChangeFeed, EntitySource, Camera, ProgramKey, ProjectViewLegacyTile, Account, AccountLimits, Session, UrlUtils, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, ProjectViewBookmarkGroup, 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,9 +5825,14 @@ 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;
5833
+ // Null outside a 3D view.
5834
+ this.horizon = null;
5835
+ this.horizonScratch = new Cartesian3();
5811
5836
  this.TrackPointer = (event) => {
5812
5837
  var _a, _b;
5813
5838
  if (event.pointerType && event.pointerType !== "mouse" && event.pointerType !== "pen")
@@ -5995,9 +6020,45 @@ var EntityLabel;
5995
6020
  }
5996
6021
  };
5997
6022
  }
6023
+ /*
6024
+ * Whether the globe hides a position; labels skip the depth test, so this is their only occluder.
6025
+ */
6026
+ IsBeyondHorizon(position) {
6027
+ if (!this.horizon) {
6028
+ return false;
6029
+ }
6030
+ const { ellipsoid, camera, limbSquared } = this.horizon;
6031
+ // Scaled space makes the ellipsoid a unit sphere.
6032
+ const scaled = ellipsoid.transformPositionToScaledSpace(position, this.horizonScratch);
6033
+ const magnitudeSquared = Cartesian3.magnitudeSquared(scaled);
6034
+ // Test sub-sea-level points from the surface.
6035
+ if (magnitudeSquared > 0 && magnitudeSquared < 1) {
6036
+ Cartesian3.normalize(scaled, scaled);
6037
+ }
6038
+ const toPoint = Cartesian3.subtract(scaled, camera, scaled);
6039
+ const along = -Cartesian3.dot(toPoint, camera);
6040
+ return along > limbSquared && along * along / Cartesian3.magnitudeSquared(toPoint) > limbSquared;
6041
+ }
6042
+ UpdateHorizon() {
6043
+ var _a, _b, _c;
6044
+ const scene = this.viewer.scene;
6045
+ const position = ((_a = scene === null || scene === void 0 ? void 0 : scene.camera) === null || _a === void 0 ? void 0 : _a.positionWC) || ((_b = scene === null || scene === void 0 ? void 0 : scene.camera) === null || _b === void 0 ? void 0 : _b.position);
6046
+ this.horizon = null;
6047
+ if ((scene === null || scene === void 0 ? void 0 : scene.mode) !== SceneMode.SCENE3D || !Number.isFinite(position === null || position === void 0 ? void 0 : position.x)) {
6048
+ return;
6049
+ }
6050
+ const ellipsoid = ((_c = scene.globe) === null || _c === void 0 ? void 0 : _c.ellipsoid) || Ellipsoid.WGS84;
6051
+ const camera = ellipsoid.transformPositionToScaledSpace(position, new Cartesian3());
6052
+ const limbSquared = Cartesian3.magnitudeSquared(camera) - 1;
6053
+ // No horizon from underground.
6054
+ if (limbSquared > 0) {
6055
+ this.horizon = { ellipsoid, camera, limbSquared };
6056
+ }
6057
+ }
5998
6058
  Update() {
5999
6059
  var _a, _b;
6000
6060
  this.coordinates = this.MeasureCoordinates();
6061
+ this.UpdateHorizon();
6001
6062
  const rect = (_b = (_a = this.viewer.canvas).getBoundingClientRect) === null || _b === void 0 ? void 0 : _b.call(_a);
6002
6063
  const pointer = this.pointerClient;
6003
6064
  this.pointer = pointer && (rect === null || rect === void 0 ? void 0 : rect.width) && (rect === null || rect === void 0 ? void 0 : rect.height) && pointer.x >= rect.left && pointer.x < rect.right && pointer.y >= rect.top && pointer.y < rect.bottom ?
@@ -6005,15 +6066,35 @@ var EntityLabel;
6005
6066
  x: (pointer.x - rect.left) * this.viewer.canvas.clientWidth / rect.width,
6006
6067
  y: (pointer.y - rect.top) * this.viewer.canvas.clientHeight / rect.height
6007
6068
  } : undefined;
6069
+ // This runs inside Cesium's frame, where one throwing label would stop rendering for the whole scene.
6008
6070
  const projected = new Map();
6009
6071
  for (const participant of this.participants) {
6010
- projected.set(participant, participant.project());
6072
+ let frame = null;
6073
+ try {
6074
+ frame = participant.project();
6075
+ }
6076
+ catch (e) {
6077
+ this.logFailure(participant, e);
6078
+ }
6079
+ projected.set(participant, frame);
6011
6080
  }
6012
6081
  const placements = new Map(Layout(Array.from(projected.values()).filter(Boolean), this.placementMemory).map(item => [item.frame.id, item]));
6013
6082
  for (const [participant, frame] of projected) {
6014
- participant.apply(frame ? placements.get(frame.id) : undefined);
6083
+ try {
6084
+ participant.apply(frame ? placements.get(frame.id) : undefined);
6085
+ }
6086
+ catch (e) {
6087
+ this.logFailure(participant, e);
6088
+ }
6015
6089
  }
6016
6090
  }
6091
+ logFailure(participant, error) {
6092
+ if (this.failed.has(participant)) {
6093
+ return;
6094
+ }
6095
+ this.failed.add(participant);
6096
+ console.error("EntityLabel: a label failed to update and is skipped this frame.", error);
6097
+ }
6017
6098
  }
6018
6099
  let nextLabelId = 0;
6019
6100
  class Label {
@@ -6752,7 +6833,8 @@ var EntityLabel;
6752
6833
  // If we're labelling from a temp label (mouse hover) don't drive opacity by cam distance.
6753
6834
  const hoverOnly = this.Transient && !this.Persistent;
6754
6835
  if (!Number.isFinite(distance) || depth <= 0 || distance < ((_c = this.options.near) !== null && _c !== void 0 ? _c : 0) ||
6755
- distance > ((_d = this.options.far) !== null && _d !== void 0 ? _d : Infinity) || (!this.prePositioned && !hoverOnly && distance >= MAX_DISTANCE)) {
6836
+ distance > ((_d = this.options.far) !== null && _d !== void 0 ? _d : Infinity) || (!this.prePositioned && !hoverOnly && distance >= MAX_DISTANCE) ||
6837
+ layer.IsBeyondHorizon(this._pos3d)) {
6756
6838
  return null;
6757
6839
  }
6758
6840
  const transforms = SceneTransforms;
@@ -9285,6 +9367,7 @@ var VisualRegisterCuller;
9285
9367
  })(VisualRegisterCuller || (VisualRegisterCuller = {}));
9286
9368
 
9287
9369
  function isTilesetFeatureAlive(visual) {
9370
+ var _a, _b;
9288
9371
  const cTileset = visual === null || visual === void 0 ? void 0 : visual.tileset;
9289
9372
  if (!cTileset) {
9290
9373
  return false;
@@ -9295,8 +9378,32 @@ function isTilesetFeatureAlive(visual) {
9295
9378
  else if (visual.primitive && visual.primitive.isDestroyed()) {
9296
9379
  return false;
9297
9380
  }
9381
+ // A tile unloads its content while the tileset lives on, and every read through the feature then throws.
9382
+ 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))) {
9383
+ return false;
9384
+ }
9298
9385
  return true;
9299
9386
  }
9387
+ /*
9388
+ * Returns if a visual is currently shown, reading a tileset feature only while its tile is loaded.
9389
+ */
9390
+ function isVisualShown(visual) {
9391
+ if (!visual) {
9392
+ return true;
9393
+ }
9394
+ if (visual instanceof Cesium3DTileFeature) {
9395
+ if (!isTilesetFeatureAlive(visual)) {
9396
+ return false;
9397
+ }
9398
+ try {
9399
+ return visual.show !== false;
9400
+ }
9401
+ catch (e) {
9402
+ return false;
9403
+ }
9404
+ }
9405
+ return visual.show !== false;
9406
+ }
9300
9407
  /**
9301
9408
  * Returns if a given visual is alive and in the scene.
9302
9409
  * @param viewer
@@ -9304,6 +9411,7 @@ function isTilesetFeatureAlive(visual) {
9304
9411
  * @returns
9305
9412
  */
9306
9413
  function isAlive$1(viewer, visual) {
9414
+ var _a, _b;
9307
9415
  if (!(viewer === null || viewer === void 0 ? void 0 : viewer.scene) || viewer.isDestroyed()) {
9308
9416
  return false;
9309
9417
  }
@@ -9324,6 +9432,10 @@ function isAlive$1(viewer, visual) {
9324
9432
  else if (visual.primitive && visual.primitive.isDestroyed()) {
9325
9433
  return false;
9326
9434
  }
9435
+ // Its tile unloaded, so every read through the feature throws.
9436
+ 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))) {
9437
+ return false;
9438
+ }
9327
9439
  return true;
9328
9440
  }
9329
9441
  return false;
@@ -9786,6 +9898,13 @@ var VisualsRegister;
9786
9898
  // Adding is asynchronous, so ordering has to wait until it is actually in the collection.
9787
9899
  Promise.resolve(this.viewer.dataSources.add(source))
9788
9900
  .then(() => {
9901
+ // Released or disposed before the add landed, when the remove found nothing to take out.
9902
+ if (this.menuItemSources.get(menuItemId) !== record) {
9903
+ if (!this.viewer.isDestroyed() && this.viewer.dataSources.contains(source)) {
9904
+ this.viewer.dataSources.remove(source, true);
9905
+ }
9906
+ return;
9907
+ }
9789
9908
  record.added = true;
9790
9909
  this.applySourceOrder();
9791
9910
  })
@@ -9822,7 +9941,9 @@ var VisualsRegister;
9822
9941
  if (this.disposed || !this.sourceOrderDirty || !((_a = this.viewer) === null || _a === void 0 ? void 0 : _a.dataSources)) {
9823
9942
  return;
9824
9943
  }
9825
- const records = Array.from(this.menuItemSources.values()).filter(x => x.added);
9944
+ // raiseToTop throws for a source the collection does not hold.
9945
+ const dataSources = this.viewer.dataSources;
9946
+ const records = Array.from(this.menuItemSources.values()).filter(x => x.added && dataSources.contains(x.source));
9826
9947
  if (records.length < 2) {
9827
9948
  // Nothing to order against yet, so leave the flag set for when there is.
9828
9949
  return;
@@ -9832,7 +9953,7 @@ var VisualsRegister;
9832
9953
  records.sort((a, b) => a.maxZIndex - b.maxZIndex);
9833
9954
  for (const record of records) {
9834
9955
  try {
9835
- this.viewer.dataSources.raiseToTop(record.source);
9956
+ dataSources.raiseToTop(record.source);
9836
9957
  }
9837
9958
  catch (e) {
9838
9959
  console.error(e);
@@ -12172,7 +12293,7 @@ var VisualsRegister;
12172
12293
  return (hover === null || hover === void 0 ? void 0 : hover.entityId) === entityId && (hover.menuItemId == null || hover.menuItemId === menuItemId) ? hover.position : undefined;
12173
12294
  }
12174
12295
  SyncLabelHover() {
12175
- var _a, _b, _c, _d;
12296
+ var _a, _b, _c;
12176
12297
  const hover = this.labelHover;
12177
12298
  if (!hover || this.disposed) {
12178
12299
  return;
@@ -12197,7 +12318,7 @@ var VisualsRegister;
12197
12318
  }
12198
12319
  const existing = rego && EntityLabel.GetLabel({ rego });
12199
12320
  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 ||
12321
+ if ((!rego && !group) || state.hidden || ((rego === null || rego === void 0 ? void 0 : rego.visual) && !isVisualShown(rego.visual)) ||
12201
12322
  (this.GetIsIsolatedAny() && !state.isolated && this.GetIsolationOpacity() == null) ||
12202
12323
  (existing && existing !== this.hoverLabel && existing.HasText) ||
12203
12324
  (group && group.options.presentation !== "icon")) {
@@ -12209,7 +12330,7 @@ var VisualsRegister;
12209
12330
  return;
12210
12331
  }
12211
12332
  // 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)) {
12333
+ if (!rego && group && [group.item.longitude, group.item.latitude, (_b = group.item.altitude) !== null && _b !== void 0 ? _b : 0].every(Number.isFinite)) {
12213
12334
  rego = {
12214
12335
  entityId: hover.entityId,
12215
12336
  menuItemId: hover.menuItemId,
@@ -12231,7 +12352,7 @@ var VisualsRegister;
12231
12352
  rego,
12232
12353
  viewer: this.viewer,
12233
12354
  visualRegister: this,
12234
- api: (_d = this.ApiGetters) === null || _d === void 0 ? void 0 : _d.GetBruceApi(),
12355
+ api: (_c = this.ApiGetters) === null || _c === void 0 ? void 0 : _c.GetBruceApi(),
12235
12356
  persistent: false,
12236
12357
  transient: true,
12237
12358
  hoverRingState: this.hoverRingState,
@@ -12241,10 +12362,10 @@ var VisualsRegister;
12241
12362
  selectOnClick: false
12242
12363
  },
12243
12364
  visible: () => {
12244
- var _a, _b;
12365
+ var _a;
12245
12366
  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))) &&
12367
+ return (!this.disposed && !current.hidden && isVisualShown(rego.visual) &&
12368
+ Boolean(this.GetRego(hover) || ((_a = this.labelGroups) === null || _a === void 0 ? void 0 : _a.Has(hover.entityId, hover.menuItemId))) &&
12248
12369
  (!this.GetIsIsolatedAny() || current.isolated || this.GetIsolationOpacity() != null));
12249
12370
  }
12250
12371
  };
@@ -14864,12 +14985,20 @@ var EntitiesRenderManager;
14864
14985
  strokeWidth: lineWidthPx,
14865
14986
  clampToGround: lineWidthPx <= 0 && polygonsClamped
14866
14987
  });
14867
- this.viewer.dataSources.add(source);
14868
- this.sources.push(source);
14869
- if (this.disposed) {
14870
- this.doDispose();
14988
+ // Dispose already cleared what was added before this, and this one has not been added.
14989
+ if (this.disposed || this.viewer.isDestroyed()) {
14871
14990
  return;
14872
14991
  }
14992
+ const viewer = this.viewer;
14993
+ this.sources.push(source);
14994
+ // The add lands asynchronously, so a dispose in between removes nothing and would orphan the source.
14995
+ Promise.resolve(viewer.dataSources.add(source)).then(() => {
14996
+ if (this.disposed && !viewer.isDestroyed() && viewer.dataSources.contains(source)) {
14997
+ viewer.dataSources.remove(source);
14998
+ }
14999
+ }).catch((e) => {
15000
+ console.error(e);
15001
+ });
14873
15002
  const groups = [];
14874
15003
  /**
14875
15004
  * Applies individual styling to a rendered entity.
@@ -15911,12 +16040,20 @@ var EntitiesLoadedRenderManager;
15911
16040
  strokeWidth: lineWidthPx,
15912
16041
  clampToGround: lineWidthPx <= 0 && polygonsClamped
15913
16042
  });
15914
- this.viewer.dataSources.add(source);
15915
- this.sources.push(source);
15916
- if (this.disposed) {
15917
- this.doDispose();
16043
+ // Dispose already cleared what was added before this, and this one has not been added.
16044
+ if (this.disposed || this.viewer.isDestroyed()) {
15918
16045
  return;
15919
16046
  }
16047
+ const viewer = this.viewer;
16048
+ this.sources.push(source);
16049
+ // The add lands asynchronously, so a dispose in between removes nothing and would orphan the source.
16050
+ Promise.resolve(viewer.dataSources.add(source)).then(() => {
16051
+ if (this.disposed && !viewer.isDestroyed() && viewer.dataSources.contains(source)) {
16052
+ viewer.dataSources.remove(source);
16053
+ }
16054
+ }).catch((e) => {
16055
+ console.error(e);
16056
+ });
15920
16057
  const groups = [];
15921
16058
  /**
15922
16059
  * Applies individual styling to a rendered entity.
@@ -19611,7 +19748,7 @@ var TilesetCadRenderManager;
19611
19748
  });
19612
19749
  this.tileUnloadRemoval = cTileset.tileUnload.addEventListener((tile) => {
19613
19750
  try {
19614
- this.queueTile(tile, false);
19751
+ this.unloadTile(tile);
19615
19752
  }
19616
19753
  catch (e) {
19617
19754
  console.error(e);
@@ -19795,7 +19932,7 @@ var TilesetCadRenderManager;
19795
19932
  });
19796
19933
  this.tileUnloadRemoval = this.cTileset.tileUnload.addEventListener((tile) => {
19797
19934
  try {
19798
- this.queueTile(tile, false);
19935
+ this.unloadTile(tile);
19799
19936
  }
19800
19937
  catch (e) {
19801
19938
  console.error(e);
@@ -19860,6 +19997,35 @@ var TilesetCadRenderManager;
19860
19997
  }
19861
19998
  this.pingFeatureQueue();
19862
19999
  }
20000
+ /*
20001
+ * Removes a tile's regos and marks its features dead, while the tile's content can still be read.
20002
+ */
20003
+ unloadTile(tile) {
20004
+ const content = tile === null || tile === void 0 ? void 0 : tile.content;
20005
+ if (!content) {
20006
+ return;
20007
+ }
20008
+ const features = [];
20009
+ for (let i = 0; i < content.featuresLength; i++) {
20010
+ const feature = content.getFeature(i);
20011
+ // Drops a load still queued for it, the batch skips anything marked.
20012
+ this.featureQueueStates.delete(feature);
20013
+ feature._bruceUnloaded = true;
20014
+ features.push(feature);
20015
+ }
20016
+ if (!features.length) {
20017
+ return;
20018
+ }
20019
+ const { removedEntityIds } = this.visualsManager.RemoveRegosByVisuals({
20020
+ visuals: features,
20021
+ requestRender: false,
20022
+ menuItemId: this.item.id,
20023
+ doRemove: false
20024
+ });
20025
+ for (const entityId of removedEntityIds) {
20026
+ delete this.loadedCesiumEntities[entityId];
20027
+ }
20028
+ }
19863
20029
  /**
19864
20030
  * Pings the feature queue to process any queued features.
19865
20031
  * Does nothing if we're already processing.
@@ -19876,7 +20042,7 @@ var TilesetCadRenderManager;
19876
20042
  return;
19877
20043
  }
19878
20044
  this.processFeatureQueueBatch();
19879
- if (!this.featureQueue) {
20045
+ if (!this.featureQueue.length) {
19880
20046
  clearInterval(this.featureQueueInterval);
19881
20047
  this.featureQueueInterval = null;
19882
20048
  }
@@ -19908,6 +20074,10 @@ var TilesetCadRenderManager;
19908
20074
  const regosToStyle = new Map();
19909
20075
  const featuresToRemove = [];
19910
20076
  for (const feature of batch) {
20077
+ // Its tile unloaded while it waited, unloadTile already removed whatever it registered.
20078
+ if (feature._bruceUnloaded) {
20079
+ continue;
20080
+ }
19911
20081
  const load = this.featureQueueStates.get(feature);
19912
20082
  this.featureQueueStates.delete(feature);
19913
20083
  if (!load) {
@@ -23080,6 +23250,7 @@ var TilesetOsmRenderManager;
23080
23250
  this.processingQueue = 0;
23081
23251
  this._osmIdToBruceId = {};
23082
23252
  this.tileLoadRemoval = null;
23253
+ this.tileUnloadRemoval = null;
23083
23254
  const { viewer, register: visualsManager, getters: apiGetter, monitor, item } = params;
23084
23255
  this.viewer = viewer;
23085
23256
  this.getters = apiGetter;
@@ -23088,7 +23259,7 @@ var TilesetOsmRenderManager;
23088
23259
  this.monitor = monitor;
23089
23260
  }
23090
23261
  Dispose() {
23091
- var _a;
23262
+ var _a, _b;
23092
23263
  if (this.disposed) {
23093
23264
  return;
23094
23265
  }
@@ -23096,6 +23267,8 @@ var TilesetOsmRenderManager;
23096
23267
  clearInterval(this.queueCheckInterval);
23097
23268
  (_a = this.tileLoadRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
23098
23269
  this.tileLoadRemoval = null;
23270
+ (_b = this.tileUnloadRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
23271
+ this.tileUnloadRemoval = null;
23099
23272
  if (this.cTileset) {
23100
23273
  const viewer = this.viewer;
23101
23274
  if (!(viewer === null || viewer === void 0 ? void 0 : viewer.isDestroyed()) && this.viewer.scene.primitives.contains(this.cTileset)) {
@@ -23191,6 +23364,14 @@ var TilesetOsmRenderManager;
23191
23364
  console.error(e);
23192
23365
  }
23193
23366
  });
23367
+ this.tileUnloadRemoval = this.cTileset.tileUnload.addEventListener((tile) => {
23368
+ try {
23369
+ this.unloadTile(tile);
23370
+ }
23371
+ catch (e) {
23372
+ console.error(e);
23373
+ }
23374
+ });
23194
23375
  this.queueCheckInterval = setInterval(() => {
23195
23376
  if (this.featureQueue.length > 0) {
23196
23377
  this.processQueue();
@@ -23227,6 +23408,34 @@ var TilesetOsmRenderManager;
23227
23408
  this.processQueue();
23228
23409
  }
23229
23410
  }
23411
+ /*
23412
+ * Removes a tile's regos and marks its features dead, while the tile's content can still be read.
23413
+ */
23414
+ unloadTile(tile) {
23415
+ const content = tile === null || tile === void 0 ? void 0 : tile.content;
23416
+ if (!content) {
23417
+ return;
23418
+ }
23419
+ const features = [];
23420
+ for (let i = 0; i < content.featuresLength; i++) {
23421
+ const feature = content.getFeature(i);
23422
+ feature._bruceUnloaded = true;
23423
+ features.push(feature);
23424
+ }
23425
+ if (!features.length) {
23426
+ return;
23427
+ }
23428
+ this.featureQueue = this.featureQueue.filter(x => !x._bruceUnloaded);
23429
+ const { removedEntityIds } = this.visualsManager.RemoveRegosByVisuals({
23430
+ visuals: features,
23431
+ requestRender: false,
23432
+ menuItemId: this.item.id,
23433
+ doRemove: false
23434
+ });
23435
+ for (const entityId of removedEntityIds) {
23436
+ delete this._loadedCesiumEntities[entityId];
23437
+ }
23438
+ }
23230
23439
  async processQueue() {
23231
23440
  if (this.processingQueue >= MAX_BATCHES) {
23232
23441
  return;
@@ -23359,6 +23568,10 @@ var TilesetOsmRenderManager;
23359
23568
  bruceId = ObjectUtils.UId();
23360
23569
  }
23361
23570
  const feature = featureMap[i];
23571
+ // Its tile unloaded while the ID lookup was in flight.
23572
+ if (feature._bruceUnloaded) {
23573
+ continue;
23574
+ }
23362
23575
  if (this.item.ghostLoading == true) {
23363
23576
  feature.color = feature._orgColor;
23364
23577
  }
@@ -23450,7 +23663,7 @@ var TilesetOsmRenderManager;
23450
23663
  return `osm:${sourceId}:${entityTypeId}`;
23451
23664
  }
23452
23665
  PrepareHandoff() {
23453
- var _a;
23666
+ var _a, _b;
23454
23667
  if (this.disposed || !this.cTileset || this.cTileset.isDestroyed()) {
23455
23668
  return null;
23456
23669
  }
@@ -23458,6 +23671,8 @@ var TilesetOsmRenderManager;
23458
23671
  this.queueCheckInterval = null;
23459
23672
  (_a = this.tileLoadRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
23460
23673
  this.tileLoadRemoval = null;
23674
+ (_b = this.tileUnloadRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
23675
+ this.tileUnloadRemoval = null;
23461
23676
  const payload = {
23462
23677
  cTileset: this.cTileset,
23463
23678
  loadedCesiumEntities: this._loadedCesiumEntities,
@@ -23505,6 +23720,14 @@ var TilesetOsmRenderManager;
23505
23720
  console.error(e);
23506
23721
  }
23507
23722
  });
23723
+ this.tileUnloadRemoval = this.cTileset.tileUnload.addEventListener((tile) => {
23724
+ try {
23725
+ this.unloadTile(tile);
23726
+ }
23727
+ catch (e) {
23728
+ console.error(e);
23729
+ }
23730
+ });
23508
23731
  this.queueCheckInterval = setInterval(() => {
23509
23732
  if (this.featureQueue.length > 0) {
23510
23733
  this.processQueue();
@@ -23695,7 +23918,7 @@ var TilesetEntitiesRenderManager;
23695
23918
  });
23696
23919
  this.tileUnloadRemoval = cTileset.tileUnload.addEventListener((tile) => {
23697
23920
  try {
23698
- this.queueTile(tile, false);
23921
+ this.unloadTile(tile);
23699
23922
  }
23700
23923
  catch (e) {
23701
23924
  console.error(e);
@@ -23741,6 +23964,35 @@ var TilesetEntitiesRenderManager;
23741
23964
  }
23742
23965
  this.pingFeatureQueue();
23743
23966
  }
23967
+ /*
23968
+ * Removes a tile's regos and marks its features dead, while the tile's content can still be read.
23969
+ */
23970
+ unloadTile(tile) {
23971
+ const content = tile === null || tile === void 0 ? void 0 : tile.content;
23972
+ if (!content) {
23973
+ return;
23974
+ }
23975
+ const features = [];
23976
+ for (let i = 0; i < content.featuresLength; i++) {
23977
+ const feature = content.getFeature(i);
23978
+ // Drops a load still queued for it, the batch skips anything marked.
23979
+ this.featureQueueStates.delete(feature);
23980
+ feature._bruceUnloaded = true;
23981
+ features.push(feature);
23982
+ }
23983
+ if (!features.length) {
23984
+ return;
23985
+ }
23986
+ const { removedEntityIds } = this.visualsManager.RemoveRegosByVisuals({
23987
+ visuals: features,
23988
+ requestRender: false,
23989
+ menuItemId: this.item.id,
23990
+ doRemove: false
23991
+ });
23992
+ for (const entityId of removedEntityIds) {
23993
+ delete this.loadedCesiumEntities[entityId];
23994
+ }
23995
+ }
23744
23996
  /**
23745
23997
  * Pings the feature queue to process any queued features.
23746
23998
  * Does nothing if we're already processing.
@@ -23757,7 +24009,7 @@ var TilesetEntitiesRenderManager;
23757
24009
  return;
23758
24010
  }
23759
24011
  this.processFeatureQueueBatch();
23760
- if (!this.featureQueue) {
24012
+ if (!this.featureQueue.length) {
23761
24013
  clearInterval(this.featureQueueInterval);
23762
24014
  this.featureQueueInterval = null;
23763
24015
  }
@@ -23775,6 +24027,10 @@ var TilesetEntitiesRenderManager;
23775
24027
  const regosToStyle = new Map();
23776
24028
  const featuresToRemove = [];
23777
24029
  for (const feature of batch) {
24030
+ // Its tile unloaded while it waited, unloadTile already removed whatever it registered.
24031
+ if (feature._bruceUnloaded) {
24032
+ continue;
24033
+ }
23778
24034
  const load = this.featureQueueStates.get(feature);
23779
24035
  this.featureQueueStates.delete(feature);
23780
24036
  if (!load) {
@@ -23980,7 +24236,7 @@ var TilesetEntitiesRenderManager;
23980
24236
  });
23981
24237
  this.tileUnloadRemoval = this.cTileset.tileUnload.addEventListener((tile) => {
23982
24238
  try {
23983
- this.queueTile(tile, false);
24239
+ this.unloadTile(tile);
23984
24240
  }
23985
24241
  catch (e) {
23986
24242
  console.error(e);
@@ -24941,7 +25197,7 @@ var TilesetArbRenderManager;
24941
25197
  });
24942
25198
  this.cTileset.tileUnload.addEventListener((tile) => {
24943
25199
  try {
24944
- this.queueTile(tile, false);
25200
+ this.unloadTile(tile);
24945
25201
  }
24946
25202
  catch (e) {
24947
25203
  console.error(e);
@@ -24969,6 +25225,35 @@ var TilesetArbRenderManager;
24969
25225
  }
24970
25226
  this.pingFeatureQueue();
24971
25227
  }
25228
+ /*
25229
+ * Removes a tile's regos and marks its features dead, while the tile's content can still be read.
25230
+ */
25231
+ unloadTile(tile) {
25232
+ const content = tile === null || tile === void 0 ? void 0 : tile.content;
25233
+ if (!content) {
25234
+ return;
25235
+ }
25236
+ const features = [];
25237
+ for (let i = 0; i < content.featuresLength; i++) {
25238
+ const feature = content.getFeature(i);
25239
+ // Drops a load still queued for it, the batch skips anything marked.
25240
+ this.featureQueueStates.delete(feature);
25241
+ feature._bruceUnloaded = true;
25242
+ features.push(feature);
25243
+ }
25244
+ if (!features.length) {
25245
+ return;
25246
+ }
25247
+ const { removedEntityIds } = this.visualsManager.RemoveRegosByVisuals({
25248
+ visuals: features,
25249
+ requestRender: false,
25250
+ menuItemId: this.item.id,
25251
+ doRemove: false
25252
+ });
25253
+ for (const entityId of removedEntityIds) {
25254
+ delete this.loadedCesiumEntities[entityId];
25255
+ }
25256
+ }
24972
25257
  /**
24973
25258
  * Pings the feature queue to process any queued features.
24974
25259
  * Does nothing if we're already processing.
@@ -24985,7 +25270,7 @@ var TilesetArbRenderManager;
24985
25270
  return;
24986
25271
  }
24987
25272
  this.processFeatureQueueBatch();
24988
- if (!this.featureQueue) {
25273
+ if (!this.featureQueue.length) {
24989
25274
  clearInterval(this.featureQueueInterval);
24990
25275
  this.featureQueueInterval = null;
24991
25276
  }
@@ -25003,6 +25288,10 @@ var TilesetArbRenderManager;
25003
25288
  const regosToStyle = new Map();
25004
25289
  const featuresToRemove = [];
25005
25290
  for (const feature of batch) {
25291
+ // Its tile unloaded while it waited, unloadTile already removed whatever it registered.
25292
+ if (feature._bruceUnloaded) {
25293
+ continue;
25294
+ }
25006
25295
  const load = this.featureQueueStates.get(feature);
25007
25296
  this.featureQueueStates.delete(feature);
25008
25297
  if (!load) {
@@ -25621,6 +25910,8 @@ var TilesetGooglePhotosRenderManager;
25621
25910
  constructor(params) {
25622
25911
  this.disposed = false;
25623
25912
  this.cTileset = null;
25913
+ // Set while a tileset is being created, so a second Init in the meantime cannot add another.
25914
+ this.initializing = false;
25624
25915
  const { viewer, item, getters } = params;
25625
25916
  this.viewer = viewer;
25626
25917
  this.item = item;
@@ -25641,6 +25932,10 @@ var TilesetGooglePhotosRenderManager;
25641
25932
  this.viewer.scene.primitives.remove(this.cTileset);
25642
25933
  this.viewer.scene.requestRender();
25643
25934
  }
25935
+ // Disposed before it was added, so nothing else will ever destroy it.
25936
+ else if (!this.cTileset.isDestroyed()) {
25937
+ this.cTileset.destroy();
25938
+ }
25644
25939
  this.cTileset = null;
25645
25940
  }
25646
25941
  }
@@ -25659,6 +25954,11 @@ var TilesetGooglePhotosRenderManager;
25659
25954
  this.viewer.scene.requestRender();
25660
25955
  return;
25661
25956
  }
25957
+ // The creation in flight applies the latest item's colour mask when it lands.
25958
+ if (this.initializing) {
25959
+ return;
25960
+ }
25961
+ this.initializing = true;
25662
25962
  try {
25663
25963
  const api = this.getters.GetBruceApi();
25664
25964
  await api.Loading;
@@ -25744,6 +26044,14 @@ var TilesetGooglePhotosRenderManager;
25744
26044
  console.error("Failed to load Google Photorealistic 3D tileset:", e);
25745
26045
  return;
25746
26046
  }
26047
+ finally {
26048
+ this.initializing = false;
26049
+ }
26050
+ // Creation can come back empty, and the viewer can go while it loads.
26051
+ if (this.disposed || !this.cTileset || this.cTileset.isDestroyed() || !this.viewer || this.viewer.isDestroyed()) {
26052
+ this.doDispose();
26053
+ return;
26054
+ }
25747
26055
  this.viewer.scene.primitives.add(this.cTileset);
25748
26056
  this.applyColorMask();
25749
26057
  this.viewer.scene.requestRender();
@@ -43234,7 +43542,8 @@ var EntityRenderEngineModel3d;
43234
43542
  const hpr = new HeadingPitchRoll(Math$1.toRadians(heading), Math$1.toRadians(pitch), Math$1.toRadians(roll));
43235
43543
  getOrient = new CallbackProperty(() => {
43236
43544
  const currentPos = position ? GetCValue(params.viewer, position) : pos3d;
43237
- return Transforms.headingPitchRollQuaternion(currentPos, hpr);
43545
+ // A live position can read as null mid-update, and throwing here would stop Cesium's frame.
43546
+ return Transforms.headingPitchRollQuaternion(currentPos || pos3d, hpr);
43238
43547
  }, false);
43239
43548
  }
43240
43549
  cEntity = new Entity({
@@ -50574,7 +50883,7 @@ var StyleUtils;
50574
50883
  StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
50575
50884
  })(StyleUtils || (StyleUtils = {}));
50576
50885
 
50577
- const VERSION = "7.4.5";
50886
+ const VERSION = "7.4.7";
50578
50887
  /**
50579
50888
  * Updates the environment instance used by bruce-cesium to one specified.
50580
50889
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.