bruce-cesium 2.1.7 → 2.1.9

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 { 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, HeightReference, Entity, HorizontalOrigin, VerticalOrigin, ClassificationType, ArcType, PolygonHierarchy, ShadowMode, PolylineGraphics, HeadingPitchRoll, Transforms, ColorBlendMode, Primitive, Cesium3DTileFeature, HeadingPitchRange, SceneMode, Cesium3DTileColorBlendMode, Cesium3DTileStyle, createOsmBuildings, KmlDataSource, createWorldTerrain, EllipsoidTerrainProvider, CesiumTerrainProvider, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, UrlTemplateImageryProvider, TileMapServiceImageryProvider, IonImageryProvider, OrthographicFrustum, JulianDate, NearFarScalar, PolygonPipeline, CesiumInspector, EllipsoidGeodesic, sampleTerrainMostDetailed, Cesium3DTileset, Matrix4, Matrix3, IonResource, ColorMaterialProperty, EasingFunction, GeometryInstance } from 'cesium';
3
+ import { Cartesian2, Cartographic, CallbackProperty, Cartesian3, Color, Rectangle, Math as Math$1, Entity, Primitive, Cesium3DTileFeature, HeightReference, DistanceDisplayCondition, NearFarScalar, HorizontalOrigin, VerticalOrigin, ClassificationType, ArcType, PolygonHierarchy, ShadowMode, PolylineGraphics, HeadingPitchRoll, Transforms, ColorBlendMode, SceneMode, HeadingPitchRange, Cesium3DTileColorBlendMode, createOsmBuildings, Cesium3DTileStyle, KmlDataSource, OrthographicFrustum, JulianDate, createWorldTerrain, EllipsoidTerrainProvider, CesiumTerrainProvider, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, UrlTemplateImageryProvider, TileMapServiceImageryProvider, IonImageryProvider, Cesium3DTileset, Matrix4, Matrix3, IonResource, CesiumInspector, EllipsoidGeodesic, sampleTerrainMostDetailed, PolygonPipeline, ColorMaterialProperty, EasingFunction, GeometryInstance } from 'cesium';
4
4
 
5
5
  var TIME_LAG = 300;
6
6
  var POSITION_CHECK_TIMER = 950;
@@ -1517,6 +1517,23 @@ function getRenderGroupId(zoomItem, terrain) {
1517
1517
  return zoomItem.MinZoom + "-" + zoomItem.MaxZoom + "-" + shouldApplyFlatFix(terrain);
1518
1518
  }
1519
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
+ }
1520
1537
  var EntityRenderEngine;
1521
1538
  (function (EntityRenderEngine) {
1522
1539
  function Render(params) {
@@ -1848,7 +1865,10 @@ var EntityRenderEngine;
1848
1865
  verticalOrigin: VerticalOrigin.BOTTOM,
1849
1866
  image: iconUrl,
1850
1867
  heightReference: getHeightRef(style),
1851
- 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),
1852
1872
  },
1853
1873
  position: EntityUtils.GetPos({
1854
1874
  viewer: params.viewer,
@@ -1899,7 +1919,8 @@ var EntityRenderEngine;
1899
1919
  extrudedHeight: fillHeight,
1900
1920
  heightReference: HeightReference.CLAMP_TO_GROUND,
1901
1921
  extrudedHeightReference: exHeightRef,
1902
- zIndex: 1
1922
+ zIndex: 1,
1923
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
1903
1924
  },
1904
1925
  position: pos === null || pos === void 0 ? void 0 : pos.clone(),
1905
1926
  show: false
@@ -1919,7 +1940,8 @@ var EntityRenderEngine;
1919
1940
  extrudedHeight: outlineHeight,
1920
1941
  heightReference: HeightReference.CLAMP_TO_GROUND,
1921
1942
  extrudedHeightReference: exHeightRef,
1922
- zIndex: 2
1943
+ zIndex: 2,
1944
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
1923
1945
  },
1924
1946
  position: pos === null || pos === void 0 ? void 0 : pos.clone()
1925
1947
  }));
@@ -1941,7 +1963,8 @@ var EntityRenderEngine;
1941
1963
  point: {
1942
1964
  pixelSize: size,
1943
1965
  color: cColor,
1944
- heightReference: getHeightRef(style)
1966
+ heightReference: getHeightRef(style),
1967
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
1945
1968
  },
1946
1969
  position: EntityUtils.GetPos({
1947
1970
  viewer: params.viewer,
@@ -2002,7 +2025,9 @@ var EntityRenderEngine;
2002
2025
  style: pStyle,
2003
2026
  tags: tags,
2004
2027
  viewer: params.viewer,
2005
- api: api
2028
+ api: api,
2029
+ maxDistance: zoomItem.MaxZoom,
2030
+ minDistance: zoomItem.MinZoom
2006
2031
  })];
2007
2032
  case 5:
2008
2033
  cEntity = _d.sent();
@@ -2093,7 +2118,8 @@ var EntityRenderEngine;
2093
2118
  classificationType: ClassificationType.TERRAIN,
2094
2119
  arcType: ArcType.GEODESIC,
2095
2120
  zIndex: getZIndex(style, entity, params.tags),
2096
- clampToGround: heightRef == HeightReference.CLAMP_TO_GROUND
2121
+ clampToGround: heightRef == HeightReference.CLAMP_TO_GROUND,
2122
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2097
2123
  },
2098
2124
  position: EntityUtils.GetPos({
2099
2125
  viewer: params.viewer,
@@ -2141,7 +2167,9 @@ var EntityRenderEngine;
2141
2167
  entity: entity,
2142
2168
  style: lStyle,
2143
2169
  tags: tags,
2144
- viewer: params.viewer
2170
+ viewer: params.viewer,
2171
+ maxDistance: zoomItem.MaxZoom,
2172
+ minDistance: zoomItem.MinZoom
2145
2173
  });
2146
2174
  if (cEntity) {
2147
2175
  cEntity._renderGroup = getRenderGroupId(zoomItem, (_c = params.viewer) === null || _c === void 0 ? void 0 : _c.terrainProvider);
@@ -2213,7 +2241,8 @@ var EntityRenderEngine;
2213
2241
  heightReference: heightRef,
2214
2242
  classificationType: ClassificationType.BOTH,
2215
2243
  perPositionHeight: heightRef == HeightReference.CLAMP_TO_GROUND ? false : true,
2216
- zIndex: zIndex
2244
+ zIndex: zIndex,
2245
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2217
2246
  },
