bruce-cesium 2.1.6 → 2.1.8

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 (24) hide show
  1. package/dist/bruce-cesium.es5.js +795 -53
  2. package/dist/bruce-cesium.es5.js.map +1 -1
  3. package/dist/bruce-cesium.umd.js +794 -52
  4. package/dist/bruce-cesium.umd.js.map +1 -1
  5. package/dist/lib/bruce-cesium.js +1 -1
  6. package/dist/lib/rendering/entity-render-engine.js +69 -14
  7. package/dist/lib/rendering/entity-render-engine.js.map +1 -1
  8. package/dist/lib/rendering/render-managers/common/point-clustering.js +602 -0
  9. package/dist/lib/rendering/render-managers/common/point-clustering.js.map +1 -0
  10. package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js +18 -10
  11. package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js.map +1 -1
  12. package/dist/lib/rendering/render-managers/entities/entities-render-manager.js +40 -20
  13. package/dist/lib/rendering/render-managers/entities/entities-render-manager.js.map +1 -1
  14. package/dist/lib/rendering/visuals-register.js +49 -1
  15. package/dist/lib/rendering/visuals-register.js.map +1 -1
  16. package/dist/lib/utils/entity-utils.js +35 -1
  17. package/dist/lib/utils/entity-utils.js.map +1 -1
  18. package/dist/types/bruce-cesium.d.ts +1 -1
  19. package/dist/types/rendering/entity-render-engine.d.ts +8 -0
  20. package/dist/types/rendering/render-managers/common/point-clustering.d.ts +97 -0
  21. package/dist/types/rendering/render-managers/entities/entities-ids-render-manager.d.ts +1 -0
  22. package/dist/types/rendering/render-managers/entities/entities-render-manager.d.ts +1 -0
  23. package/dist/types/rendering/visuals-register.d.ts +4 -0
  24. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  import { BruceEvent, Cartes, Carto, Entity as Entity$1, Geometry, Tileset, MathUtils, LRUCache, ZoomControl, Style, EntityTag, Calculator, EntityLod, EntityType, ClientFile, ObjectUtils, DelayQueue, BatchedDataGetter, EntityRelationType, EntityCoords, EntityFilterGetter, EntitySource, MenuItem, EntityRelation, ENVIRONMENT, ProjectView, ProjectViewBookmark, ProjectViewTile, ProjectViewLegacyTile, ProgramKey, Camera } from 'bruce-models';
2
2
  import * as Cesium from 'cesium';
3
- import { Cartesian2, Cartographic, CallbackProperty, Cartesian3, Color, Rectangle, Math as Math$1, SceneMode, Entity, Primitive, Cesium3DTileFeature, HeightReference, HorizontalOrigin, VerticalOrigin, ClassificationType, ArcType, PolygonHierarchy, ShadowMode, PolylineGraphics, HeadingPitchRoll, Transforms, ColorBlendMode, Cesium3DTileColorBlendMode, HeadingPitchRange, createOsmBuildings, Cesium3DTileStyle, KmlDataSource, createWorldTerrain, EllipsoidTerrainProvider, CesiumTerrainProvider, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, UrlTemplateImageryProvider, TileMapServiceImageryProvider, IonImageryProvider, OrthographicFrustum, JulianDate, NearFarScalar, Cesium3DTileset, Matrix4, Matrix3, IonResource, CesiumInspector, ColorMaterialProperty, EasingFunction, GeometryInstance, EllipsoidGeodesic, sampleTerrainMostDetailed, PolygonPipeline } from 'cesium';
3
+ import { Cartesian2, Cartographic, CallbackProperty, Cartesian3, Color, Rectangle, Math as Math$1, Entity, Primitive, Cesium3DTileFeature, SceneMode, HeightReference, DistanceDisplayCondition, NearFarScalar, HorizontalOrigin, VerticalOrigin, ClassificationType, ArcType, PolygonHierarchy, ShadowMode, PolylineGraphics, HeadingPitchRoll, Transforms, ColorBlendMode, Cesium3DTileColorBlendMode, HeadingPitchRange, createOsmBuildings, Cesium3DTileStyle, KmlDataSource, createWorldTerrain, EllipsoidTerrainProvider, CesiumTerrainProvider, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, UrlTemplateImageryProvider, TileMapServiceImageryProvider, IonImageryProvider, CesiumInspector, OrthographicFrustum, JulianDate, Cesium3DTileset, Matrix4, Matrix3, IonResource, EllipsoidGeodesic, sampleTerrainMostDetailed, ColorMaterialProperty, EasingFunction, GeometryInstance, PolygonPipeline } from 'cesium';
4
4
 
5
5
  var TIME_LAG = 300;
6
6
  var POSITION_CHECK_TIMER = 950;
@@ -549,6 +549,34 @@ var DrawingUtils;
549
549
  DrawingUtils.EnsurePosHeight = EnsurePosHeight;
550
550
  })(DrawingUtils || (DrawingUtils = {}));
551
551
 
552
+ /**
553
+ * Returns if a given visual is alive and in the scene.
554
+ * @param viewer
555
+ * @param visual
556
+ * @returns
557
+ */
558
+ function isAlive(viewer, visual) {
559
+ if (!(viewer === null || viewer === void 0 ? void 0 : viewer.scene) || viewer.isDestroyed()) {
560
+ return false;
561
+ }
562
+ if (visual instanceof Entity) {
563
+ return viewer.entities.contains(visual);
564
+ }
565
+ else if (visual instanceof Primitive) {
566
+ return viewer.scene.primitives.contains(visual);
567
+ }
568
+ else if (visual instanceof Cesium3DTileFeature) {
569
+ var cTileset = visual === null || visual === void 0 ? void 0 : visual.tileset;
570
+ if (!cTileset) {
571
+ return false;
572
+ }
573
+ if (cTileset.isDestroyed() || !viewer.scene.primitives.contains(cTileset)) {
574
+ return false;
575
+ }
576
+ return true;
577
+ }
578
+ return false;
579
+ }
552
580
  function traverseEntity(cEntity, arr, ignoreParent) {
553
581
  if (cEntity._parentEntity && !ignoreParent) {
554
582
  traverseEntity(cEntity._parentEntity, arr, false);
@@ -597,6 +625,9 @@ function applyOpacityToGraphic(viewer, entity, graphicKey, materialKey, opacity)
597
625
  }
598
626
  }
