bruce-cesium 7.4.2 → 7.4.3

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.
@@ -1,6 +1,6 @@
1
1
  import * as Cesium from 'cesium';
2
- import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, HeightReference, ColorBlendMode, HeadingPitchRoll, Math as Math$1, Transforms, ShadowMode, Cartesian3, ClassificationType, Model, ShaderSource, Ellipsoid, 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, DistanceDisplayCondition, ArcType, CornerType, ConstantPositionProperty, HorizontalOrigin, VerticalOrigin, ImageMaterialProperty, SceneTransforms, PolygonHierarchy, PolylineGraphics, Rectangle, FeatureDetection, KmlDataSource, NearFarScalar, GeoJsonDataSource, Matrix3, SceneMode, Ion, IonResource, Cesium3DTileStyle, HeadingPitchRange, Cesium3DTileColorBlendMode, Cesium3DTileset, Intersect, OrthographicFrustum, EasingFunction, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, EllipsoidGeodesic, EllipsoidTerrainProvider, sampleTerrainMostDetailed, defined, PolygonPipeline, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, GeometryInstance, ScreenSpaceEventHandler, ScreenSpaceEventType, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, CustomDataSource, Fullscreen, CzmlDataSource } from 'cesium';
3
- import { Cartes, LRUCache, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, Entity as Entity$1, EntityLod, EntityTag, EntityType, ObjectUtils, Style, Carto, Geometry as Geometry$1, Api, ClientFileValueMap, Color as Color$1, BruceEvent, EntityCoords, MenuItem, Tileset, ProjectView, ProjectViewBookmark, ZoomControl, Bounds, DataLab, DelayQueue, AccountConcept, BruceApi, EntityRelation, RecordChangeFeed, EntitySource, Camera, ProgramKey, ProjectViewLegacyTile, 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, ColorBlendMode, HeadingPitchRoll, Math as Math$1, Transforms, ShadowMode, Cartesian3, ClassificationType, Model, JulianDate, Quaternion, Matrix4, ShaderSource, Ellipsoid, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, Cartesian2, Cartesian4, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, ArcType, CornerType, HorizontalOrigin, VerticalOrigin, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, SceneTransforms, FeatureDetection, NearFarScalar, Matrix3, KmlDataSource, SceneMode, GeoJsonDataSource, Cesium3DTileStyle, HeadingPitchRange, Ion, IonResource, Cesium3DTileColorBlendMode, Cesium3DTileset, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, OrthographicFrustum, EasingFunction, Intersect, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, PolygonPipeline, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, GeometryInstance, CustomDataSource, ScreenSpaceEventHandler, ScreenSpaceEventType, Fullscreen, CzmlDataSource } from 'cesium';
3
+ import { Cartes, LRUCache, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, Entity as Entity$1, EntityLod, EntityTag, EntityType, ObjectUtils, Style, Carto, Geometry as Geometry$1, Api, Bounds, ClientFileValueMap, Color as Color$1, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, DataLab, BruceEvent, EntityCoords, AccountConcept, DelayQueue, BruceApi, EntityRelation, RecordChangeFeed, EntitySource, ProgramKey, ProjectViewLegacyTile, 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.
@@ -16796,9 +16796,6 @@ class EntityGatherer {
16796
16796
  // Last date-time range taken from the clock.
16797
16797
  this.lastDateTimeMin = null;
16798
16798
  this.lastDateTimeMax = null;
16799
- // Entity ID -> last resolved date time.
16800
- // Helps determine if a slow resolved request can still be applied while we wait for the next one.
16801
- this.lastFoundDateTimes = new Map();
16802
16799
  // ID of Entity IDs that need to be requested.
16803
16800
  this.eIdQueue = [];
16804
16801
  // Membership mirror of eIdQueue for quick checks.
@@ -16830,8 +16827,12 @@ class EntityGatherer {
16830
16827
  // Unsubscribes the view monitor listener that queues what the camera has moved onto.
16831
16828
  this.monitorRemoval = null;
16832
16829
  // Indicates a tick is active.
16833
- // When true, we won't bother calling onTick again.
16830
+ // When true, a new tick is not started; it is noted in pendingTick and run once this one ends.
16834
16831
  this.runningTick = false;
16832
+ // A tick was asked for while one was running, so another is owed once it finishes.
16833
+ this.pendingTick = false;
16834
+ // The debounce every clock change goes through, kept so a tick owed after a running one does too.
16835
+ this.tickDelay = null;
16835
16836
  // Entity ID -> Entity blob.
16836
16837
  // This is a tool that lets developers set their own JSON blobs instead of requesting data from API.
16837
16838
  this.entityDataOverrides = new Map();
@@ -16895,11 +16896,13 @@ class EntityGatherer {
16895
16896
  let tickDelay = new DelayQueue(() => {
16896
16897
  this.onTick(false);
16897
16898
  }, 250, true);
16899
+ this.tickDelay = tickDelay;
16898
16900
  this.hDisposals.push(() => {
16899
16901
  if (tickDelay) {
16900
16902
  tickDelay.Dispose();
16901
16903
  }
16902
16904
  tickDelay = null;
16905
+ this.tickDelay = null;
16903
16906
  });
16904
16907
  // React to clock changes and request new Entities.
16905
16908
  let prevTime = null;
@@ -16939,7 +16942,6 @@ class EntityGatherer {
16939
16942
  this.priorityCount = 0;
16940
16943
  this.lastOrderFocus = null;
16941
16944
  this.allEIds.clear();
16942
- this.lastFoundDateTimes.clear();
16943
16945
  this.everFound.clear();
16944
16946
  this.clearIndex();
16945
16947
  this.lastDateTime = null;
@@ -17301,7 +17303,6 @@ class EntityGatherer {
17301
17303
  this.eIdQueued.clear();
17302
17304
  this.priorityCount = 0;
17303
17305
  this.allEIds.clear();
17304
- this.lastFoundDateTimes.clear();
17305
17306
  this.everFound.clear();
17306
17307
  this.clearIndex();
17307
17308
  this.entityDataOverrides.clear();
@@ -17317,7 +17318,13 @@ class EntityGatherer {
17317
17318
  }
17318
17319
  }
17319
17320
  onTick(force) {
17320
- if (this.runningTick || this.disposed) {
17321
+ if (this.disposed) {
17322
+ return;
17323
+ }
17324
+ if (this.runningTick) {
17325
+ if (this.historic) {
17326
+ this.pendingTick = true;
17327
+ }
17321
17328
  return;
17322
17329
  }
17323
17330
  const rTime = this.viewer.clock.currentTime.toString();
@@ -17325,10 +17332,16 @@ class EntityGatherer {
17325
17332
  return;
17326
17333
  }
17327
17334
  this.lastDateTime = rTime;
17335
+ // Whether the clock has left the moment this tick is reading.
17336
+ const movedOn = () => this.historic && this.viewer.clock.currentTime.toString() !== rTime;
17328
17337
  (async () => {
17329
17338
  this.runningTick = true;
17339
+ this.pendingTick = false;
17330
17340
  this.placeStragglers();
17331
17341
  let rerun = false;
17342
+ let interrupted = false;
17343
+ // Batch's answer is applied while the next batch is being read.
17344
+ const applying = [];
17332
17345
  try {
17333
17346
  const handleResponse = async (requestedBatch, entities) => {
17334
17347
  var _a, _b, _c, _d;
@@ -17392,45 +17405,7 @@ class EntityGatherer {
17392
17405
  api: this.api
17393
17406
  })).tags;
17394
17407
  }
17395
- // 0 = rTime is still the current time.
17396
- // 1 = rTime is in the future.
17397
- // -1 = rTime is in the past.
17398
- let changeDir = 0;
17399
- if (this.lastDateTime !== this.viewer.clock.currentTime.toString()) {
17400
- changeDir = this.lastDateTime < this.viewer.clock.currentTime.toString() ? 1 : -1;
17401
- }
17402
- let toEmit;
17403
- if (this.historic) {
17404
- // We can emit Entities if the last resolved time (per Entity) isn't newer than rTime.
17405
- // We compare using the changeDir to determine if we should emit or not.
17406
- toEmit = resolvedEntities.filter((e) => {
17407
- var _a;
17408
- const entityId = ((_a = e === null || e === void 0 ? void 0 : e.Bruce) === null || _a === void 0 ? void 0 : _a.ID) || (e === null || e === void 0 ? void 0 : e.id);
17409
- const lastFoundDateTime = this.lastFoundDateTimes.get(entityId);
17410
- if (lastFoundDateTime) {
17411
- if (changeDir === 1) {
17412
- return lastFoundDateTime <= rTime;
17413
- }
17414
- else if (changeDir === -1) {
17415
- return lastFoundDateTime >= rTime;
17416
- }
17417
- }
17418
- return true;
17419
- });
17420
- // Update the last found date times for the filtered Entities.
17421
- toEmit.forEach((e) => {
17422
- var _a;
17423
- const entityId = ((_a = e === null || e === void 0 ? void 0 : e.Bruce) === null || _a === void 0 ? void 0 : _a.ID) || (e === null || e === void 0 ? void 0 : e.id);
17424
- if (entityId) {
17425
- this.lastFoundDateTimes.set(entityId, rTime);
17426
- }
17427
- });
17428
- }
17429
- else {
17430
- // If we're not historic, we can just emit everything.
17431
- toEmit = resolvedEntities;
17432
- }
17433
- this.emitEntities(toEmit, tags);
17408
+ this.emitEntities(resolvedEntities, tags);
17434
17409
  };
17435
17410
  const QUEUE_BATCH_SIZE = 500;
17436
17411
  const requestedIds = new Set();
@@ -17439,7 +17414,8 @@ class EntityGatherer {
17439
17414
  const total = this.eIdQueue.length;
17440
17415
  let done = 0;
17441
17416
  while (this.eIdQueue.length && !this.disposed) {
17442
- if (this.historic && this.lastDateTime !== rTime) {
17417
+ if (movedOn()) {
17418
+ interrupted = true;
17443
17419
  break;
17444
17420
  }
17445
17421
  this.orderQueueByCamera();
@@ -17455,7 +17431,7 @@ class EntityGatherer {
17455
17431
  api: this.api,
17456
17432
  maxSearchTimeSec: 60 * 2
17457
17433
  });
17458
- handleResponse(batch, entities);
17434
+ applying.push(handleResponse(batch, entities));
17459
17435
  for (let i = 0; i < batch.length; i++) {
17460
17436
  requestedIds.add(batch[i]);
17461
17437
  }
@@ -17487,7 +17463,8 @@ class EntityGatherer {
17487
17463
  // The near ones are resolved first out of whatever the view still reaches.
17488
17464
  allEIds = this.bandIds(allEIds);
17489
17465
  while (allEIds.length && !this.disposed && !this.eIdQueue.length) {
17490
- if (this.historic && this.lastDateTime !== rTime) {
17466
+ if (movedOn()) {
17467
+ interrupted = true;
17491
17468
  break;
17492
17469
  }
17493
17470
  const batch = allEIds.splice(0, QUEUE_BATCH_SIZE);
@@ -17498,7 +17475,7 @@ class EntityGatherer {
17498
17475
  api: this.api,
17499
17476
  maxSearchTimeSec: 60 * 2
17500
17477
  });
17501
- handleResponse(batch, entities);
17478
+ applying.push(handleResponse(batch, entities));
17502
17479
  for (let i = 0; i < batch.length; i++) {
17503
17480
  requestedIds.add(batch[i]);
17504
17481
  }
@@ -17513,10 +17490,32 @@ class EntityGatherer {
17513
17490
  console.error(e);
17514
17491
  }
17515
17492
  finally {
17493
+ // Only a historic answer can be overtaken by a newer moment, so nothing else waits.
17494
+ if (this.historic && applying.length) {
17495
+ await Promise.all(applying.map((pending) => pending.catch((e) => console.error(e))));
17496
+ }
17516
17497
  this.runningTick = false;
17517
17498
  }
17518
- if (rerun) {
17499
+ // A moment read only in part is forgotten, so coming back to it reads it again in full.
17500
+ if (interrupted && this.lastDateTime === rTime) {
17501
+ this.lastDateTime = null;
17502
+ }
17503
+ if (this.disposed) {
17504
+ return;
17505
+ }
17506
+ // Leftovers at the same moment carry straight on, as they always have.
17507
+ if (rerun && !interrupted) {
17519
17508
  this.onTick(true);
17509
+ return;
17510
+ }
17511
+ if (interrupted || this.pendingTick || movedOn()) {
17512
+ this.pendingTick = false;
17513
+ if (this.tickDelay) {
17514
+ this.tickDelay.Call();
17515
+ }
17516
+ else {
17517
+ this.onTick(false);
17518
+ }
17520
17519
  }
17521
17520
  })();
17522
17521
  }
@@ -49206,7 +49205,7 @@ var EntityRenderEngine;
49206
49205
  }
49207
49206
  EntityRenderEngine.GetGraphicShapeId = GetGraphicShapeId;
49208
49207
  async function Render(params) {
49209
- var _a, _b, _c;
49208
+ var _a, _b, _c, _d, _e;
49210
49209
  const groupRenderParams = {
49211
49210
  apiGetter: params.apiGetter,
49212
49211
  viewer: params.viewer,
@@ -49383,10 +49382,20 @@ var EntityRenderEngine;
49383
49382
  polygons.push(entity);
49384
49383
  continue;
49385
49384
  }
49385
+ // Present when the gate above chose to reuse this entity's graphic.
49386
+ const existingRoot = cEntities.get(entity.Bruce.ID);
49387
+ const existingParts = new Map();
49388
+ (_d = existingRoot === null || existingRoot === void 0 ? void 0 : existingRoot._siblingGraphics) === null || _d === void 0 ? void 0 : _d.forEach((part) => {
49389
+ if (part._multiPartIndex != null) {
49390
+ existingParts.set(part._multiPartIndex, part);
49391
+ }
49392
+ });
49393
+ const partRendered = new Map();
49394
+ const partIndexes = new Map();
49386
49395
  const pParams = {
49387
49396
  ...groupRenderParams,
49388
49397
  entities: [],
49389
- rendered: cEntities
49398
+ rendered: partRendered
49390
49399
  };
49391
49400
  pParams.entitiesHistoric = params.entitiesHistoric;
49392
49401
  const zoomItem = pParams.zoomItems[entity.Bruce.ID];
@@ -49402,39 +49411,59 @@ var EntityRenderEngine;
49402
49411
  };
49403
49412
  pParams.zoomItems[subEntity.Bruce.ID] = zoomItem;
49404
49413
  pParams.entities.push(subEntity);
49405
- }
49406
- const cPoly = await Polygon.RenderGroup(pParams);
49407
- Array.from(cPoly.keys()).forEach((key) => {
49408
- if (cPoly.get(key)) {
49409
- pParams.entities = pParams.entities.filter((e) => e.Bruce.ID != key);
49410
- }
49411
- });
49412
- let rendered = Array.from(cPoly.values());
49413
- const cLines = await Polyline.RenderGroup(pParams);
49414
- Array.from(cLines.keys()).forEach((key) => {
49415
- if (cLines.get(key)) {
49414
+ partIndexes.set(subEntity.Bruce.ID, j);
49415
+ const existingPart = existingParts.get(j);
49416
+ if (existingPart) {
49417
+ // An engine preparing a reused graphic gathers everything connected to it, so a part still
49418
+ // attached to its root would have every other part evicted from the scene.
49419
+ existingPart._parentEntity = null;
49420
+ partRendered.set(subEntity.Bruce.ID, existingPart);
49421
+ }
49422
+ }
49423
+ const rendered = [];
49424
+ const collect = (results) => {
49425
+ results.forEach((cEntity, key) => {
49426
+ if (!cEntity) {
49427
+ return;
49428
+ }
49429
+ cEntity._multiPartIndex = partIndexes.get(key);
49430
+ rendered.push(cEntity);
49416
49431
  pParams.entities = pParams.entities.filter((e) => e.Bruce.ID != key);
49417
- }
49418
- });
49419
- rendered = rendered.concat(Array.from(cLines.values()));
49432
+ });
49433
+ };
49434
+ collect(await Polygon.RenderGroup(pParams));
49435
+ collect(await Polyline.RenderGroup(pParams));
49420
49436
  // We'll only render points when there's no other geometry.
49421
49437
  // Generally speaking when polygons/polylines are drawn, points are only drawn because of invalid data.
49422
49438
  if (!rendered.length) {
49423
- const cPoints = await Point.RenderGroup(pParams);
49424
- rendered = rendered.concat(Array.from(cPoints.values()));
49439
+ collect(await Point.RenderGroup(pParams));
49425
49440
  }
49426
- rendered = rendered.filter(x => x != null);
49427
49441
  if (rendered.length) {
49428
- const rootEntity = new Entity({
49429
- id: ObjectUtils.UId(15)
49430
- });
49431
- rootEntity._siblingGraphics = [];
49442
+ const sameParts = ((_e = existingRoot === null || existingRoot === void 0 ? void 0 : existingRoot._siblingGraphics) === null || _e === void 0 ? void 0 : _e.length) == rendered.length &&
49443
+ rendered.every((part) => existingRoot._siblingGraphics.includes(part));
49444
+ let rootEntity;
49445
+ if (sameParts) {
49446
+ rootEntity = existingRoot;
49447
+ }
49448
+ else {
49449
+ if (existingRoot === null || existingRoot === void 0 ? void 0 : existingRoot._siblingGraphics) {
49450
+ // Retiring the old root removes its parts, and the ones carried over belong to the new root now.
49451
+ existingRoot._siblingGraphics = existingRoot._siblingGraphics.filter((part) => !rendered.includes(part));
49452
+ }
49453
+ rootEntity = new Entity({
49454
+ id: ObjectUtils.UId(15)
49455
+ });
49456
+ }
49457
+ rootEntity._siblingGraphics = rendered;
49432
49458
  rootEntity._renderGroup = GetRenderGroupId(zoomItem);
49433
- rootEntity._siblingGraphics = rootEntity._siblingGraphics.concat(rendered);
49459
+ // The skip gate compares the rego's style against the zoom item's, and the rego takes it from here.
49460
+ rootEntity.styleId = (zoomItem === null || zoomItem === void 0 ? void 0 : zoomItem.StyleID) == -1 ? -1 : (+(zoomItem === null || zoomItem === void 0 ? void 0 : zoomItem.StyleID) || null);
49461
+ rootEntity.styleEffective = rendered[0].styleEffective;
49434
49462
  cEntities.set(entity.Bruce.ID, rootEntity);
49435
- const firstEntity = rendered[0];
49436
- if (firstEntity) {
49437
- rootEntity.position = GetCValue(params.viewer, firstEntity.position);
49463
+ const newPosition = GetCValue(params.viewer, rendered[0].position);
49464
+ const oldPosition = GetCValue(params.viewer, rootEntity.position);
49465
+ if (newPosition && (!oldPosition || !Cartes.IsEqualCartes3(oldPosition, newPosition))) {
49466
+ rootEntity.position = new ConstantPositionProperty(newPosition);
49438
49467
  }
49439
49468
  rendered.forEach((child) => {
49440
49469
  child._parentEntity = rootEntity;
@@ -50371,7 +50400,7 @@ var StyleUtils;
50371
50400
  StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
50372
50401
  })(StyleUtils || (StyleUtils = {}));
50373
50402
 
50374
- const VERSION = "7.4.2";
50403
+ const VERSION = "7.4.3";
50375
50404
  /**
50376
50405
  * Updates the environment instance used by bruce-cesium to one specified.
50377
50406
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.