2218
2247
  position: EntityUtils.GetPos({
2219
2248
  viewer: params.viewer,
@@ -2238,7 +2267,8 @@ var EntityRenderEngine;
2238
2267
  clampToGround: heightRef == HeightReference.CLAMP_TO_GROUND,
2239
2268
  classificationType: ClassificationType.TERRAIN,
2240
2269
  arcType: ArcType.GEODESIC,
2241
- zIndex: zIndex
2270
+ zIndex: zIndex,
2271
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2242
2272
  }),
2243
2273
  show: false
2244
2274
  });
@@ -2256,7 +2286,8 @@ var EntityRenderEngine;
2256
2286
  clampToGround: heightRef == HeightReference.CLAMP_TO_GROUND,
2257
2287
  classificationType: ClassificationType.TERRAIN,
2258
2288
  arcType: ArcType.GEODESIC,
2259
- zIndex: zIndex
2289
+ zIndex: zIndex,
2290
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2260
2291
  }),
2261
2292
  show: false
2262
2293
  });
@@ -2303,7 +2334,9 @@ var EntityRenderEngine;
2303
2334
  entity: entity,
2304
2335
  style: pStyle,
2305
2336
  tags: tags,
2306
- viewer: params.viewer
2337
+ viewer: params.viewer,
2338
+ maxDistance: zoomItem.MaxZoom,
2339
+ minDistance: zoomItem.MinZoom
2307
2340
  });
2308
2341
  if (cEntity) {
2309
2342
  cEntity._renderGroup = getRenderGroupId(zoomItem, (_c = params.viewer) === null || _c === void 0 ? void 0 : _c.terrainProvider);
@@ -2380,7 +2413,8 @@ var EntityRenderEngine;
2380
2413
  shadows: ShadowMode.ENABLED,
2381
2414
  colorBlendAmount: blendAmount,
2382
2415
  colorBlendMode: blendMode,
2383
- color: color
2416
+ color: color,
2417
+ distanceDisplayCondition: getDisplayCondition(params.minDistance, params.maxDistance)
2384
2418
  },
2385
2419
  orientation: orientation,
2386
2420
  position: pos,
@@ -2494,7 +2528,9 @@ var EntityRenderEngine;
2494
2528
  api: api,
2495
2529
  fileId: lod.clientFileId
2496
2530
  }),
2497
- lodClientFileId: lod.clientFileId
2531
+ lodClientFileId: lod.clientFileId,
2532
+ maxDistance: zoomItem.MaxZoom,
2533
+ minDistance: zoomItem.MinZoom
2498
2534
  });
2499
2535
  if (cEntity) {
2500
2536
  cEntity._renderGroup = getRenderGroupId(zoomItem, (_e = params.viewer) === null || _e === void 0 ? void 0 : _e.terrainProvider);
@@ -2524,6 +2560,773 @@ var EntityRenderEngine;
2524
2560
  })(Model3d = EntityRenderEngine.Model3d || (EntityRenderEngine.Model3d = {}));
2525
2561
  })(EntityRenderEngine || (EntityRenderEngine = {}));