599
627
  function revertAppliedEntityOpacity(viewer, entity) {
628
+ if (!isAlive(viewer, entity)) {
629
+ return;
630
+ }
600
631
  entity[NEW_OPACITY_KEY] = null;
601
632
  if (entity instanceof Entity) {
602
633
  var processKey = function (graphicKey, materialKey) {
@@ -626,6 +657,9 @@ function revertAppliedEntityOpacity(viewer, entity) {
626
657
  }
627
658
  }
628
659
  function applyOpacityToEntity(viewer, opacity, entity) {
660
+ if (!isAlive(viewer, entity)) {
661
+ return;
662
+ }
629
663
  entity[NEW_OPACITY_KEY] = opacity;
630
664
  if (entity instanceof Entity) {
631
665
  var processKey = function (graphicKey, materialKey) {
@@ -665,7 +699,7 @@ function applyOpacityToEntity(viewer, opacity, entity) {
665
699
  }
666
700
  }
667
701
  function findOpacity(entity) {
668
- return entity[NEW_OPACITY_KEY];
702
+ return entity ? entity[NEW_OPACITY_KEY] : null;
669
703
  }
670
704
  function GetValue(viewer, obj) {
671
705
  if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
@@ -1483,6 +1517,23 @@ function getRenderGroupId(zoomItem, terrain) {
1483
1517
  return zoomItem.MinZoom + "-" + zoomItem.MaxZoom + "-" + shouldApplyFlatFix(terrain);
1484
1518
  }
1485
1519
  var _fileValidationCache = {};
1520
+ function getDisplayCondition(min, max) {
1521
+ // Max is required.
1522
+ if (isNaN(+max)) {
1523
+ return undefined;
1524
+ }
1525
+ // Min is optional.
1526
+ if (isNaN(+min)) {
1527
+ min = 0;
1528
+ }
1529
+ // Adjusting slightly because I distrust our initial calculation vs Cesium's one.
1530
+ max = (+max) * 1.2;
1531
+ min = +min;
1532
+ if (min > 0) {
1533
+ min = (+min) * 0.8;
1534
+ }
1535
+ return new DistanceDisplayCondition(min, max);
1536
+ }
1486
1537
  var EntityRenderEngine;
1487
1538
  (function (EntityRenderEngine) {
1488
1539
  function Render(params) {
@@ -1814,7 +1865,10 @@ var EntityRenderEngine;
1814
1865
  verticalOrigin: VerticalOrigin.BOTTOM,
1815
1866
  image: iconUrl,
1816
1867
  heightReference: getHeightRef(style),
1817
- scale: iconScale
1868
+ scale: iconScale,
1869
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance),
1870
+ // Would be great once we have a setting for this.
1871
+ // translucencyByDistance: getTranslucencyByDistance(params.minDistance, params.maxDistance),
1818
1872
  },
1819
1873
  position: EntityUtils.GetPos({
1820
1874
  viewer: params.viewer,
@@ -1865,7 +1919,8 @@ var EntityRenderEngine;
1865
1919
  extrudedHeight: fillHeight,
1866
1920
  heightReference: HeightReference.CLAMP_TO_GROUND,
1867
1921
  extrudedHeightReference: exHeightRef,
1868
- zIndex: 1
1922
+ zIndex: 1,
1923
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
1869
1924
  },
1870
1925
  position: pos === null || pos === void 0 ? void 0 : pos.clone(),
1871
1926
  show: false
@@ -1885,7 +1940,8 @@ var EntityRenderEngine;
1885
1940
  extrudedHeight: outlineHeight,
1886
1941
  heightReference: HeightReference.CLAMP_TO_GROUND,
1887
1942
  extrudedHeightReference: exHeightRef,
1888
- zIndex: 2
1943
+ zIndex: 2,
1944
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
1889
1945
  },
1890
1946
  position: pos === null || pos === void 0 ? void 0 : pos.clone()
1891
1947
  }));
@@ -1907,7 +1963,8 @@ var EntityRenderEngine;
1907
1963
  point: {
1908
1964
  pixelSize: size,
1909
1965
  color: cColor,
1910
- heightReference: getHeightRef(style)
1966
+ heightReference: getHeightRef(style),
1967
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
1911
1968
  },
1912
1969
  position: EntityUtils.GetPos({
1913
1970
  viewer: params.viewer,
@@ -1968,11 +2025,15 @@ var EntityRenderEngine;
1968
2025
  style: pStyle,
1969
2026
  tags: tags,
1970
2027
  viewer: params.viewer,
1971
- api: api
2028
+ api: api,
2029
+ maxDistance: zoomItem.MaxZoom,
2030
+ minDistance: zoomItem.MinZoom
1972
2031
  })];
1973
2032
  case 5:
1974
2033
  cEntity = _d.sent();
1975
- cEntity._renderGroup = getRenderGroupId(zoomItem, (_c = params.viewer) === null || _c === void 0 ? void 0 : _c.terrainProvider);
2034
+ if (cEntity) {
2035
+ cEntity._renderGroup = getRenderGroupId(zoomItem, (_c = params.viewer) === null || _c === void 0 ? void 0 : _c.terrainProvider);
2036
+ }
1976
2037
  cEntities[entity.Bruce.ID] = cEntity;
1977
2038
  _d.label = 6;
1978
2039
  case 6:
@@ -2057,7 +2118,8 @@ var EntityRenderEngine;
2057
2118
  classificationType: ClassificationType.TERRAIN,
2058
2119
  arcType: ArcType.GEODESIC,
2059
2120
  zIndex: getZIndex(style, entity, params.tags),
2060
- clampToGround: heightRef == HeightReference.CLAMP_TO_GROUND
2121
+ clampToGround: heightRef == HeightReference.CLAMP_TO_GROUND,
2122
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2061
2123
  },
2062
2124
  position: EntityUtils.GetPos({
2063
2125
  viewer: params.viewer,
@@ -2105,7 +2167,9 @@ var EntityRenderEngine;
2105
2167
  entity: entity,
2106
2168
  style: lStyle,
2107
2169
  tags: tags,
2108
- viewer: params.viewer
2170
+ viewer: params.viewer,
2171
+ maxDistance: zoomItem.MaxZoom,
2172
+ minDistance: zoomItem.MinZoom
2109
2173
  });
2110
2174
  if (cEntity) {
2111
2175
  cEntity._renderGroup = getRenderGroupId(zoomItem, (_c = params.viewer) === null || _c === void 0 ? void 0 : _c.terrainProvider);
@@ -2177,7 +2241,8 @@ var EntityRenderEngine;
2177
2241
  heightReference: heightRef,
2178
2242
  classificationType: ClassificationType.BOTH,
2179
2243
  perPositionHeight: heightRef == HeightReference.CLAMP_TO_GROUND ? false : true,
2180
- zIndex: zIndex
2244
+ zIndex: zIndex,
2245
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2181
2246
  },
2182
2247
  position: EntityUtils.GetPos({
2183
2248
  viewer: params.viewer,
@@ -2202,7 +2267,8 @@ var EntityRenderEngine;
2202
2267
  clampToGround: heightRef == HeightReference.CLAMP_TO_GROUND,
2203
2268
  classificationType: ClassificationType.TERRAIN,
2204
2269
  arcType: ArcType.GEODESIC,
2205
- zIndex: zIndex
2270
+ zIndex: zIndex,
2271
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2206
2272
  }),
2207
2273
  show: false
2208
2274
  });
@@ -2220,7 +2286,8 @@ var EntityRenderEngine;
2220
2286
  clampToGround: heightRef == HeightReference.CLAMP_TO_GROUND,
2221
2287
  classificationType: ClassificationType.TERRAIN,
2222
2288
  arcType: ArcType.GEODESIC,
2223
- zIndex: zIndex
2289
+ zIndex: zIndex,
2290
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2224
2291
  }),
2225
2292
  show: false
2226
2293
  });
@@ -2267,7 +2334,9 @@ var EntityRenderEngine;
2267
2334
  entity: entity,
2268
2335
  style: pStyle,
2269
2336
  tags: tags,
2270
- viewer: params.viewer
2337
+ viewer: params.viewer,
2338
+ maxDistance: zoomItem.MaxZoom,
2339
+ minDistance: zoomItem.MinZoom
2271
2340
  });
2272
2341
  if (cEntity) {
2273
2342
  cEntity._renderGroup = getRenderGroupId(zoomItem, (_c = params.viewer) === null || _c === void 0 ? void 0 : _c.terrainProvider);
@@ -2344,7 +2413,8 @@ var EntityRenderEngine;
2344
2413
  shadows: ShadowMode.ENABLED,
2345
2414
  colorBlendAmount: blendAmount,
2346
2415
  colorBlendMode: blendMode,
2347
- color: color
2416
+ color: color,
2417
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2348
2418
  },
2349
2419
  orientation: orientation,
2350
2420
  position: pos,
@@ -2458,7 +2528,9 @@ var EntityRenderEngine;
2458
2528
  api: api,
2459
2529
  fileId: lod.clientFileId
2460
2530
  }),
2461
- lodClientFileId: lod.clientFileId
2531
+ lodClientFileId: lod.clientFileId,
2532
+ maxDistance: zoomItem.MaxZoom,
2533
+ minDistance: zoomItem.MinZoom
2462
2534
  });
2463
2535
  if (cEntity) {
2464
2536
  cEntity._renderGroup = getRenderGroupId(zoomItem, (_e = params.viewer) === null || _e === void 0 ? void 0 : _e.terrainProvider);
@@ -2488,6 +2560,602 @@ var EntityRenderEngine;
2488
2560
  })(Model3d = EntityRenderEngine.Model3d || (EntityRenderEngine.Model3d = {}));