2526
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 _clusterImageCache = new LRUCache(500);
2717
+ var _clusterImageLoadedCache = new LRUCache(500);
2718
+ function _loadClusterImage(params) {
2719
+ return __awaiter(this, void 0, void 0, function () {
2720
+ var size, txtColor, bgColor, text, iconUrl, key, cacheData, prom;
2721
+ return __generator(this, function (_a) {
2722
+ switch (_a.label) {
2723
+ case 0:
2724
+ size = params.size, txtColor = params.txtColor, bgColor = params.bgColor, text = params.text, iconUrl = params.iconUrl;
2725
+ key = "".concat(size, "-").concat(txtColor, "-").concat(bgColor, "-").concat(text, "-").concat(iconUrl);
2726
+ cacheData = _clusterImageCache.Get(key);
2727
+ if (!cacheData) return [3 /*break*/, 2];
2728
+ return [4 /*yield*/, cacheData];
2729
+ case 1: return [2 /*return*/, _a.sent()];
2730
+ case 2:
2731
+ prom = new Promise(function (res, rej) {
2732
+ var canvas = document.createElement("canvas");
2733
+ canvas.width = size;
2734
+ canvas.height = size;
2735
+ var ctx = canvas.getContext("2d");
2736
+ var drawWithoutImage = function (img) {
2737
+ ctx.beginPath();
2738
+ ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI, false);
2739
+ var fill = null;
2740
+ var txt = null;
2741
+ if (img) {
2742
+ var brightness = calculateImageBrightness(img);
2743
+ // brightness < 128 = light background.
2744
+ fill = brightness < 128 ? "white" : "#114d78";
2745
+ txt = brightness < 128 ? "black" : "white";
2746
+ }
2747
+ else {
2748
+ fill = bgColor ? bgColor : "#114d78";
2749
+ txt = txtColor ? txtColor : "white";
2750
+ }
2751
+ ctx.fillStyle = fill;
2752
+ ctx.fill();
2753
+ var maxTextWidth = size * 0.8;
2754
+ var maxTextHeight = size * 0.8;
2755
+ var minTextSize = Math.floor(size / 10);
2756
+ var textSize = findOptimalFontSize(text, maxTextWidth, maxTextHeight, minTextSize);
2757
+ ctx.font = "bold ".concat(textSize, "px Arial");
2758
+ ctx.fillStyle = txt;
2759
+ ctx.textAlign = "center";
2760
+ ctx.textBaseline = "middle";
2761
+ ctx.fillText(text, size / 2, size / 2);
2762
+ };
2763
+ var drawWithImage = function (img) {
2764
+ var aspectRatio = img.width / img.height;
2765
+ var imageSize = Math.min(size / 2, img.width, img.height);
2766
+ if (imageSize / aspectRatio > size / 2) {
2767
+ imageSize = (size / 2) * aspectRatio;
2768
+ }
2769
+ var imageX = (size - imageSize) / 2;
2770
+ var imageY = (size - imageSize) / 2 - imageSize / 3;
2771
+ ctx.beginPath();
2772
+ ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI, false);
2773
+ var brightness = calculateImageBrightness(img);
2774
+ var bgColor = brightness < 128 ? "white" : "#114d78";
2775
+ var txtColor = brightness < 128 ? "black" : "white";
2776
+ ctx.fillStyle = bgColor;
2777
+ ctx.fill();
2778
+ ctx.shadowColor = "rgba(0, 0, 0, 0.3)";
2779
+ ctx.shadowOffsetX = 3;
2780
+ ctx.shadowOffsetY = 3;
2781
+ ctx.shadowBlur = 5;
2782
+ ctx.drawImage(img, imageX, imageY, imageSize, imageSize);
2783
+ var padding = imageSize / 6;
2784
+ var maxTextWidth = imageSize;
2785
+ var maxTextHeight = imageSize - padding;
2786
+ var minTextSize = Math.floor(imageSize / 5);
2787
+ var textSize = findOptimalFontSize(text, maxTextWidth, maxTextHeight, minTextSize);
2788
+ ctx.font = "bold ".concat(textSize, "px Arial");
2789
+ ctx.fillStyle = txtColor;
2790
+ ctx.textAlign = "center";
2791
+ ctx.textBaseline = "top";
2792
+ ctx.shadowColor = "rgba(0, 0, 0, 0)";
2793
+ ctx.shadowOffsetX = 0;
2794
+ ctx.shadowOffsetY = 0;
2795
+ ctx.shadowBlur = 0;
2796
+ ctx.fillText(text, size / 2, imageY + imageSize + padding);
2797
+ };
2798
+ var findOptimalFontSize = function (text, maxWidth, maxHeight, minSize) {
2799
+ var fontSize = maxHeight;
2800
+ var tempCanvas = document.createElement("canvas");
2801
+ var tempCtx = tempCanvas.getContext("2d");
2802
+ while (fontSize > minSize) {
2803
+ tempCtx.font = "bold ".concat(fontSize, "px Arial");
2804
+ var measuredWidth = tempCtx.measureText(text).width;
2805
+ var measuredHeight = fontSize * 1.2; // Allowing some padding
2806
+ if (measuredWidth <= maxWidth && measuredHeight <= maxHeight) {
2807
+ break;
2808
+ }
2809
+ fontSize--;
2810
+ }
2811
+ return fontSize;
2812
+ };
2813
+ var calculateImageBrightness = function (img) {
2814
+ var brightness = 0;
2815
+ var tempCanvas = document.createElement("canvas");
2816
+ tempCanvas.width = img.width;
2817
+ tempCanvas.height = img.height;
2818
+ var tempCtx = tempCanvas.getContext("2d");
2819
+ tempCtx.drawImage(img, 0, 0);
2820
+ var imageData = tempCtx.getImageData(0, 0, img.width, img.height).data;
2821
+ for (var i = 0; i < imageData.length; i += 4) {
2822
+ var r = imageData[i];
2823
+ var g = imageData[i + 1];
2824
+ var b = imageData[i + 2];
2825
+ brightness += (r + g + b) / 3;
2826
+ }
2827
+ return Math.round(brightness / (img.width * img.height));
2828
+ };
2829
+ if (iconUrl) {
2830
+ var img_1 = new Image();
2831
+ img_1.crossOrigin = "anonymous";
2832
+ img_1.src = iconUrl;
2833
+ img_1.onload = function () {
2834
+ if (size > 50) {
2835
+ drawWithImage(img_1);
2836
+ }
2837
+ else {
2838
+ drawWithoutImage(img_1);
2839
+ }
2840
+ res(canvas);
2841
+ };
2842
+ img_1.onerror = function () {
2843
+ drawWithoutImage();
2844
+ res(canvas);
2845
+ };
2846
+ }
2847
+ else {
2848
+ drawWithoutImage();
2849
+ res(canvas);
2850
+ }
2851
+ });
2852
+ _clusterImageCache.Set(key, prom);
2853
+ prom.then(function (canvas) {
2854
+ _clusterImageLoadedCache.Set(key, canvas);
2855
+ _clusterImageCache.Set(key, null);
2856
+ });
2857
+ return [4 /*yield*/, prom];
2858
+ case 3: return [2 /*return*/, _a.sent()];
2859
+ }
2860
+ });
2861
+ });
2862
+ }
2863
+ function getClusterImage(params) {
2864
+ var size = params.size, txtColor = params.txtColor, bgColor = params.bgColor, text = params.text, iconUrl = params.iconUrl;
2865
+ var key = "".concat(size, "-").concat(txtColor, "-").concat(bgColor, "-").concat(text, "-").concat(iconUrl);
2866
+ var cacheData = _clusterImageLoadedCache.Get(key);
2867
+ // If available then return.
2868
+ if (cacheData) {
2869
+ return cacheData;
2870
+ }
2871
+ // If not available then queue for it to cook.
2872
+ else {
2873
+ _loadClusterImage(params);
2874
+ }
2875
+ return null;
2876
+ }
2877
+ var PointClustering = /** @class */ (function () {
2878
+ function PointClustering(register, menuItemId) {
2879
+ var _this = this;
2880
+ this.disposed = false;
2881
+ this.registeredEntityIds = new Set();
2882
+ this.register = register;
2883
+ this.viewer = register.Viewer;
2884
+ this.menuItemId = menuItemId;
2885
+ this.updateClusterSpacing(0);
2886
+ var boundary = new Rectangle$1(0, 0, 360, 180);
2887
+ this.quadTree = new Quad(boundary, 4);
2888
+ this.prevClusteredEntities = new Set();
2889
+ this.currClusteredEntities = new Set();
2890
+ this.clusterEntities = new Map();
2891
+ this.updateQueue = new DelayQueue(function () {
2892
+ _this.doUpdate();
2893
+ }, 1000);
2894
+ this.listenCamera();
2895
+ }
2896
+ /**
2897
+ * Starts listening to camera changes.
2898
+ * This will trigger the clustering update whenever camera is moved.
2899
+ */
2900
+ PointClustering.prototype.listenCamera = function () {
2901
+ var _this = this;
2902
+ var viewer = this.viewer;
2903
+ var lastPos3d;
2904
+ var hasMoved = function () {
2905
+ var _a;
2906
+ var cameraPos = (_a = viewer === null || viewer === void 0 ? void 0 : viewer.camera) === null || _a === void 0 ? void 0 : _a.positionCartographic;
2907
+ if (!cameraPos) {
2908
+ return false;
2909
+ }
2910
+ var pos3d = Cartographic.toCartesian(cameraPos);
2911
+ if (!lastPos3d) {
2912
+ lastPos3d = pos3d;
2913
+ return false;
2914
+ }
2915
+ var distance = Cartesian3.distance(pos3d, lastPos3d);
2916
+ lastPos3d = pos3d;
2917
+ // 50 meter movement at least.
2918
+ return distance > 50;
2919
+ };
2920
+ this.listenCameraRemoval = viewer.scene.camera.changed.addEventListener(function () {
2921
+ if (hasMoved()) {
2922
+ _this.updateQueue.Call();
2923
+ }
2924
+ });
2925
+ };
2926
+ /**
2927
+ * Stops listening to camera changes.
2928
+ */
2929
+ PointClustering.prototype.unlistenCamera = function () {
2930
+ if (this.listenCameraRemoval) {
2931
+ this.listenCameraRemoval();
2932
+ this.listenCameraRemoval = null;
2933
+ }
2934
+ };
2935
+ /**
2936
+ * Removes all clusters and updates entities to no longer be suppressed.
2937
+ * @returns
2938
+ */
2939
+ PointClustering.prototype.Dispose = function () {
2940
+ if (this.disposed) {
2941
+ return;
2942
+ }
2943
+ for (var _i = 0, _a = Array.from(this.clusterEntities); _i < _a.length; _i++) {
2944
+ var _b = _a[_i], entity = _b[1];
2945
+ this.viewer.entities.remove(entity);
2946
+ }
2947
+ this.clusterEntities.clear();
2948
+ this.unlistenCamera();
2949
+ this.disposed = true;
2950
+ // Restore entities.
2951
+ var toUpdateIds = [];
2952
+ for (var _c = 0, _d = Array.from(this.registeredEntityIds); _c < _d.length; _c++) {
2953
+ var id = _d[_c];
2954
+ var rego = this.register.GetRego({
2955
+ entityId: id,
2956
+ menuItemId: this.menuItemId
2957
+ });
2958
+ if (rego && rego.suppressShow) {
2959
+ rego.suppressShow = false;
2960
+ toUpdateIds.push(id);
2961
+ }
2962
+ }
2963
+ if (toUpdateIds.length) {
2964
+ this.register.ForceUpdate({
2965
+ entityIds: toUpdateIds,
2966
+ });
2967
+ }
2968
+ };
2969
+ /**
2970
+ * Calculates center of given points.
2971
+ * @param points
2972
+ * @returns
2973
+ */
2974
+ PointClustering.prototype.calculateCentroid = function (points) {
2975
+ var lonSum = 0;
2976
+ var latSum = 0;
2977
+ for (var _i = 0, points_1 = points; _i < points_1.length; _i++) {
2978
+ var point = points_1[_i];
2979
+ lonSum += point.lon;
2980
+ latSum += point.lat;
2981
+ }
2982
+ var lonAvg = lonSum / points.length;
2983
+ var latAvg = latSum / points.length;
2984
+ return new Point(lonAvg, latAvg, "");
2985
+ };
2986
+ /**
2987
+ * Gathers current clusters and renders them.
2988
+ * @returns
2989
+ */
2990
+ PointClustering.prototype.doUpdate = function () {
2991
+ var _this = this;
2992
+ if (this.disposed) {
2993
+ return;
2994
+ }
2995
+ // 1: Update precision.
2996
+ // This defines how far apart these clusters can be.
2997
+ var cameraHeight = this.viewer.camera.positionCartographic.height;
2998
+ this.updateClusterSpacing(cameraHeight);
2999
+ // 2: Get clusters.
3000
+ var _a = this.getClusters(), clusters = _a.clusters, noLongerClustered = _a.noLongerClustered;
3001
+ // 3: Remove all cesium cluster entities that are no longer clustered.
3002
+ for (var _i = 0, _b = Array.from(noLongerClustered); _i < _b.length; _i++) {
3003
+ var id = _b[_i];
3004
+ this.removeClusterEntity(id);
3005
+ }
3006
+ // 4: Stop hiding entities that are no longer clustered.
3007
+ var previousEntityIds = new Set(this.registeredEntityIds);
3008
+ for (var _c = 0, _d = Array.from(previousEntityIds); _c < _d.length; _c++) {
3009
+ var id = _d[_c];
3010
+ if (!this.currClusteredEntities.has(id)) {
3011
+ var rego = this.register.GetRego({
3012
+ entityId: id,
3013
+ menuItemId: this.menuItemId
3014
+ });
3015
+ if (rego && rego.suppressShow) {
3016
+ rego.suppressShow = false;
3017
+ this.register.ForceUpdate({
3018
+ entityIds: [id],
3019
+ });
3020
+ }
3021
+ }
3022
+ }
3023
+ var getScale = function (count) {
3024
+ var baseSize = 20;
3025
+ var scalingFactor = 2;
3026
+ var scale = baseSize + scalingFactor * (count - 1);
3027
+ scale = Math.min(scale, 120);
3028
+ return scale;
3029
+ };
3030
+ /**
3031
+ * Generate circle with label in center.
3032
+ * @param count
3033
+ * @returns
3034
+ */
3035
+ var getCanvas = function (count) {
3036
+ var params = {
3037
+ size: getScale(count),
3038
+ txtColor: _this.pointColorTxt,
3039
+ bgColor: _this.pointColorBg,
3040
+ text: String(count),
3041
+ iconUrl: _this.iconUrl
3042
+ };
3043
+ return getClusterImage(params);
3044
+ };
3045
+ var _loop_1 = function (cluster) {
3046
+ var clusterId = cluster.center.id;
3047
+ var clusterEntity = this_1.clusterEntities.get(clusterId);
3048
+ var centroid = this_1.calculateCentroid(cluster.points);
3049
+ var count = cluster.points.length;
3050
+ if (clusterEntity) {
3051
+ clusterEntity.position = Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150);
3052
+ clusterEntity.billboard.image = new CallbackProperty(function () {
3053
+ return getCanvas(count);
3054
+ }, false),
3055
+ clusterEntity.billboard.width = getScale(cluster.points.length);
3056
+ clusterEntity.billboard.height = getScale(cluster.points.length);
3057
+ }
3058
+ else {
3059
+ clusterEntity = this_1.viewer.entities.add({
3060
+ position: Cartesian3.fromDegrees(centroid.lon, centroid.lat, 150),
3061
+ billboard: {
3062
+ heightReference: HeightReference.NONE,
3063
+ image: new CallbackProperty(function () {
3064
+ return getCanvas(count);
3065
+ }, false),
3066
+ width: getScale(count),
3067
+ height: getScale(count),
3068
+ verticalOrigin: VerticalOrigin.CENTER,
3069
+ horizontalOrigin: HorizontalOrigin.CENTER,
3070
+ disableDepthTestDistance: Number.POSITIVE_INFINITY
3071
+ }
3072
+ });
3073
+ this_1.clusterEntities.set(clusterId, clusterEntity);
3074
+ }
3075
+ for (var i = 0; i < cluster.points.length; i++) {
3076
+ var entityId = cluster.points[i].id;
3077
+ var rego = this_1.register.GetRego({
3078
+ entityId: entityId,
3079
+ menuItemId: this_1.menuItemId
3080
+ });
3081
+ if (rego && !rego.suppressShow) {
3082
+ rego.suppressShow = true;
3083
+ this_1.register.ForceUpdate({
3084
+ entityIds: [entityId],
3085
+ });
3086
+ }
3087
+ }
3088
+ };
3089
+ var this_1 = this;
3090
+ // 5: iterate over clusters and add/update them as Cesium entities.
3091
+ for (var _e = 0, clusters_1 = clusters; _e < clusters_1.length; _e++) {
3092
+ var cluster = clusters_1[_e];
3093
+ _loop_1(cluster);
3094
+ }
3095
+ var _loop_2 = function (clusterId, clusterEntity) {
3096
+ if (!clusters.find(function (x) { return x.center.id == clusterId; })) {
3097
+ this_2.viewer.entities.remove(clusterEntity);
3098
+ this_2.clusterEntities.delete(clusterId);
3099
+ }
3100
+ };
3101
+ var this_2 = this;
3102
+ // 6: Iterate over existing cluster entities and remove those that are no longer clustered.
3103
+ for (var _f = 0, _g = Array.from(this.clusterEntities); _f < _g.length; _f++) {
3104
+ var _h = _g[_f], clusterId = _h[0], clusterEntity = _h[1];
3105
+ _loop_2(clusterId, clusterEntity);
3106
+ }
3107
+ };
3108
+ /**
3109
+ * Updates how apart clusters can be based on camera distance.
3110
+ * @param cameraHeight
3111
+ */
3112
+ PointClustering.prototype.updateClusterSpacing = function (cameraHeight) {
3113
+ // Camera height thresholds in meters.
3114
+ var cameraHeightThresholds = [4000, 5000, 8000, 13000, 25000, 40000];
3115
+ // Distance increments in degrees.
3116
+ var distanceIncrements = [0.005, 0.01, 0.02, 0.04, 0.1, 0.5];
3117
+ // Find the appropriate spacing based on the camera height.
3118
+ var spacing = 0;
3119
+ for (var i = 0; i < cameraHeightThresholds.length; i++) {
3120
+ if (cameraHeight && cameraHeight < cameraHeightThresholds[i]) {
3121
+ spacing += distanceIncrements[i];
3122
+ break;
3123
+ }
3124
+ spacing += distanceIncrements[i];
3125
+ }
3126
+ this.distanceBetweenClusters = spacing;
3127
+ };
3128
+ /**
3129
+ * Gathers clusters.
3130
+ * @returns
3131
+ */
3132
+ PointClustering.prototype.getClusters = function () {
3133
+ var _this = this;
3134
+ this.currClusteredEntities.clear();
3135
+ var clusters = [];
3136
+ var processedPoints = new Set();
3137
+ var cameraPosition = this.viewer.camera.position;
3138
+ for (var _i = 0, _a = this.quadTree.points; _i < _a.length; _i++) {
3139
+ var point = _a[_i];
3140
+ // Skip points already processed in previous clusters.
3141
+ if (processedPoints.has(point.id)) {
3142
+ continue;
3143
+ }
3144
+ // Skip points closer than 4000 meters to the camera.
3145
+ var cartesian3 = Cartesian3.fromDegrees(point.lon, point.lat);
3146
+ if (Cartesian3.distance(cartesian3, cameraPosition) <= 4000) {
3147
+ continue;
3148
+ }
3149
+ var found = [];
3150
+ var nearbyPoints = this.quadTree.Query(new Circle(point.lon, point.lat, this.distanceBetweenClusters), found);
3151
+ if (nearbyPoints.length > 1) {
3152
+ var cluster = { center: point, points: [] };
3153
+ for (var _b = 0, nearbyPoints_1 = nearbyPoints; _b < nearbyPoints_1.length; _b++) {
3154
+ var nearby = nearbyPoints_1[_b];
3155
+ if (!cluster.points.includes(nearby)) {
3156
+ cluster.points.push(nearby);
3157
+ processedPoints.add(nearby.id);
3158
+ this.currClusteredEntities.add(nearby.id);
3159
+ }
3160
+ }
3161
+ clusters.push(cluster);
3162
+ }
3163
+ }
3164
+ // Filter out clusters with only one point.
3165
+ var validClusters = clusters.filter(function (cluster) { return cluster.points.length > 1; });
3166
+ // Merge adjacent clusters.
3167
+ var mergedClusters = this.mergeClusters(validClusters);
3168
+ // Get the entity IDs that are no longer clustered
3169
+ var noLongerClustered = new Set(Array.from(this.prevClusteredEntities).filter(function (id) { return !_this.currClusteredEntities.has(id); }));
3170
+ // Update the previous clustered entities ref.
3171
+ this.prevClusteredEntities = new Set(this.currClusteredEntities);
3172
+ return { clusters: mergedClusters, noLongerClustered: noLongerClustered };
3173
+ };
3174
+ /**
3175
+ * Merges clusters that are nearby based on the distanceBetweenClusters value.
3176
+ * @param clusters
3177
+ * @returns
3178
+ */
3179
+ PointClustering.prototype.mergeClusters = function (clusters) {
3180
+ var _a;
3181
+ var mergedClusters = [].concat(clusters);
3182
+ // Keep looping while merges keep happening.
3183
+ var mergeOccurred = true;
3184
+ while (mergeOccurred) {
3185
+ mergeOccurred = false;
3186
+ for (var i = 0; i < mergedClusters.length - 1; i++) {
3187
+ for (var j = i + 1; j < mergedClusters.length; j++) {
3188
+ var cluster1 = mergedClusters[i];
3189
+ var cluster2 = mergedClusters[j];
3190
+ var centerDistance = this.calculateDistance(cluster1.center.lon, cluster1.center.lat, cluster2.center.lon, cluster2.center.lat);
3191
+ var distanceThreshold = this.distanceBetweenClusters;
3192
+ if (centerDistance <= distanceThreshold) {
3193
+ // Merge clusters.
3194
+ (_a = cluster1.points).push.apply(_a, cluster2.points);
3195
+ mergedClusters.splice(j, 1);
3196
+ this.removeClusterEntity(cluster2.center.id);
3197
+ mergeOccurred = true;
3198
+ break;
3199
+ }
3200
+ }
3201
+ if (mergeOccurred) {
3202
+ break;
3203
+ }
3204
+ }
3205
+ }
3206
+ return mergedClusters;
3207
+ };
3208
+ /**
3209
+ * Removes Cesium cluster entity.
3210
+ * @param clusterId
3211
+ */
3212
+ PointClustering.prototype.removeClusterEntity = function (clusterId) {
3213
+ var clusterEntity = this.clusterEntities.get(clusterId);
3214
+ if (clusterEntity) {
3215
+ this.viewer.entities.remove(clusterEntity);
3216
+ this.clusterEntities.delete(clusterId);
3217
+ }
3218
+ };
3219
+ PointClustering.prototype.convertCartesianToCartographic = function (cartesian3) {
3220
+ var carto = Cartographic.fromCartesian(cartesian3);
3221
+ var lon = Math$1.toDegrees(carto.longitude);
3222
+ var lat = Math$1.toDegrees(carto.latitude);
3223
+ var id = lon + ',' + lat;
3224
+ return new Point(lon, lat, id);
3225
+ };
3226
+ /**
3227
+ * Adds new entity to the clustering logic.
3228
+ * @param id Bruce entity ID.
3229
+ * @param cartesian3 entity's position.
3230
+ */
3231
+ PointClustering.prototype.addPoint = function (id, cartesian3) {
3232
+ var point = this.convertCartesianToCartographic(cartesian3);
3233
+ point.id = id;
3234
+ this.quadTree.Insert(point);
3235
+ };
3236
+ /**
3237
+ * Calculates rough distance across earth between two points.
3238
+ * @param lon1
3239
+ * @param lat1
3240
+ * @param lon2
3241
+ * @param lat2
3242
+ * @returns
3243
+ */
3244
+ PointClustering.prototype.calculateDistance = function (lon1, lat1, lon2, lat2) {
3245
+ var lonDelta = Math.abs(lon1 - lon2);
3246
+ var latDelta = Math.abs(lat1 - lat2);
3247
+ // Approximate radius of the Earth in kilometers
3248
+ var earthRadius = 6371;
3249
+ var distance = 2 * Math.asin(Math.sqrt(Math.sin(latDelta / 2) * Math.sin(latDelta / 2) +
3250
+ Math.cos(lat1) * Math.cos(lat2) * Math.sin(lonDelta / 2) * Math.sin(lonDelta / 2))) * earthRadius;
3251
+ return distance;
3252
+ };
3253
+ /**
3254
+ * Adds entity to clustering logic.
3255
+ * Will return false if entity could not be clustered and therefor should not be hidden.
3256
+ * @param id
3257
+ * @param entity
3258
+ * @returns
3259
+ */
3260
+ PointClustering.prototype.AddEntity = function (id, entity) {
3261
+ if (this.disposed) {
3262
+ return false;
3263
+ }
3264
+ if (!entity) {
3265
+ return false;
3266
+ }
3267
+ if (entity.polygon || entity.polyline) {
3268
+ return false;
3269
+ }
3270
+ var pos3d = GetValue$1(this.viewer, entity.position);
3271
+ if (!(pos3d === null || pos3d === void 0 ? void 0 : pos3d.x)) {
3272
+ return false;
3273
+ }
3274
+ if (!this.pointColorBg && entity.point) {
3275
+ var pointColorBg = GetValue$1(this.viewer, entity.point.color);
3276
+ if (pointColorBg) {
3277
+ var cColor = null;
3278
+ if (pointColorBg instanceof Object) {
3279
+ cColor = new Color(pointColorBg.red, pointColorBg.green, pointColorBg.blue, pointColorBg.alpha);
3280
+ }
3281
+ else if (typeof pointColorBg === "string") {
3282
+ cColor = Color.fromCssColorString(pointColorBg);
3283
+ }
3284
+ // Determine if text color should instead be black based on background.
3285
+ // cColor contains r,g,b,a values where r,g,b are in the range [0,1].
3286
+ if (cColor) {
3287
+ var brightness = (cColor.red * 299 + cColor.green * 587 + cColor.blue * 114) / 1000;
3288
+ if (brightness > 0.5) {
3289
+ this.pointColorTxt = "black";
3290
+ }
3291
+ else {
3292
+ this.pointColorTxt = "white";
3293
+ }
3294
+ this.pointColorBg = cColor.toCssColorString();
3295
+ }
3296
+ }
3297
+ }
3298
+ if (!this.iconUrl && entity.billboard) {
3299
+ var iconUrl = GetValue$1(this.viewer, entity.billboard.image);
3300
+ if (typeof iconUrl == "string") {
3301
+ this.iconUrl = iconUrl;
3302
+ }
3303
+ }
3304
+ this.registeredEntityIds.add(id);
3305
+ this.addPoint(id, pos3d);
3306
+ this.updateQueue.Call();
3307
+ return true;
3308
+ };
3309
+ /**
3310
+ * Removes entity from clustering logic.
3311
+ * Warning: This will not reveal the entity, suppressShow will remain true.
3312
+ * This is made with the assumption that the entity is being removed from viewer.
3313
+ * @param id
3314
+ * @returns
3315
+ */
3316
+ PointClustering.prototype.RemoveEntity = function (id) {
3317
+ if (this.disposed) {
3318
+ return;
3319
+ }
3320
+ var pointToRemove = this.quadTree.Find(id);
3321
+ if (pointToRemove) {
3322
+ this.quadTree.Remove(pointToRemove);
3323
+ this.updateQueue.Call();
3324
+ }
3325
+ this.registeredEntityIds.delete(id);
3326
+ };
3327
+ return PointClustering;
3328
+ }());
3329
+
2527
3330
  var BATCH_SIZE = 500;
2528
3331
  var CHECK_BATCH_SIZE = 250;
2529
3332
  /**
@@ -2552,6 +3355,9 @@ var EntitiesRenderManager;
2552
3355
  this.apiGetter = apiGetter;
2553
3356
  this.item = item;
2554
3357
  this.visualsManager = visualsManager;
3358
+ if (item.enableClustering) {
3359
+ this.clustering = new PointClustering(this.visualsManager, this.item.id);
3360
+ }
2555
3361
  }
2556
3362
  Object.defineProperty(Manager.prototype, "Disposed", {
2557
3363
  get: function () {
@@ -2562,7 +3368,7 @@ var EntitiesRenderManager;
2562
3368
  });
2563
3369
  Manager.prototype.Init = function (params) {
2564
3370
  var _this = this;
2565
- var _a, _b, _c, _d, _e;
3371
+ var _a, _b, _c, _d, _e, _f, _g;
2566
3372
  if (this.disposed) {
2567
3373
  throw (new Error("This item is disposed."));
2568
3374
  }
@@ -2594,17 +3400,22 @@ var EntitiesRenderManager;
2594
3400
  menuItemId: this.item.id,
2595
3401
  retainTagIds: tagsToRender
2596
3402
  });
3403
+ (_e = this.clustering) === null || _e === void 0 ? void 0 : _e.Dispose();
2597
3404
  }
2598
3405
  else {
2599
3406
  this.visualsManager.RemoveRegos({
2600
3407
  menuItemId: this.item.id
2601
3408
  });
3409
+ (_f = this.clustering) === null || _f === void 0 ? void 0 : _f.Dispose();
2602
3410
  return;
2603
3411
  }
3412
+ if (this.item.enableClustering) {
3413
+ this.clustering = new PointClustering(this.visualsManager, this.item.id);
3414
+ }
2604
3415
  var api = this.apiGetter.getApi();
2605
3416
  this.getter = this.sharedGetters.GetOrCreateFilterGetter({
2606
3417
  api: api,
2607
- attrFilter: (_e = this.item.BruceEntity.Filter) !== null && _e !== void 0 ? _e : {},
3418
+ attrFilter: (_g = this.item.BruceEntity.Filter) !== null && _g !== void 0 ? _g : {},
2608
3419
  batchSize: BATCH_SIZE,
2609
3420
  typeId: this.item.BruceEntity["EntityType.ID"],
2610
3421
  monitor: this.monitor,
@@ -2636,7 +3447,13 @@ var EntitiesRenderManager;
2636
3447
  _this.entityCheckQueue.Call();
2637
3448
  });
2638
3449
  this.entityCheckQueue = new DelayQueue(function () {
2639
- _this.doEntityCheck(Object.keys(_this.renderedEntities));
3450
+ var _a;
3451
+ // Don't bother checking for zoom control changes if we only have 1 item.
3452
+ // We'll let Cesium handle hide/show at max zoom range.
3453
+ var shouldCheck = ((_a = _this.item) === null || _a === void 0 ? void 0 : _a.CameraZoomSettings) && _this.item.CameraZoomSettings.length > 1;
3454
+ if (shouldCheck) {
3455
+ _this.doEntityCheck(Object.keys(_this.renderedEntities));
3456
+ }
2640
3457
  }, 3000);
2641
3458
  };
2642
3459
  Manager.prototype.Dispose = function () {
@@ -2646,7 +3463,7 @@ var EntitiesRenderManager;
2646
3463
  this.doDispose();
2647
3464
  };
2648
3465
  Manager.prototype.doDispose = function () {
2649
- var _a, _b, _c;
3466
+ var _a, _b, _c, _d;
2650
3467
  (_a = this.getterSub) === null || _a === void 0 ? void 0 : _a.call(this);
2651
3468
  this.getterSub = null;
2652
3469
  if (this.getter) {
@@ -2660,6 +3477,7 @@ var EntitiesRenderManager;
2660
3477
  (_c = this.viewMonitorRemoval) === null || _c === void 0 ? void 0 : _c.call(this);
2661
3478
  clearInterval(this.renderQueueInterval);
2662
3479
  this.renderQueue = [];
3480
+ (_d = this.clustering) === null || _d === void 0 ? void 0 : _d.Dispose();
2663
3481
  };
2664
3482
  Manager.prototype.ReRender = function (params) {
2665
3483
  return __awaiter(this, void 0, void 0, function () {
@@ -2793,14 +3611,14 @@ var EntitiesRenderManager;
2793
3611
  }
2794
3612
  };
2795
3613
  Manager.prototype.renderEntities = function (entities, force) {
2796
- var _a, _b, _c;
3614
+ var _a, _b, _c, _d;
2797
3615
  if (force === void 0) { force = false; }
2798
3616
  return __awaiter(this, void 0, void 0, function () {
2799
- var typeId_1, cEntities, i, entity, id, cEntity, visual, tagIds, e_3;
2800
- return __generator(this, function (_d) {
2801
- switch (_d.label) {
3617
+ var typeId_1, cEntities, i, entity, id, cEntity, visual, wasClustered, tagIds, rego, e_3;
3618
+ return __generator(this, function (_e) {
3619
+ switch (_e.label) {
2802
3620
  case 0:
2803
- _d.trys.push([0, 2, , 3]);
3621
+ _e.trys.push([0, 2, , 3]);
2804
3622
  if (this.disposed || this.viewer.isDestroyed()) {
2805
3623
  return [2 /*return*/];