2489
2561
  })(EntityRenderEngine || (EntityRenderEngine = {}));
2490
2562
 
2563
+ function GetValue$1(viewer, obj) {
2564
+ if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
2565
+ return obj.getValue(viewer.scene.lastRenderTime);
2566
+ }
2567
+ return obj;
2568
+ }
2569
+ var Point = /** @class */ (function () {
2570
+ function Point(lon, lat, id) {
2571
+ this.lon = lon;
2572
+ this.lat = lat;
2573
+ this.id = id;
2574
+ }
2575
+ return Point;
2576
+ }());
2577
+ var Circle = /** @class */ (function () {
2578
+ function Circle(x, y, radius) {
2579
+ this.x = x;
2580
+ this.y = y;
2581
+ this.radius = radius;
2582
+ this.width = 2 * radius;
2583
+ this.height = 2 * radius;
2584
+ }
2585
+ Circle.prototype.Intersects = function (range) {
2586
+ var xDist = Math.abs(range.x - this.x);
2587
+ var yDist = Math.abs(range.y - this.y);
2588
+ var r = this.radius;
2589
+ var w = range.width;
2590
+ var h = range.height;
2591
+ if (xDist > (w + r) || yDist > (h + r)) {
2592
+ return false;
2593
+ }
2594
+ if (xDist <= w || yDist <= h) {
2595
+ return true;
2596
+ }
2597
+ var dx = xDist - w;
2598
+ var dy = yDist - h;
2599
+ return (dx * dx + dy * dy <= this.radius * this.radius);
2600
+ };
2601
+ Circle.prototype.Contains = function (point) {
2602
+ var dx = this.x - point.lon;
2603
+ var dy = this.y - point.lat;
2604
+ var distance = Math.sqrt(dx * dx + dy * dy);
2605
+ return distance <= this.radius;
2606
+ };
2607
+ return Circle;
2608
+ }());
2609
+ var Rectangle$1 = /** @class */ (function () {
2610
+ function Rectangle$$1(x, y, w, h) {
2611
+ this.x = x;
2612
+ this.y = y;
2613
+ this.w = w;
2614
+ this.h = h;
2615
+ this.width = 2 * w;
2616
+ this.height = 2 * h;
2617
+ }
2618
+ Rectangle$$1.prototype.Contains = function (point) {
2619
+ return (point.lon >= this.x - this.w &&
2620
+ point.lon < this.x + this.w &&
2621
+ point.lat >= this.y - this.h &&
2622
+ point.lat < this.y + this.h);
2623
+ };
2624
+ Rectangle$$1.prototype.Intersects = function (range) {
2625
+ return !(range.x - range.w > this.x + this.w ||
2626
+ range.x + range.w < this.x - this.w ||
2627
+ range.y - range.h > this.y + this.h ||
2628
+ range.y + range.h < this.y - this.h);
2629
+ };
2630
+ return Rectangle$$1;
2631
+ }());
2632
+ var Quad = /** @class */ (function () {
2633
+ function Quad(boundary, capacity) {
2634
+ this.boundary = boundary;
2635
+ this.capacity = capacity;
2636
+ this.points = [];
2637
+ this.divided = false;
2638
+ }
2639
+ Quad.prototype.Subdivide = function () {
2640
+ var x = this.boundary.x;
2641
+ var y = this.boundary.y;
2642
+ var w = this.boundary.w / 2;
2643
+ var h = this.boundary.h / 2;
2644
+ var ne = new Rectangle$1(x + w / 2, y - h / 2, w, h);
2645
+ this.northeast = new Quad(ne, this.capacity);
2646
+ var nw = new Rectangle$1(x - w / 2, y - h / 2, w, h);
2647
+ this.northwest = new Quad(nw, this.capacity);
2648
+ var se = new Rectangle$1(x + w / 2, y + h / 2, w, h);
2649
+ this.southeast = new Quad(se, this.capacity);
2650
+ var sw = new Rectangle$1(x - w / 2, y + h / 2, w, h);
2651
+ this.southwest = new Quad(sw, this.capacity);
2652
+ this.divided = true;
2653
+ };
2654
+ Quad.prototype.Insert = function (point) {
2655
+ if (!this.boundary.Contains(point)) {
2656
+ return false;
2657
+ }
2658
+ if (this.points.length < this.capacity) {
2659
+ this.points.push(point);
2660
+ return true;
2661
+ }
2662
+ if (!this.divided) {
2663
+ this.Subdivide();
2664
+ }
2665
+ return (this.northeast.Insert(point) || this.northwest.Insert(point) ||
2666
+ this.southeast.Insert(point) || this.southwest.Insert(point));
2667
+ };
2668
+ Quad.prototype.Query = function (range, found) {
2669
+ if (!found) {
2670
+ found = [];
2671
+ }
2672
+ if (!range.Intersects(this.boundary)) {
2673
+ return found;
2674
+ }
2675
+ for (var _i = 0, _a = this.points; _i < _a.length; _i++) {
2676
+ var p = _a[_i];
2677
+ if (range.Contains(p)) {
2678
+ found.push(p);
2679
+ }
2680
+ }
2681
+ if (this.divided) {
2682
+ this.northwest.Query(range, found);
2683
+ this.northeast.Query(range, found);
2684
+ this.southwest.Query(range, found);
2685
+ this.southeast.Query(range, found);
2686
+ }
2687
+ return found;
2688
+ };
2689
+ Quad.prototype.Find = function (id) {
2690
+ for (var _i = 0, _a = this.points; _i < _a.length; _i++) {
2691
+ var point = _a[_i];
2692
+ if (point.id === id) {
2693
+ return point;
2694
+ }
2695
+ }
2696
+ if (this.divided) {
2697
+ return this.northwest.Find(id) || this.northeast.Find(id) ||
2698
+ this.southwest.Find(id) || this.southeast.Find(id);
2699
+ }
2700
+ return null;
2701
+ };
2702
+ Quad.prototype.Remove = function (point) {
2703
+ var index = this.points.indexOf(point);
2704
+ if (index !== -1) {
2705
+ this.points.splice(index, 1);
2706
+ }
2707
+ if (this.divided) {
2708
+ this.northwest.Remove(point);
2709
+ this.northeast.Remove(point);
2710
+ this.southwest.Remove(point);
2711
+ this.southeast.Remove(point);
2712
+ }
2713
+ };
2714
+ return Quad;
2715
+ }());
2716
+ var PointClustering = /** @class */ (function () {
2717
+ function PointClustering(register, menuItemId) {
2718
+ var _this = this;
2719
+ this.disposed = false;
2720
+ this.registeredEntityIds = new Set();
2721
+ this.register = register;
2722
+ this.viewer = register.Viewer;
2723
+ this.menuItemId = menuItemId;
2724
+ this.updateClusterSpacing(0);
2725
+ var boundary = new Rectangle$1(0, 0, 360, 180);
2726
+ this.quadTree = new Quad(boundary, 4);
2727
+ this.prevClusteredEntities = new Set();
2728
+ this.currClusteredEntities = new Set();
2729
+ this.clusterEntities = new Map();
2730
+ this.updateQueue = new DelayQueue(function () {
2731
+ _this.doUpdate();
2732
+ }, 1000);
2733
+ this.listenCamera();
2734
+ }
2735
+ /**
2736
+ * Starts listening to camera changes.
2737
+ * This will trigger the clustering update whenever camera is moved.
2738
+ */
2739
+ PointClustering.prototype.listenCamera = function () {
2740
+ var _this = this;
2741
+ var viewer = this.viewer;
2742
+ var lastPos3d;
2743
+ var hasMoved = function () {
2744
+ var _a;
2745
+ var cameraPos = (_a = viewer === null || viewer === void 0 ? void 0 : viewer.camera) === null || _a === void 0 ? void 0 : _a.positionCartographic;
2746
+ if (!cameraPos) {
2747
+ return false;
2748
+ }
2749
+ var pos3d = Cartographic.toCartesian(cameraPos);
2750
+ if (!lastPos3d) {
2751
+ lastPos3d = pos3d;
2752
+ return false;
2753
+ }
2754
+ var distance = Cartesian3.distance(pos3d, lastPos3d);
2755
+ lastPos3d = pos3d;
2756
+ // 50 meter movement at least.
2757
+ return distance > 50;
2758
+ };
2759
+ this.listenCameraRemoval = viewer.scene.camera.changed.addEventListener(function () {
2760
+ if (hasMoved()) {
2761
+ _this.updateQueue.Call();
2762
+ }
2763
+ });
2764
+ };
2765
+ /**
2766
+ * Stops listening to camera changes.
2767
+ */
2768
+ PointClustering.prototype.unlistenCamera = function () {
2769
+ if (this.listenCameraRemoval) {
2770
+ this.listenCameraRemoval();
2771
+ this.listenCameraRemoval = null;
2772
+ }
2773
+ };
2774
+ /**
2775
+ * Removes all clusters and updates entities to no longer be suppressed.
2776
+ * @returns
2777
+ */
2778
+ PointClustering.prototype.Dispose = function () {
2779
+ if (this.disposed) {
2780
+ return;
2781
+ }
2782
+ for (var _i = 0, _a = Array.from(this.clusterEntities); _i < _a.length; _i++) {
2783
+ var _b = _a[_i], entity = _b[1];
2784
+ this.viewer.entities.remove(entity);
2785
+ }
2786
+ this.clusterEntities.clear();
2787
+ this.unlistenCamera();
2788
+ this.disposed = true;
2789
+ // Restore entities.
2790
+ var toUpdateIds = [];
2791
+ for (var _c = 0, _d = Array.from(this.registeredEntityIds); _c < _d.length; _c++) {
2792
+ var id = _d[_c];
2793
+ var rego = this.register.GetRego({
2794
+ entityId: id,
2795
+ menuItemId: this.menuItemId
2796
+ });
2797
+ if (rego && rego.suppressShow) {
2798
+ rego.suppressShow = false;
2799
+ toUpdateIds.push(id);
2800
+ }
2801
+ }
2802
+ if (toUpdateIds.length) {
2803
+ this.register.ForceUpdate({
2804
+ entityIds: toUpdateIds,
2805
+ });
2806
+ }
2807
+ };
2808
+ /**
2809
+ * Calculates center of given points.
2810
+ * @param points
2811
+ * @returns
2812
+ */
2813
+ PointClustering.prototype.calculateCentroid = function (points) {
2814
+ var lonSum = 0;
2815
+ var latSum = 0;
2816
+ for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
2817
+ var point = points_1[_i];
2818
+ lonSum += point.lon;
2819
+ latSum += point.lat;
2820
+ }
2821
+ var lonAvg = lonSum / points.length;
2822
+ var latAvg = latSum / points.length;
2823
+ return new Point(lonAvg, latAvg, "");
2824
+ };
2825
+ /**
2826
+ * Gathers current clusters and renders them.
2827
+ * @returns
2828
+ */
2829
+ PointClustering.prototype.doUpdate = function () {
2830
+ var _this = this;
2831
+ if (this.disposed) {
2832
+ return;
2833
+ }
2834
+ // 1: Update precision.
2835
+ // This defines how far apart these clusters can be.
2836
+ var cameraHeight = this.viewer.camera.positionCartographic.height;
2837
+ this.updateClusterSpacing(cameraHeight);
2838
+ // 2: Get clusters.
2839
+ var _a = this.getClusters(), clusters = _a.clusters, noLongerClustered = _a.noLongerClustered;
2840
+ // 3: Remove all cesium cluster entities that are no longer clustered.
2841
+ for (var _i = 0, _b = Array.from(noLongerClustered); _i < _b.length; _i++) {
2842
+ var id = _b[_i];
2843
+ this.removeClusterEntity(id);
2844
+ }
2845
+ // 4: Stop hiding entities that are no longer clustered.
2846
+ var previousEntityIds = new Set(this.registeredEntityIds);
2847
+ for (var _c = 0, _d = Array.from(previousEntityIds); _c < _d.length; _c++) {
2848
+ var id = _d[_c];
2849
+ if (!this.currClusteredEntities.has(id)) {
2850
+ var rego = this.register.GetRego({
2851
+ entityId: id,
2852
+ menuItemId: this.menuItemId
2853
+ });
2854
+ if (rego && rego.suppressShow) {
2855
+ rego.suppressShow = false;
2856
+ this.register.ForceUpdate({
2857
+ entityIds: [id],
2858
+ });
2859
+ }
2860
+ }
2861
+ }
2862
+ var getScale = function (count) {
2863
+ var baseSize = 20;
2864
+ var scalingFactor = 2;
2865
+ var scale = baseSize + scalingFactor * (count - 1);
2866
+ scale = Math.min(scale, 120);
2867
+ return scale;
2868
+ };
2869
+ var getLabel = function (count) {
2870
+ var color = _this.pointColorTxt ? _this.pointColorTxt : "white";
2871
+ var canvas = document.createElement("canvas");
2872
+ var ctx = canvas.getContext("2d");
2873
+ var size = getScale(count);
2874
+ canvas.width = size;
2875
+ canvas.height = size;
2876
+ ctx.font = "bold 20px Arial";
2877
+ ctx.fillStyle = color;
2878
+ ctx.textAlign = "center";
2879
+ ctx.textBaseline = "middle";
2880
+ ctx.fillText(String(count), size / 2, size / 2);
2881
+ return canvas;
2882
+ };
2883
+ // 5: iterate over clusters and add/update them as Cesium entities.
2884
+ for (var _e = 0, clusters_1 = clusters; _e < clusters_1.length; _e++) {
2885
+ var cluster = clusters_1[_e];
2886
+ var clusterId = cluster.center.id;
2887
+ var clusterEntity = this.clusterEntities.get(clusterId);
2888
+ var centroid = this.calculateCentroid(cluster.points);
2889
+ var count = cluster.points.length;
2890
+ if (clusterEntity) {
2891
+ clusterEntity.position = Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150);
2892
+ clusterEntity.point.pixelSize = getScale(cluster.points.length);
2893
+ clusterEntity.billboard.image = getLabel(cluster.points.length);
2894
+ clusterEntity.billboard.width = getScale(cluster.points.length);
2895
+ clusterEntity.billboard.height = getScale(cluster.points.length);
2896
+ }
2897
+ else {
2898
+ clusterEntity = this.viewer.entities.add({
2899
+ position: Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150),
2900
+ point: {
2901
+ heightReference: HeightReference.NONE,
2902
+ pixelSize: getScale(count),
2903
+ color: this.pointColorBg ? this.pointColorBg : Color.fromCssColorString("#4287f5")
2904
+ },
2905
+ billboard: {
2906
+ heightReference: HeightReference.NONE,
2907
+ image: getLabel(count),
2908
+ width: getScale(count),
2909
+ height: getScale(count),
2910
+ verticalOrigin: VerticalOrigin.CENTER,
2911
+ horizontalOrigin: HorizontalOrigin.CENTER,
2912
+ disableDepthTestDistance: Number.POSITIVE_INFINITY
2913
+ }
2914
+ });
2915
+ this.clusterEntities.set(clusterId, clusterEntity);
2916
+ }
2917
+ for (var i = 0; i < cluster.points.length; i++) {
2918
+ var entityId = cluster.points[i].id;
2919
+ var rego = this.register.GetRego({
2920
+ entityId: entityId,
2921
+ menuItemId: this.menuItemId
2922
+ });
2923
+ if (rego && !rego.suppressShow) {
2924
+ rego.suppressShow = true;
2925
+ this.register.ForceUpdate({
2926
+ entityIds: [entityId],
2927
+ });
2928
+ }
2929
+ }
2930
+ }
2931
+ var _loop_1 = function (clusterId, clusterEntity) {
2932
+ if (!clusters.find(function (x) { return x.center.id == clusterId; })) {
2933
+ this_1.viewer.entities.remove(clusterEntity);
2934
+ this_1.clusterEntities.delete(clusterId);
2935
+ }
2936
+ };
2937
+ var this_1 = this;
2938
+ // 6: Iterate over existing cluster entities and remove those that are no longer clustered.
2939
+ for (var _f = 0, _g = Array.from(this.clusterEntities); _f < _g.length; _f++) {
2940
+ var _h = _g[_f], clusterId = _h[0], clusterEntity = _h[1];
2941
+ _loop_1(clusterId, clusterEntity);
2942
+ }
2943
+ };
2944
+ /**
2945
+ * Updates how apart clusters can be based on camera distance.
2946
+ * @param cameraHeight
2947
+ */
2948
+ PointClustering.prototype.updateClusterSpacing = function (cameraHeight) {
2949
+ // Camera height thresholds in meters.
2950
+ var cameraHeightThresholds = [2000, 5000, 8000, 13000, 25000, 40000];
2951
+ // Distance increments in degrees.
2952
+ var distanceIncrements = [0.005, 0.01, 0.02, 0.04, 0.1, 0.5];
2953
+ // Find the appropriate spacing based on the camera height.
2954
+ var spacing = 0;
2955
+ for (var i = 0; i < cameraHeightThresholds.length; i++) {
2956
+ if (cameraHeight && cameraHeight < cameraHeightThresholds[i]) {
2957
+ spacing += distanceIncrements[i];
2958
+ break;
2959
+ }
2960
+ spacing += distanceIncrements[i];
2961
+ }
2962
+ this.distanceBetweenClusters = spacing;
2963
+ };
2964
+ /**
2965
+ * Gathers clusters.
2966
+ * @returns
2967
+ */
2968
+ PointClustering.prototype.getClusters = function () {
2969
+ var _this = this;
2970
+ this.currClusteredEntities.clear();
2971
+ var clusters = [];
2972
+ var processedPoints = new Set();
2973
+ var cameraPosition = this.viewer.camera.position;
2974
+ for (var _i = 0, _a = this.quadTree.points; _i < _a.length; _i++) {
2975
+ var point = _a[_i];
2976
+ // Skip points already processed in previous clusters.
2977
+ if (processedPoints.has(point.id)) {
2978
+ continue;
2979
+ }
2980
+ // Skip points closer than 2000 meters to the camera.
2981
+ var cartesian3 = Cartesian3.fromDegrees(point.lon, point.lat);
2982
+ if (Cartesian3.distance(cartesian3, cameraPosition) <= 2000) {
2983
+ continue;
2984
+ }
2985
+ var found = [];
2986
+ var nearbyPoints = this.quadTree.Query(new Circle(point.lon, point.lat, this.distanceBetweenClusters), found);
2987
+ if (nearbyPoints.length > 1) {
2988
+ var cluster = { center: point, points: [] };
2989
+ for (var _b = 0, nearbyPoints_1 = nearbyPoints; _b < nearbyPoints_1.length; _b++) {
2990
+ var nearby = nearbyPoints_1[_b];
2991
+ if (!cluster.points.includes(nearby)) {
2992
+ cluster.points.push(nearby);
2993
+ processedPoints.add(nearby.id);
2994
+ this.currClusteredEntities.add(nearby.id);
2995
+ }
2996
+ }
2997
+ clusters.push(cluster);
2998
+ }
2999
+ }
3000
+ // Filter out clusters with only one point.
3001
+ var validClusters = clusters.filter(function (cluster) { return cluster.points.length > 1; });
3002
+ // Merge adjacent clusters.
3003
+ var mergedClusters = this.mergeClusters(validClusters);
3004
+ // Get the entity IDs that are no longer clustered
3005
+ var noLongerClustered = new Set(Array.from(this.prevClusteredEntities).filter(function (id) { return !_this.currClusteredEntities.has(id); }));
3006
+ // Update the previous clustered entities ref.
3007
+ this.prevClusteredEntities = new Set(this.currClusteredEntities);
3008
+ return { clusters: mergedClusters, noLongerClustered: noLongerClustered };
3009
+ };
3010
+ /**
3011
+ * Merges clusters that are nearby based on the distanceBetweenClusters value.
3012
+ * @param clusters
3013
+ * @returns
3014
+ */
3015
+ PointClustering.prototype.mergeClusters = function (clusters) {
3016
+ var _a;
3017
+ var mergedClusters = [].concat(clusters);
3018
+ // Keep looping while merges keep happening.
3019
+ var mergeOccurred = true;
3020
+ while (mergeOccurred) {
3021
+ mergeOccurred = false;
3022
+ for (var i = 0; i < mergedClusters.length - 1; i++) {
3023
+ for (var j = i + 1; j < mergedClusters.length; j++) {
3024
+ var cluster1 = mergedClusters[i];
3025
+ var cluster2 = mergedClusters[j];
3026
+ var centerDistance = this.calculateDistance(cluster1.center.lon, cluster1.center.lat, cluster2.center.lon, cluster2.center.lat);
3027
+ var distanceThreshold = this.distanceBetweenClusters;
3028
+ if (centerDistance <= distanceThreshold) {
3029
+ // Merge clusters.
3030
+ (_a = cluster1.points).push.apply(_a, cluster2.points);
3031
+ mergedClusters.splice(j, 1);
3032
+ this.removeClusterEntity(cluster2.center.id);
3033
+ mergeOccurred = true;
3034
+ break;
3035
+ }
3036
+ }
3037
+ if (mergeOccurred) {
3038
+ break;
3039
+ }
3040
+ }
3041
+ }
3042
+ return mergedClusters;
3043
+ };
3044
+ /**
3045
+ * Removes Cesium cluster entity.
3046
+ * @param clusterId
3047
+ */
3048
+ PointClustering.prototype.removeClusterEntity = function (clusterId) {
3049
+ var clusterEntity = this.clusterEntities.get(clusterId);
3050
+ if (clusterEntity) {
3051
+ this.viewer.entities.remove(clusterEntity);
3052
+ this.clusterEntities.delete(clusterId);
3053
+ }
3054
+ };
3055
+ PointClustering.prototype.convertCartesianToCartographic = function (cartesian3) {
3056
+ var carto = Cartographic.fromCartesian(cartesian3);
3057
+ var lon = Math$1.toDegrees(carto.longitude);
3058
+ var lat = Math$1.toDegrees(carto.latitude);
3059
+ var id = lon + ',' + lat;
3060
+ return new Point(lon, lat, id);
3061
+ };
3062
+ /**
3063
+ * Adds new entity to the clustering logic.
3064
+ * @param id Bruce entity ID.
3065
+ * @param cartesian3 entity's position.
3066
+ */
3067
+ PointClustering.prototype.addPoint = function (id, cartesian3) {
3068
+ var point = this.convertCartesianToCartographic(cartesian3);
3069
+ point.id = id;
3070
+ this.quadTree.Insert(point);
3071
+ };
3072
+ /**
3073
+ * Calculates rough distance across earth between two points.
3074
+ * @param lon1
3075
+ * @param lat1
3076
+ * @param lon2
3077
+ * @param lat2
3078
+ * @returns
3079
+ */
3080
+ PointClustering.prototype.calculateDistance = function (lon1, lat1, lon2, lat2) {
3081
+ var lonDelta = Math.abs(lon1 - lon2);
3082
+ var latDelta = Math.abs(lat1 - lat2);
3083
+ // Approximate radius of the Earth in kilometers
3084
+ var earthRadius = 6371;
3085
+ var distance = 2 * Math.asin(Math.sqrt(Math.sin(latDelta / 2) * Math.sin(latDelta / 2) +
3086
+ Math.cos(lat1) * Math.cos(lat2) * Math.sin(lonDelta / 2) * Math.sin(lonDelta / 2))) * earthRadius;
3087
+ return distance;
3088
+ };
3089
+ /**
3090
+ * Adds entity to clustering logic.
3091
+ * Will return false if entity could not be clustered and therefor should not be hidden.
3092
+ * @param id
3093
+ * @param entity
3094
+ * @returns
3095
+ */
3096
+ PointClustering.prototype.AddEntity = function (id, entity) {
3097
+ if (this.disposed) {
3098
+ return false;
3099
+ }
3100
+ if (!entity) {
3101
+ return false;
3102
+ }
3103
+ if (entity.polygon || entity.polyline) {
3104
+ return false;
3105
+ }
3106
+ var pos3d = GetValue$1(this.viewer, entity.position);
3107
+ if (!(pos3d === null || pos3d === void 0 ? void 0 : pos3d.x)) {
3108
+ return false;
3109
+ }
3110
+ if (!this.pointColorBg && entity.point) {
3111
+ this.pointColorBg = GetValue$1(this.viewer, entity.point.color);
3112
+ if (this.pointColorBg) {
3113
+ var cColor = null;
3114
+ if (this.pointColorBg instanceof Object) {
3115
+ cColor = new Color(this.pointColorBg.red, this.pointColorBg.green, this.pointColorBg.blue, this.pointColorBg.alpha);
3116
+ }
3117
+ else if (typeof this.pointColorBg === "string") {
3118
+ cColor = Color.fromCssColorString(this.pointColorBg);
3119
+ }
3120
+ // Determine if text color should instead be black based on background.
3121
+ // cColor contains r,g,b,a values where r,g,b are in the range [0,1].
3122
+ if (cColor) {
3123
+ var brightness = (cColor.red * 299 + cColor.green * 587 + cColor.blue * 114) / 1000;
3124
+ if (brightness > 0.5) {
3125
+ this.pointColorTxt = "black";
3126
+ }
3127
+ else {
3128
+ this.pointColorTxt = "white";
3129
+ }
3130
+ }
3131
+ }
3132
+ }
3133
+ this.registeredEntityIds.add(id);
3134
+ this.addPoint(id, pos3d);
3135
+ this.updateQueue.Call();
3136
+ return true;
3137
+ };
3138
+ /**
3139
+ * Removes entity from clustering logic.
3140
+ * Warning: This will not reveal the entity, suppressShow will remain true.
3141
+ * This is made with the assumption that the entity is being removed from viewer.
3142
+ * @param id
3143
+ * @returns
3144
+ */
3145
+ PointClustering.prototype.RemoveEntity = function (id) {
3146
+ if (this.disposed) {
3147
+ return;
3148
+ }
3149
+ var pointToRemove = this.quadTree.Find(id);
3150
+ if (pointToRemove) {
3151
+ this.quadTree.Remove(pointToRemove);
3152
+ this.updateQueue.Call();
3153
+ }
3154
+ this.registeredEntityIds.delete(id);
3155
+ };
3156
+ return PointClustering;
3157
+ }());
3158
+
2491
3159
  var BATCH_SIZE = 500;