2806
3624
  }
@@ -2818,7 +3636,7 @@ var EntitiesRenderManager;
2818
3636
  force: force
2819
3637
  })];
2820
3638
  case 1:
2821
- cEntities = _d.sent();
3639
+ cEntities = _e.sent();
2822
3640
  if (this.disposed) {
2823
3641
  this.doDispose();
2824
3642
  return [2 /*return*/];
@@ -2834,17 +3652,20 @@ var EntitiesRenderManager;
2834
3652
  menuItemId: this.item.id
2835
3653
  })) === null || _b === void 0 ? void 0 : _b.visual;
2836
3654
  if (!visual || visual != cEntity) {
3655
+ wasClustered = this.clustering ? this.clustering.AddEntity(id, cEntity) : false;
2837
3656
  tagIds = (_c = entity.Bruce) === null || _c === void 0 ? void 0 : _c["Layer.ID"];
3657
+ rego = {
3658
+ entityId: id,
3659
+ menuItemId: this.item.id,
3660
+ visual: cEntity,
3661
+ priority: 0,
3662
+ entityTypeId: entity.Bruce["EntityType.ID"],
3663
+ accountId: this.apiGetter.accountId,
3664
+ tagIds: tagIds ? [].concat(tagIds) : [],
3665
+ suppressShow: wasClustered
3666
+ };
2838
3667
  this.visualsManager.AddRego({
2839
- rego: {
2840
- entityId: id,
2841
- menuItemId: this.item.id,
2842
- visual: cEntity,
2843
- priority: 0,
2844
- entityTypeId: entity.Bruce["EntityType.ID"],
2845
- accountId: this.apiGetter.accountId,
2846
- tagIds: tagIds ? [].concat(tagIds) : []
2847
- }
3668
+ rego: rego
2848
3669
  });
2849
3670
  }