2492
3160
  var CHECK_BATCH_SIZE = 250;
2493
3161
  /**
@@ -2516,6 +3184,9 @@ var EntitiesRenderManager;
2516
3184
  this.apiGetter = apiGetter;
2517
3185
  this.item = item;
2518
3186
  this.visualsManager = visualsManager;
3187
+ if (item.enableClustering) {
3188
+ this.clustering = new PointClustering(this.visualsManager, this.item.id);
3189
+ }
2519
3190
  }
2520
3191
  Object.defineProperty(Manager.prototype, "Disposed", {
2521
3192
  get: function () {
@@ -2526,7 +3197,7 @@ var EntitiesRenderManager;
2526
3197
  });
2527
3198
  Manager.prototype.Init = function (params) {
2528
3199
  var _this = this;
2529
- var _a, _b, _c, _d, _e;
3200
+ var _a, _b, _c, _d, _e, _f, _g;
2530
3201
  if (this.disposed) {
2531
3202
  throw (new Error("This item is disposed."));
2532
3203
  }
@@ -2558,17 +3229,22 @@ var EntitiesRenderManager;
2558
3229
  menuItemId: this.item.id,
2559
3230
  retainTagIds: tagsToRender
2560
3231
  });
3232
+ (_e = this.clustering) === null || _e === void 0 ? void 0 : _e.Dispose();
2561
3233
  }
2562
3234
  else {
2563
3235
  this.visualsManager.RemoveRegos({
2564
3236
  menuItemId: this.item.id
2565
3237
  });
3238
+ (_f = this.clustering) === null || _f === void 0 ? void 0 : _f.Dispose();
2566
3239
  return;
2567
3240
  }
3241
+ if (this.item.enableClustering) {
3242
+ this.clustering = new PointClustering(this.visualsManager, this.item.id);
3243
+ }
2568
3244
  var api = this.apiGetter.getApi();
2569
3245
  this.getter = this.sharedGetters.GetOrCreateFilterGetter({
2570
3246
  api: api,
2571
- attrFilter: (_e = this.item.BruceEntity.Filter) !== null && _e !== void 0 ? _e : {},
3247
+ attrFilter: (_g = this.item.BruceEntity.Filter) !== null && _g !== void 0 ? _g : {},
2572
3248
  batchSize: BATCH_SIZE,
2573
3249
  typeId: this.item.BruceEntity["EntityType.ID"],
2574
3250
  monitor: this.monitor,
@@ -2600,7 +3276,13 @@ var EntitiesRenderManager;
2600
3276
  _this.entityCheckQueue.Call();
2601
3277
  });
2602
3278
  this.entityCheckQueue = new DelayQueue(function () {
2603
- _this.doEntityCheck(Object.keys(_this.renderedEntities));
3279
+ var _a;
3280
+ // Don't bother checking for zoom control changes if we only have 1 item.
3281
+ // We'll let Cesium handle hide/show at max zoom range.
3282
+ var shouldCheck = ((_a = _this.item) === null || _a === void 0 ? void 0 : _a.CameraZoomSettings) && _this.item.CameraZoomSettings.length > 1;
3283
+ if (shouldCheck) {
3284
+ _this.doEntityCheck(Object.keys(_this.renderedEntities));
3285
+ }
2604
3286
  }, 3000);
2605
3287
  };
2606
3288
  Manager.prototype.Dispose = function () {
@@ -2610,7 +3292,7 @@ var EntitiesRenderManager;
2610
3292
  this.doDispose();
2611
3293
  };
2612
3294
  Manager.prototype.doDispose = function () {
2613
- var _a, _b, _c;
3295
+ var _a, _b, _c, _d;
2614
3296
  (_a = this.getterSub) === null || _a === void 0 ? void 0 : _a.call(this);
2615
3297
  this.getterSub = null;
2616
3298
  if (this.getter) {
@@ -2624,6 +3306,7 @@ var EntitiesRenderManager;
2624
3306
  (_c = this.viewMonitorRemoval) === null || _c === void 0 ? void 0 : _c.call(this);
2625
3307
  clearInterval(this.renderQueueInterval);
2626
3308
  this.renderQueue = [];
3309
+ (_d = this.clustering) === null || _d === void 0 ? void 0 : _d.Dispose();
2627
3310
  };
2628
3311
  Manager.prototype.ReRender = function (params) {
2629
3312
  return __awaiter(this, void 0, void 0, function () {
@@ -2757,14 +3440,14 @@ var EntitiesRenderManager;
2757
3440
  }
2758
3441
  };
2759
3442
  Manager.prototype.renderEntities = function (entities, force) {
2760
- var _a, _b, _c;
3443
+ var _a, _b, _c, _d;
2761
3444
  if (force === void 0) { force = false; }
2762
3445
  return __awaiter(this, void 0, void 0, function () {
2763
- var typeId_1, cEntities, i, entity, id, cEntity, visual, tagIds, e_3;
2764
- return __generator(this, function (_d) {
2765
- switch (_d.label) {
3446
+ var typeId_1, cEntities, i, entity, id, cEntity, visual, wasClustered, tagIds, rego, e_3;
3447
+ return __generator(this, function (_e) {
3448
+ switch (_e.label) {
2766
3449
  case 0:
2767
- _d.trys.push([0, 2, , 3]);
3450
+ _e.trys.push([0, 2, , 3]);
2768
3451
  if (this.disposed || this.viewer.isDestroyed()) {
2769
3452
  return [2 /*return*/];
2770
3453
  }
@@ -2782,7 +3465,7 @@ var EntitiesRenderManager;
2782
3465
  force: force
2783
3466
  })];
2784
3467
  case 1:
2785
- cEntities = _d.sent();
3468
+ cEntities = _e.sent();
2786
3469
  if (this.disposed) {
2787
3470
  this.doDispose();
2788
3471
  return [2 /*return*/];
@@ -2798,17 +3481,20 @@ var EntitiesRenderManager;
2798
3481
  menuItemId: this.item.id
2799
3482
  })) === null || _b === void 0 ? void 0 : _b.visual;
2800
3483
  if (!visual || visual != cEntity) {
3484
+ wasClustered = this.clustering ? this.clustering.AddEntity(id, cEntity) : false;
2801
3485
  tagIds = (_c = entity.Bruce) === null || _c === void 0 ? void 0 : _c["Layer.ID"];
3486
+ rego = {
3487
+ entityId: id,
3488
+ menuItemId: this.item.id,
3489
+ visual: cEntity,
3490
+ priority: 0,
3491
+ entityTypeId: entity.Bruce["EntityType.ID"],
3492
+ accountId: this.apiGetter.accountId,
3493
+ tagIds: tagIds ? [].concat(tagIds) : [],
3494
+ suppressShow: wasClustered
3495
+ };
2802
3496
  this.visualsManager.AddRego({
2803
- rego: {
2804
- entityId: id,
2805
- menuItemId: this.item.id,
2806
- visual: cEntity,
2807
- priority: 0,
2808
- entityTypeId: entity.Bruce["EntityType.ID"],
2809
- accountId: this.apiGetter.accountId,
2810
- tagIds: tagIds ? [].concat(tagIds) : []
2811
- }
3497
+ rego: rego
2812
3498
  });
2813
3499
  }