2850
3671
  }
@@ -2853,12 +3674,13 @@ var EntitiesRenderManager;
2853
3674
  entityId: id,
2854
3675
  menuItemId: this.item.id
2855
3676
  });
3677
+ (_d = this.clustering) === null || _d === void 0 ? void 0 : _d.RemoveEntity(id);
2856
3678
  }
2857
3679
  }
2858
3680
  this.viewer.scene.requestRender();
2859
3681
  return [3 /*break*/, 3];
2860
3682
  case 2:
2861
- e_3 = _d.sent();
3683
+ e_3 = _e.sent();
2862
3684
  console.error(e_3);
2863
3685
  return [3 /*break*/, 3];
2864
3686
  case 3: return [2 /*return*/];
@@ -3750,7 +4572,7 @@ function updateEntity(viewer, entityId, register) {
3750
4572
  for (var i = 0; i < regos.length; i++) {
3751
4573
  var rego = regos[i];
3752
4574
  rego.best = rego === highestPriority;
3753
- updateEntityShow(viewer, rego.visual, getShowState(rego));
4575
+ updateEntityShow(viewer, rego.visual, rego.suppressShow ? false : getShowState(rego));
3754
4576
  }
3755
4577
  }
3756
4578
  function markEntity(register, rego, visual, ignoreParent) {
@@ -3947,6 +4769,17 @@ var VisualsRegister;
3947
4769
  enumerable: false,
3948
4770
  configurable: true
3949
4771
  });