2814
3500
  }
@@ -2817,12 +3503,13 @@ var EntitiesRenderManager;
2817
3503
  entityId: id,
2818
3504
  menuItemId: this.item.id
2819
3505
  });
3506
+ (_d = this.clustering) === null || _d === void 0 ? void 0 : _d.RemoveEntity(id);
2820
3507
  }
2821
3508
  }
2822
3509
  this.viewer.scene.requestRender();
2823
3510
  return [3 /*break*/, 3];
2824
3511
  case 2:
2825
- e_3 = _d.sent();
3512
+ e_3 = _e.sent();
2826
3513
  console.error(e_3);
2827
3514
  return [3 /*break*/, 3];
2828
3515
  case 3: return [2 /*return*/];
@@ -3597,6 +4284,34 @@ var RelationRenderEngine;
3597
4284
  })(Parabola = RelationRenderEngine.Parabola || (RelationRenderEngine.Parabola = {}));
3598
4285
  })(RelationRenderEngine || (RelationRenderEngine = {}));
3599
4286
 
4287
+ /**
4288
+ * Returns if a given visual is alive and in the scene.
4289
+ * @param viewer
4290
+ * @param visual
4291
+ * @returns
4292
+ */
4293
+ function isAlive$1(viewer, visual) {
4294
+ if (!(viewer === null || viewer === void 0 ? void 0 : viewer.scene) || viewer.isDestroyed()) {
4295
+ return false;
4296
+ }
4297
+ if (visual instanceof Entity) {
4298
+ return viewer.entities.contains(visual);
4299
+ }
4300
+ else if (visual instanceof Primitive) {
4301
+ return viewer.scene.primitives.contains(visual);
4302
+ }
4303
+ else if (visual instanceof Cesium3DTileFeature) {
4304
+ var cTileset = visual === null || visual === void 0 ? void 0 : visual.tileset;
4305
+ if (!cTileset) {
4306
+ return false;
4307
+ }
4308
+ if (cTileset.isDestroyed() || !viewer.scene.primitives.contains(cTileset)) {
4309
+ return false;
4310
+ }
4311
+ return true;
4312
+ }
4313
+ return false;
4314
+ }
3600
4315
  function removeEntity(viewer, visual) {
3601
4316
  unmarkEntity(visual, false);
3602
4317
  if (visual instanceof Entity) {
@@ -3637,6 +4352,9 @@ function updateCEntityShow(viewer, visual, show, ignoreParent) {
3637
4352
  }
3638
4353
  }
3639
4354
  function updateEntityShow(viewer, visual, show) {
4355
+ if (!isAlive$1(viewer, visual)) {
4356
+ return;
4357
+ }
3640
4358
  if (visual instanceof Entity) {
3641
4359
  updateCEntityShow(viewer, visual, show, false);
3642
4360
  }
@@ -3683,7 +4401,7 @@ function updateEntity(viewer, entityId, register) {
3683
4401
  for (var i = 0; i < regos.length; i++) {
3684
4402
  var rego = regos[i];
3685
4403
  rego.best = rego === highestPriority;
3686
- updateEntityShow(viewer, rego.visual, getShowState(rego));
4404
+ updateEntityShow(viewer, rego.visual, rego.suppressShow ? false : getShowState(rego));
3687
4405
  }
3688
4406
  }
3689
4407
  function markEntity(register, rego, visual, ignoreParent) {
@@ -3720,6 +4438,9 @@ function unmarkEntity(visual, ignoreParent) {
3720
4438
  var ORG_COLOR_KEY = "_org_color_";
3721
4439
  function select(viewer, visual, color) {
3722
4440
  var _a;
4441
+ if (!isAlive$1(viewer, visual)) {
4442
+ return;
4443
+ }
3723
4444
  if (!color) {
3724
4445
  color = Color.fromAlpha(Color.YELLOW, 0.5);
3725
4446
  }
@@ -3779,6 +4500,9 @@ function select(viewer, visual, color) {
3779
4500
  }
3780
4501
  }
3781
4502
  function deselect(viewer, visual) {
4503
+ if (!isAlive$1(viewer, visual)) {
4504
+ return;
4505
+ }
3782
4506
  if (visual instanceof Entity) {
3783
4507
  var entities = EntityUtils.GatherEntity({
3784
4508
  entity: visual
@@ -3874,6 +4598,17 @@ var VisualsRegister;
3874
4598
  enumerable: false,
3875
4599
  configurable: true
3876
4600
  });
4601
+ Register.prototype.ForceUpdate = function (params) {
4602
+ var entityIds = params.entityIds;
4603
+ for (var i = 0; i < entityIds.length; i++) {
4604
+ var entityId = entityIds[i];
4605
+ updateEntity(this.viewer, entityId, this);
4606
+ this.OnUpdate.Trigger({
4607
+ type: EVisualUpdateType.Update,
4608
+ entityId: entityId
4609
+ });
4610
+ }
4611
+ };
3877
4612
  Register.prototype.SetSelectionColor = function (color) {
3878
4613
  this.selectionColor = color;
3879
4614
  };
@@ -4396,6 +5131,9 @@ var EntitiesIdsRenderManager;
4396
5131
  this.monitor = monitor;
4397
5132
  this.item = item;
4398
5133
  this.visualsManager = visualsManager;
5134
+ if (this.item.enableClustering) {
5135
+ this.clustering = new PointClustering(visualsManager, this.item.id);
5136
+ }
4399
5137
  }
4400
5138
  Object.defineProperty(Manager.prototype, "Disposed", {
4401
5139
  get: function () {
@@ -4416,7 +5154,7 @@ var EntitiesIdsRenderManager;
4416
5154
  this.getter.Start();
4417
5155
  };
4418
5156
  Manager.prototype.Dispose = function () {
4419
- var _a;
5157
+ var _a, _b;
4420
5158
  if (this.disposed) {
4421
5159
  return;
4422
5160
  }
@@ -4426,6 +5164,7 @@ var EntitiesIdsRenderManager;
4426
5164
  this.visualsManager.RemoveRegos({
4427
5165
  menuItemId: this.item.id
4428
5166
  });
5167
+ (_b = this.clustering) === null || _b === void 0 ? void 0 : _b.Dispose();
4429
5168
  };
4430
5169
  Manager.prototype.ReRender = function (params) {
4431
5170
  return __awaiter(this, void 0, void 0, function () {
@@ -4494,19 +5233,19 @@ var EntitiesIdsRenderManager;
4494
5233
  });
4495
5234
  };
4496
5235
  Manager.prototype.renderEntities = function (entities, force) {
4497
- var _a;
5236
+ var _a, _b;
4498
5237
  if (force === void 0) { force = false; }
4499
5238
  return __awaiter(this, void 0, void 0, function () {
4500
- var cEntities, i, entity, id, cEntity, visual, e_2;
4501
- return __generator(this, function (_b) {
4502
- switch (_b.label) {
5239
+ var cEntities, i, entity, id, cEntity, visual, clustered, e_2;
5240
+ return __generator(this, function (_c) {
5241
+ switch (_c.label) {
4503
5242
  case 0:
4504
5243
  if (this.disposed || this.viewer.isDestroyed()) {
4505
5244
  return [2 /*return*/];
4506
5245
  }
4507
- _b.label = 1;
5246
+ _c.label = 1;
4508
5247
  case 1:
4509
- _b.trys.push([1, 3, , 4]);
5248
+ _c.trys.push([1, 3, , 4]);
4510
5249
  return [4 /*yield*/, EntityRenderEngine.Render({
4511
5250
  viewer: this.viewer,
4512
5251
  apiGetter: this.apiGetter,
@@ -4517,7 +5256,7 @@ var EntitiesIdsRenderManager;
4517
5256
  force: force
4518
5257
  })];
4519
5258
  case 2:
4520
- cEntities = _b.sent();
5259
+ cEntities = _c.sent();
4521
5260
  for (i = 0; i < entities.length; i++) {
4522
5261
  entity = entities[i];
4523
5262
  id = entity.Bruce.ID;
@@ -4529,6 +5268,7 @@ var EntitiesIdsRenderManager;
4529
5268
  menuItemId: this.item.id
4530
5269
  })) === null || _a === void 0 ? void 0 : _a.visual;
4531
5270
  if (!visual || visual != cEntity) {
5271
+ clustered = this.clustering ? this.clustering.AddEntity(id, cEntity) : false;
4532
5272
  this.visualsManager.AddRego({
4533
5273
  rego: {
4534
5274
  entityId: id,
@@ -4536,7 +5276,8 @@ var EntitiesIdsRenderManager;
4536
5276
  visual: cEntity,
4537
5277
  priority: 0,
4538
5278
  entityTypeId: entity.Bruce["EntityType.ID"],
4539
- accountId: this.apiGetter.accountId
5279
+ accountId: this.apiGetter.accountId,
5280
+ suppressShow: clustered
4540
5281
  }
4541
5282
  });
4542
5283
  }
@@ -4546,12 +5287,13 @@ var EntitiesIdsRenderManager;
4546
5287
  entityId: id,
4547
5288
  menuItemId: this.item.id
4548
5289
  });
5290
+ (_b = this.clustering) === null || _b === void 0 ? void 0 : _b.RemoveEntity(id);
4549
5291
  }
4550
5292
  }
4551
5293
  this.viewer.scene.requestRender();
4552
5294
  return [3 /*break*/, 4];
4553
5295
  case 3:
4554
- e_2 = _b.sent();
5296
+ e_2 = _c.sent();
4555
5297
  console.error(e_2);
4556
5298
  return [3 /*break*/, 4];
4557
5299
  case 4: return [2 /*return*/];
@@ -4746,7 +5488,7 @@ function colorToCColor$2(color) {
4746
5488
  * @param cTileset
4747
5489
  * @returns
4748
5490
  */
4749
- function isAlive(viewer, cTileset) {
5491
+ function isAlive$2(viewer, cTileset) {
4750
5492
  if (!(viewer === null || viewer === void 0 ? void 0 : viewer.scene)) {
4751
5493
  return false;
4752
5494
  }
@@ -4970,7 +5712,7 @@ var TilesetRenderEngine;
4970
5712
  cTileset_1.readyPromise.then(function () {
4971
5713
  var _a, _b, _c, _d;
4972
5714
  try {
4973
- if (!isAlive(params.viewer, cTileset_1)) {
5715
+ if (!isAlive$2(params.viewer, cTileset_1)) {
4974
5716
  return;
4975
5717
  }
4976
5718
  (_a = GetMemoryWatcher(params.viewer)) === null || _a === void 0 ? void 0 : _a.Watch(cTileset_1);
@@ -5019,7 +5761,7 @@ var TilesetRenderEngine;
5019
5761
  cTileset_2.readyPromise.then(function () {
5020
5762
  var _a;
5021
5763
  try {
5022
- if (!isAlive(params.viewer, cTileset_2)) {
5764
+ if (!isAlive$2(params.viewer, cTileset_2)) {
5023
5765
  return;
5024
5766
  }
5025
5767
  (_a = GetMemoryWatcher(params.viewer)) === null || _a === void 0 ? void 0 : _a.Watch(cTileset_2);
@@ -5097,7 +5839,7 @@ var TilesetRenderEngine;
5097
5839
  cTileset.readyPromise.then(function () {
5098
5840
  var _a;
5099
5841
  try {
5100
- if (!isAlive(viewer, cTileset)) {
5842
+ if (!isAlive$2(viewer, cTileset)) {
5101
5843
  return;
5102
5844
  }
5103
5845
  (_a = GetMemoryWatcher(params.viewer)) === null || _a === void 0 ? void 0 : _a.Watch(cTileset);
@@ -5583,7 +6325,7 @@ var TilesetRenderEngine;
5583
6325
  MemoryWatcher.prototype.clean = function () {
5584
6326
  var _this = this;
5585
6327
  // Remove all dead tilesets.
5586
- this.watched = this.watched.filter(function (x) { return isAlive(_this.viewer, x); });
6328
+ this.watched = this.watched.filter(function (x) { return isAlive$2(_this.viewer, x); });
5587
6329
  // Check if viewer is destroyed.
5588
6330
  if (!this.viewer || this.viewer.isDestroyed()) {
5589
6331
  this.destroy();
@@ -9920,7 +10662,7 @@ var ViewRenderEngine;
9920
10662
  ViewRenderEngine.Render = Render;
9921
10663
  })(ViewRenderEngine || (ViewRenderEngine = {}));
9922
10664
 
9923
- var VERSION = "2.1.3";
10665
+ var VERSION = "2.1.8";
9924
10666
 
9925
10667
  export { VERSION, CesiumViewMonitor, ViewerUtils, MenuItemManager, EntityRenderEngine, MenuItemCreator, VisualsRegister, RenderManager, EntitiesIdsRenderManager, EntitiesLoadedRenderManager, EntitiesRenderManager, EntityRenderManager, TilesetCadRenderManager, TilesetArbRenderManager, TilesetEntitiesRenderManager, TilesetOsmRenderManager, TilesetPointcloudRenderManager, TilesetGooglePhotosRenderManager, DataSourceStaticKmlManager, RelationsRenderManager, SharedGetters, CesiumParabola, ViewRenderEngine, TileRenderEngine, TilesetRenderEngine, CESIUM_INSPECTOR_KEY, ViewUtils, DrawingUtils, MeasureUtils, EntityUtils };
9926
10668
  //# sourceMappingURL=bruce-cesium.es5.js.map