4772
+ Register.prototype.ForceUpdate = function (params) {
4773
+ var entityIds = params.entityIds;
4774
+ for (var i = 0; i < entityIds.length; i++) {
4775
+ var entityId = entityIds[i];
4776
+ updateEntity(this.viewer, entityId, this);
4777
+ this.OnUpdate.Trigger({
4778
+ type: EVisualUpdateType.Update,
4779
+ entityId: entityId
4780
+ });
4781
+ }
4782
+ };
3950
4783
  Register.prototype.SetSelectionColor = function (color) {
3951
4784
  this.selectionColor = color;
3952
4785
  };
@@ -4469,6 +5302,9 @@ var EntitiesIdsRenderManager;
4469
5302
  this.monitor = monitor;
4470
5303
  this.item = item;
4471
5304
  this.visualsManager = visualsManager;
5305
+ if (this.item.enableClustering) {
5306
+ this.clustering = new PointClustering(visualsManager, this.item.id);
5307
+ }
4472
5308
  }
4473
5309
  Object.defineProperty(Manager.prototype, "Disposed", {
4474
5310
  get: function () {
@@ -4489,7 +5325,7 @@ var EntitiesIdsRenderManager;
4489
5325
  this.getter.Start();
4490
5326
  };
4491
5327
  Manager.prototype.Dispose = function () {
4492
- var _a;
5328
+ var _a, _b;
4493
5329
  if (this.disposed) {
4494
5330
  return;
4495
5331
  }
@@ -4499,6 +5335,7 @@ var EntitiesIdsRenderManager;
4499
5335
  this.visualsManager.RemoveRegos({
4500
5336
  menuItemId: this.item.id
4501
5337
  });
5338
+ (_b = this.clustering) === null || _b === void 0 ? void 0 : _b.Dispose();
4502
5339
  };
4503
5340
  Manager.prototype.ReRender = function (params) {
4504
5341
  return __awaiter(this, void 0, void 0, function () {
@@ -4567,19 +5404,19 @@ var EntitiesIdsRenderManager;
4567
5404
  });
4568
5405
  };
4569
5406
  Manager.prototype.renderEntities = function (entities, force) {
4570
- var _a;
5407
+ var _a, _b;
4571
5408
  if (force === void 0) { force = false; }
4572
5409
  return __awaiter(this, void 0, void 0, function () {
4573
- var cEntities, i, entity, id, cEntity, visual, e_2;
4574
- return __generator(this, function (_b) {
4575
- switch (_b.label) {
5410
+ var cEntities, i, entity, id, cEntity, visual, clustered, e_2;
5411
+ return __generator(this, function (_c) {
5412
+ switch (_c.label) {
4576
5413
  case 0:
4577
5414
  if (this.disposed || this.viewer.isDestroyed()) {
4578
5415
  return [2 /*return*/];
4579
5416
  }
4580
- _b.label = 1;
5417
+ _c.label = 1;
4581
5418
  case 1:
4582
- _b.trys.push([1, 3, , 4]);
5419
+ _c.trys.push([1, 3, , 4]);
4583
5420
  return [4 /*yield*/, EntityRenderEngine.Render({
4584
5421
  viewer: this.viewer,
4585
5422
  apiGetter: this.apiGetter,
@@ -4590,7 +5427,7 @@ var EntitiesIdsRenderManager;
4590
5427
  force: force
4591
5428
  })];
4592
5429
  case 2:
4593
- cEntities = _b.sent();
5430
+ cEntities = _c.sent();
4594
5431
  for (i = 0; i < entities.length; i++) {
4595
5432
  entity = entities[i];
4596
5433
  id = entity.Bruce.ID;
@@ -4602,6 +5439,7 @@ var EntitiesIdsRenderManager;
4602
5439
  menuItemId: this.item.id
4603
5440
  })) === null || _a === void 0 ? void 0 : _a.visual;
4604
5441
  if (!visual || visual != cEntity) {
5442
+ clustered = this.clustering ? this.clustering.AddEntity(id, cEntity) : false;
4605
5443
  this.visualsManager.AddRego({
4606
5444
  rego: {
4607
5445
  entityId: id,
@@ -4609,7 +5447,8 @@ var EntitiesIdsRenderManager;
4609
5447
  visual: cEntity,
4610
5448
  priority: 0,
4611
5449
  entityTypeId: entity.Bruce["EntityType.ID"],
4612
- accountId: this.apiGetter.accountId
5450
+ accountId: this.apiGetter.accountId,
5451
+ suppressShow: clustered
4613
5452
  }
4614
5453
  });
4615
5454
  }
@@ -4619,12 +5458,13 @@ var EntitiesIdsRenderManager;
4619
5458
  entityId: id,
4620
5459
  menuItemId: this.item.id
4621
5460
  });
5461
+ (_b = this.clustering) === null || _b === void 0 ? void 0 : _b.RemoveEntity(id);
4622
5462
  }
4623
5463
  }
4624
5464
  this.viewer.scene.requestRender();
4625
5465
  return [3 /*break*/, 4];
4626
5466
  case 3:
4627
- e_2 = _b.sent();
5467
+ e_2 = _c.sent();
4628
5468
  console.error(e_2);
4629
5469
  return [3 /*break*/, 4];
4630
5470
  case 4: return [2 /*return*/];
@@ -9993,7 +10833,7 @@ var ViewRenderEngine;
9993
10833
  ViewRenderEngine.Render = Render;
9994
10834
  })(ViewRenderEngine || (ViewRenderEngine = {}));
9995
10835
 
9996
- var VERSION = "2.1.3";
10836
+ var VERSION = "2.1.9";
9997
10837
 
9998
10838
  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 };
9999
10839
  //# sourceMappingURL=bruce-cesium.es5.js.map