bruce-cesium 6.6.5 → 6.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- import { Cartes, Entity as Entity$1, Calculator, EntityRelationType, EntityType, Style, ENVIRONMENT, ProjectViewTile, DelayQueue, LRUCache, BruceEvent, ObjectUtils, Geometry, EntityHistoricData, EntityLod, ZoomControl, EntityTag, Tileset, EntityCoords, Api, DataLab, EntitySource, ClientFile, MenuItem, EntityRelation, ProgramKey, Bounds, Carto, ProjectView, ProjectViewBookmark, ProjectViewLegacyTile, Camera, AbstractApi, Session, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils } from 'bruce-models';
1
+ import { Cartes, Entity as Entity$1, Geometry, ProjectViewTile, ENVIRONMENT, EntityRelationType, EntityType, Calculator, Style, DelayQueue, LRUCache, BruceEvent, ObjectUtils, AccountConcept, EntityHistoricData, EntityLod, RecordChangeFeed, ZoomControl, EntityTag, Tileset, EntityCoords, Api, DataLab, EntitySource, ClientFile, MenuItem, EntityRelation, ProgramKey, Bounds, Carto, ProjectView, ProjectViewBookmark, ProjectViewLegacyTile, Camera, AbstractApi, Session, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils } from 'bruce-models';
2
2
  import * as Cesium from 'cesium';
3
- import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, Math as Math$1, Cartesian3, JulianDate, Quaternion, Transforms, HeadingPitchRoll, Matrix4, DistanceDisplayCondition, HeightReference, ColorBlendMode, ShadowMode, ClassificationType, Model, HorizontalOrigin, VerticalOrigin, ConstantPositionProperty, PolygonHierarchy, PolylineGraphics, ArcType, CornerType, Cartesian2, SceneTransforms, NearFarScalar, Matrix3, Rectangle, KmlDataSource, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, HeadingPitchRange, Cesium3DTileColorBlendMode, Ion, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, IonResource, Cesium3DTileset, OrthographicFrustum, EasingFunction, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, PolygonPipeline, CesiumInspector, ClockRange, BoundingSphere, GeometryInstance, ScreenSpaceEventHandler, ScreenSpaceEventType, Intersect, CzmlDataSource, Fullscreen } from 'cesium';
3
+ import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, DistanceDisplayCondition, Cartesian3, HeightReference, ClassificationType, PolygonHierarchy, ShadowMode, ConstantPositionProperty, PolylineGraphics, ArcType, CornerType, HorizontalOrigin, VerticalOrigin, Math as Math$1, JulianDate, Quaternion, Transforms, HeadingPitchRoll, Matrix4, ColorBlendMode, Model, Cartesian2, SceneTransforms, NearFarScalar, Matrix3, Rectangle, KmlDataSource, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, HeadingPitchRange, Cesium3DTileColorBlendMode, Ion, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, IonResource, OrthographicFrustum, EasingFunction, Cesium3DTileset, BoundingSphere, GeometryInstance, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, PolygonPipeline, CesiumInspector, ClockRange, ScreenSpaceEventHandler, ScreenSpaceEventType, Intersect, CzmlDataSource, Fullscreen } from 'cesium';
4
4
 
5
5
  /**
6
6
  * Ensures a number is returned from a given value.
@@ -2582,609 +2582,846 @@ var CesiumEntityStyler;
2582
2582
  CesiumEntityStyler.Unhighlight = Unhighlight;
2583
2583
  })(CesiumEntityStyler || (CesiumEntityStyler = {}));
2584
2584
 
2585
+ function isTurfAvailable() {
2586
+ return window && window.turf != null;
2587
+ }
2585
2588
  /**
2586
- * Utility for rendering parabolas between two points on the map.
2589
+ * Util for simplifying geometry on the fly.
2587
2590
  */
2588
- class CesiumParabola {
2589
- get Disposed() {
2590
- return this.disposed;
2591
- }
2592
- set Hidden(value) {
2593
- this.hidden = value;
2594
- }
2595
- get curPos1() {
2596
- return this.pos1 instanceof Function ? this.pos1() : this.pos1;
2591
+ var SimplifyGeometry;
2592
+ (function (SimplifyGeometry) {
2593
+ /**
2594
+ * Returns the total number of points in the geometry.
2595
+ * @param geometry
2596
+ * @param limit number to count up to before returning.
2597
+ * @returns
2598
+ */
2599
+ function CountPoints(geometry, limit) {
2600
+ let count = 0;
2601
+ const traverse = (geometry) => {
2602
+ if (geometry.MultiGeometry) {
2603
+ for (let i = 0; i < geometry.MultiGeometry.length; i++) {
2604
+ traverse(geometry.MultiGeometry[i]);
2605
+ // Reached the limit, return.
2606
+ if (limit && count >= limit) {
2607
+ return;
2608
+ }
2609
+ }
2610
+ }
2611
+ else if (geometry.Polygon) {
2612
+ for (let i = 0; i < geometry.Polygon.length; i++) {
2613
+ const polygon = geometry.Polygon[i];
2614
+ count += Geometry.ParsePoints(polygon.LinearRing).length;
2615
+ }
2616
+ }
2617
+ else if (geometry.LineString) {
2618
+ count += Geometry.ParsePoints(geometry.LineString).length;
2619
+ }
2620
+ else if (geometry.Point) {
2621
+ count += 1;
2622
+ }
2623
+ };
2624
+ traverse(geometry);
2625
+ return count;
2597
2626
  }
2598
- get curPos2() {
2599
- return this.pos2 instanceof Function ? this.pos2() : this.pos2;
2627
+ SimplifyGeometry.CountPoints = CountPoints;
2628
+ /**
2629
+ * Simplifies input geometry.
2630
+ * This will turn it into GeoJSON, run it through turf, then back to Bruce geometry.
2631
+ * @param geometry
2632
+ */
2633
+ function Simplify(entityId, geometry, tolerance) {
2634
+ var _a;
2635
+ if (!geometry || !isTurfAvailable() || !turf.simplify) {
2636
+ return geometry;
2637
+ }
2638
+ // Convert to geojson so that we can interact with turf.
2639
+ const gFeature = Geometry.ToGeoJsonFeature({
2640
+ geometry: geometry
2641
+ });
2642
+ // Unkink the geometry.
2643
+ // This removes overlapping polygons before we start merging and simplifying.
2644
+ // Commented out because it has crashes and doesn't handle holes.
2645
+ untangleFeature(gFeature);
2646
+ // Union the geometry.
2647
+ // This merges overlapping polygons.
2648
+ unionFeature(gFeature);
2649
+ // Simplify the geometry.
2650
+ if (tolerance > 0) {
2651
+ gFeature.geometry = turf.simplify(gFeature.geometry, {
2652
+ tolerance: tolerance,
2653
+ highQuality: true,
2654
+ mutate: true
2655
+ });
2656
+ }
2657
+ // Converting back to Bruce geometry.
2658
+ geometry = (_a = Geometry.FromGeoJson({
2659
+ geoJson: gFeature
2660
+ })) === null || _a === void 0 ? void 0 : _a.geometry;
2661
+ return geometry;
2600
2662
  }
2601
- constructor(params) {
2602
- this.disposed = false;
2603
- this.color = "white";
2604
- this.width = 2;
2605
- this.duration = 10;
2606
- this.heightDistanceRatio = 0.25;
2607
- this.curPoints = [];
2608
- this.animateInterval = null;
2609
- this.retryTimeout = null;
2610
- this.hidden = false;
2611
- this.viewer = params.viewer;
2612
- this.pos1 = params.pos1;
2613
- this.pos2 = params.pos2;
2614
- if (params.color) {
2615
- this.color = params.color;
2663
+ SimplifyGeometry.Simplify = Simplify;
2664
+ })(SimplifyGeometry || (SimplifyGeometry = {}));
2665
+ /**
2666
+ * Runs through all found polygons and runs unkink through turf on them.
2667
+ * @param feature
2668
+ */
2669
+ function untangleFeature(feature) {
2670
+ // Collection to add to because the result might be multiple from an unkink.
2671
+ const collection = {
2672
+ geometries: [],
2673
+ type: "GeometryCollection"
2674
+ };
2675
+ // Runs a dedupe and unkink on the coordinates.
2676
+ // Returns if the coordinates were added to the collection.
2677
+ const processCoordinates = (coords) => {
2678
+ try {
2679
+ // Dedupe the coordinates to avoid issues with unkink.
2680
+ coords = dedupeCoordinates(coords);
2681
+ const outer = [];
2682
+ let inner = [];
2683
+ // We'll unkink each ring separately as this is killing the holes when it is done as a whole.
2684
+ // So we'll do it separate then recombine.
2685
+ for (let i = 0; i < coords.length; i++) {
2686
+ const ring = coords[i];
2687
+ const unkink = turf.unkinkPolygon({
2688
+ type: "Polygon",
2689
+ coordinates: [ring]
2690
+ });
2691
+ if (unkink.type == "FeatureCollection") {
2692
+ let target = i == 0 ? outer : inner;
2693
+ for (let j = 0; j < unkink.features.length; j++) {
2694
+ const unkinked = unkink.features[j].geometry.coordinates;
2695
+ if (unkinked.length > 0) {
2696
+ target.push(unkinked[0]);
2697
+ }
2698
+ }
2699
+ }
2700
+ else {
2701
+ console.error("Unexpected unkink result.", unkink);
2702
+ }
2703
+ }
2704
+ // Recreate the rings and reapply to the collection.
2705
+ if (outer.length > 0) {
2706
+ const combinedCoords = [outer[0]];
2707
+ for (let i = 0; i < inner.length; i++) {
2708
+ combinedCoords.push(inner[i]);
2709
+ }
2710
+ // Add the combined coordinates to the collection
2711
+ const polygon = {
2712
+ type: "Polygon",
2713
+ coordinates: combinedCoords
2714
+ };
2715
+ // Ensure right-hand rule is followed.
2716
+ ensureRightHandRule(polygon);
2717
+ // Add to the collection.
2718
+ collection.geometries.push(polygon);
2719
+ return true;
2720
+ }
2616
2721
  }
2617
- if (!isNaN(params.width)) {
2618
- this.width = params.width;
2722
+ catch (e) {
2723
+ // console.error("Failed to unkink polygon.", e);
2619
2724
  }
2620
- if (!isNaN(params.duration)) {
2621
- this.duration = params.duration;
2725
+ return false;
2726
+ };
2727
+ const processGeometry = (geometry) => {
2728
+ let added = false;
2729
+ if (geometry.type == "Polygon") {
2730
+ added = processCoordinates(geometry.coordinates);
2622
2731
  }
2623
- if (!isNaN(params.heightDistanceRatio)) {
2624
- this.heightDistanceRatio = params.heightDistanceRatio;
2732
+ else if (geometry.type == "MultiPolygon") {
2733
+ for (let i = 0; i < geometry.coordinates.length; i++) {
2734
+ added = processCoordinates(geometry.coordinates[i]) || added;
2735
+ }
2625
2736
  }
2626
- this.prepareEntities();
2737
+ if (!added) {
2738
+ // Adding original since we can't unkink it.
2739
+ collection.geometries.push(geometry);
2740
+ }
2741
+ };
2742
+ if (feature.geometry.type == "GeometryCollection") {
2743
+ feature.geometry.geometries.forEach((geometry) => {
2744
+ processGeometry(geometry);
2745
+ });
2627
2746
  }
2628
- prepareEntities() {
2629
- const parabola = new Entity({
2630
- polyline: {
2631
- positions: new CallbackProperty(() => {
2632
- return this.curPoints;
2633
- }, false),
2634
- width: this.width,
2635
- material: Color.fromCssColorString(this.color),
2636
- show: new CallbackProperty(() => {
2637
- return !this.hidden;
2638
- }, false)
2747
+ else {
2748
+ processGeometry(feature.geometry);
2749
+ }
2750
+ // Re-assign the geometry.
2751
+ if (collection.geometries.length == 1) {
2752
+ feature.geometry = collection.geometries[0];
2753
+ }
2754
+ else {
2755
+ feature.geometry = collection;
2756
+ }
2757
+ }
2758
+ /**
2759
+ * Runs through all found polygons and unions them using turf.
2760
+ * Failed unions are ignored and the original is kept.
2761
+ * @param feature
2762
+ */
2763
+ function unionFeature(feature) {
2764
+ // Collection to add to because the result might be multiple from an unkink.
2765
+ const collection = {
2766
+ geometries: [],
2767
+ type: "GeometryCollection"
2768
+ };
2769
+ // We'll turn each geometry into a feature and union them.
2770
+ const tmpCollection = {
2771
+ features: [],
2772
+ type: "FeatureCollection"
2773
+ };
2774
+ if (feature.geometry.type == "GeometryCollection") {
2775
+ feature.geometry.geometries.forEach((geometry) => {
2776
+ if (geometry.type == "Polygon") {
2777
+ tmpCollection.features.push({
2778
+ type: "Feature",
2779
+ geometry: geometry,
2780
+ properties: {}
2781
+ });
2639
2782
  }
2640
- });
2641
- const p1Entity = new Entity({
2642
- position: new CallbackProperty(() => {
2643
- return this.curPoints.length ? this.curPoints[0] : new Cartesian3();
2644
- }, false),
2645
- point: {
2646
- heightReference: HeightReference.NONE,
2647
- pixelSize: this.width * 1.3,
2648
- color: Color.fromCssColorString(this.color),
2649
- outlineColor: Color.WHITE,
2650
- outlineWidth: 2,
2651
- show: new CallbackProperty(() => {
2652
- return !this.hidden;
2653
- }, false)
2783
+ else if (geometry.type == "MultiPolygon") {
2784
+ for (let i = 0; i < geometry.coordinates.length; i++) {
2785
+ tmpCollection.features.push({
2786
+ type: "Feature",
2787
+ geometry: {
2788
+ type: "Polygon",
2789
+ coordinates: geometry.coordinates[i]
2790
+ },
2791
+ properties: {}
2792
+ });
2793
+ }
2654
2794
  }
2655
- });
2656
- const p2Entity = new Entity({
2657
- position: new CallbackProperty(() => {
2658
- return this.curPoints.length ? this.curPoints[this.curPoints.length - 1] : new Cartesian3();
2659
- }, false),
2660
- point: {
2661
- heightReference: HeightReference.NONE,
2662
- pixelSize: this.width * 1.8,
2663
- color: Color.fromCssColorString(this.color),
2664
- outlineColor: Color.WHITE,
2665
- outlineWidth: 2,
2666
- show: new CallbackProperty(() => {
2667
- return !this.hidden;
2668
- }, false)
2795
+ // Only focusing on polygons.
2796
+ else {
2797
+ collection.geometries.push(geometry);
2669
2798
  }
2670
2799
  });
2671
- p1Entity.parent = parabola;
2672
- p2Entity.parent = parabola;
2673
- const siblings = [p1Entity, p2Entity];
2674
- this.parabola = parabola;
2675
- this.siblings = siblings;
2676
- // The parabola is hidden while this entity is not added.
2677
- // If we avoid adding it now, then the parent can control if the parabola is visible at first or not.
2678
- // this.viewer.entities.add(this.parabola);
2679
- this.viewer.entities.add(p1Entity);
2680
- this.viewer.entities.add(p2Entity);
2681
2800
  }
2682
- Animate() {
2683
- if (this.disposed) {
2684
- return null;
2801
+ else if (feature.geometry.type == "Polygon") {
2802
+ tmpCollection.features.push({
2803
+ type: "Feature",
2804
+ geometry: feature.geometry,
2805
+ properties: {}
2806
+ });
2807
+ }
2808
+ else if (feature.geometry.type == "MultiPolygon") {
2809
+ for (let i = 0; i < feature.geometry.coordinates.length; i++) {
2810
+ tmpCollection.features.push({
2811
+ type: "Feature",
2812
+ geometry: {
2813
+ type: "Polygon",
2814
+ coordinates: feature.geometry.coordinates[i]
2815
+ },
2816
+ properties: {}
2817
+ });
2685
2818
  }
2686
- let retry = false;
2687
- if (!this.curPos1 || !this.curPos2 || !Cartes.ValidateCartes3(this.curPos1) || !Cartes.ValidateCartes3(this.curPos2)) {
2688
- retry = true;
2819
+ }
2820
+ // No polygons to union.
2821
+ // Need at least 2 to union.
2822
+ if (tmpCollection.features.length < 2) {
2823
+ return;
2824
+ }
2825
+ // Now we'll union them.
2826
+ try {
2827
+ const union = turf.union(tmpCollection);
2828
+ if (union.geometry.type == "Polygon") {
2829
+ collection.geometries.push(union.geometry);
2689
2830
  }
2690
- let TOTAL_LENGTH = retry ? 0 : Cartesian3.distance(this.curPos1, this.curPos2);
2691
- if (TOTAL_LENGTH <= 0) {
2692
- retry = true;
2831
+ else if (union.geometry.type == "MultiPolygon") {
2832
+ for (let i = 0; i < union.geometry.coordinates.length; i++) {
2833
+ collection.geometries.push({
2834
+ type: "Polygon",
2835
+ coordinates: union.geometry.coordinates[i]
2836
+ });
2837
+ }
2693
2838
  }
2694
- if (retry) {
2695
- this.retryTimeout = setTimeout(() => {
2696
- this.Animate();
2697
- }, 2000);
2698
- return {
2699
- parabola: this.parabola,
2700
- siblings: this.siblings
2701
- };
2839
+ else {
2840
+ // Returning early because the result is unexpected.
2841
+ return;
2702
2842
  }
2703
- const RATE_PER_SECOND = 1000 / 40;
2704
- const SEC_DURATION = this.duration;
2705
- const HEIGHT_DISTANCE_RATIO = this.heightDistanceRatio;
2706
- let TOTAL_POINTS = null;
2707
- let POINT_LENGTH = null;
2708
- let TICK_LENGTH_INC = null;
2709
- // Updates TOTAL_POINTS, POINT_LENGTH, and TICK_LENGTH_INC based on current TOTAL_LENGTH and camera position.
2710
- // We want less points the further away the camera is.
2711
- const updateParams = () => {
2712
- var _a, _b;
2713
- // TODO: Do distance to parabola line instead.
2714
- const MIN_POINTS = 30;
2715
- let totalPoints = 80;
2716
- let cameraHeight = (_b = (_a = this.viewer.camera) === null || _a === void 0 ? void 0 : _a.positionCartographic) === null || _b === void 0 ? void 0 : _b.height;
2717
- if (isNaN(cameraHeight) || cameraHeight >= 100000) {
2718
- totalPoints = MIN_POINTS;
2719
- }
2720
- else if (cameraHeight >= 10000) {
2721
- totalPoints = 50;
2722
- }
2723
- else if (cameraHeight >= 1000) {
2724
- totalPoints = 80;
2725
- }
2726
- else if (cameraHeight >= 100) {
2727
- totalPoints = 100;
2728
- }
2729
- TOTAL_POINTS = Math.max(MIN_POINTS, Math.min(totalPoints, TOTAL_LENGTH * 0.1));
2730
- POINT_LENGTH = TOTAL_LENGTH / TOTAL_POINTS;
2731
- TICK_LENGTH_INC = SEC_DURATION == 0 ? TOTAL_LENGTH : TOTAL_POINTS / (RATE_PER_SECOND * SEC_DURATION);
2732
- };
2733
- updateParams();
2734
- let curPoint = 0;
2735
- let quadraticKey = null;
2736
- let quadratic = null;
2737
- let quadraticPreparing = false;
2738
- const prepareQuadratic = async () => {
2739
- if (quadraticPreparing) {
2740
- return;
2741
- }
2742
- quadraticPreparing = true;
2743
- try {
2744
- const p1 = this.curPos1;
2745
- const p2 = this.curPos2;
2746
- if (!p1 || !p2 || !Cartes.ValidateCartes3(p1) || !Cartes.ValidateCartes3(p2)) {
2747
- return;
2748
- }
2749
- const height1 = Cartographic.fromCartesian(p1).height;
2750
- const height2 = Cartographic.fromCartesian(p2).height;
2751
- if (isNaN(height1) || isNaN(height2)) {
2752
- return;
2753
- }
2754
- const totalHeight = height2 + height1;
2755
- const curQuadraticKey = `${height1}-${height2}-${TOTAL_LENGTH}`;
2756
- if (quadraticKey == curQuadraticKey) {
2757
- return;
2758
- }
2759
- const points2d = [
2760
- new Cartesian2(0, height1),
2761
- new Cartesian2(TOTAL_LENGTH, height2)
2762
- ];
2763
- let vertexHeight = 0;
2764
- // Flat line.
2765
- if (HEIGHT_DISTANCE_RATIO == 0) {
2766
- vertexHeight = totalHeight * 0.5;
2767
- }
2768
- else {
2769
- const largestHeight = Math.max(height1, height2);
2770
- vertexHeight = largestHeight + (TOTAL_LENGTH * HEIGHT_DISTANCE_RATIO);
2771
- }
2772
- points2d.push(new Cartesian2(TOTAL_LENGTH * 0.5, vertexHeight));
2773
- const calcQuadratic = (points) => {
2774
- // Swaps position of two rows in matrix.
2775
- function swapRows(matrix, rowAIndex, rowBIndex) {
2776
- const rowAVal = matrix[rowAIndex];
2777
- matrix[rowAIndex] = matrix[rowBIndex];
2778
- matrix[rowBIndex] = rowAVal;
2779
- return matrix;
2780
- }
2781
- // Zeros rowA at colIndex by subtracting a multiplied rowB from it.
2782
- function reduceMatrixRowByRow(matrix, zeroingIndex, parentIndex, colIndex) {
2783
- const zeroRow = matrix[zeroingIndex];
2784
- const parentRow = matrix[parentIndex];
2785
- if (zeroRow[colIndex] == 0) {
2786
- return matrix;
2787
- }
2788
- else if (parentRow[colIndex] == 0) {
2789
- matrix = swapRows(matrix, parentIndex, zeroingIndex);
2790
- return divideMatrixRow(matrix, parentIndex, colIndex);
2791
- }
2792
- // rowAIndex colIndex / rowBIndex colIndex = factor;
2793
- let factor = zeroRow[colIndex] / parentRow[colIndex];
2794
- for (let i = 0; i < zeroRow.length; i++) {
2795
- if (i >= colIndex) {
2796
- zeroRow[i] -= parentRow[i] * factor;
2797
- }
2798
- }
2799
- return matrix;
2800
- }
2801
- // Makes a given row column equal 1 by diving while row by that column.
2802
- function divideMatrixRow(matrix, rowIndex, colIndex) {
2803
- const row = matrix[rowIndex];
2804
- const colValue = row[colIndex];
2805
- for (let i = 0; i < row.length; i++) {
2806
- if (i >= colIndex) {
2807
- row[i] /= colValue;
2808
- }
2809
- }
2810
- return matrix;
2811
- }
2812
- // Returns initial matrix for calculating a, b and c for quadratic formula from given points.
2813
- function matrixFromPoints(points) {
2814
- const rows = [];
2815
- const constructRow = (point) => {
2816
- rows.push([
2817
- -Math.pow(point.x, 2),
2818
- point.x,
2819
- 1,
2820
- point.y
2821
- ]);
2822
- };
2823
- for (let i = 0; i < points.length; i++) {
2824
- constructRow(points[i]);
2825
- }
2826
- return rows;
2827
- }
2828
- const initialMatrix = matrixFromPoints(points);
2829
- const step1Matrix = reduceMatrixRowByRow(initialMatrix, 1, 0, 0);
2830
- const step2Matrix = reduceMatrixRowByRow(step1Matrix, 2, 0, 0);
2831
- const step3Matrix = reduceMatrixRowByRow(step2Matrix, 2, 1, 1);
2832
- const step4Matrix = reduceMatrixRowByRow(step3Matrix, 0, 1, 1);
2833
- const step5Matrix = reduceMatrixRowByRow(step4Matrix, 0, 2, 2);
2834
- const step6Matrix = reduceMatrixRowByRow(step5Matrix, 1, 2, 2);
2835
- const a = step6Matrix[0][3];
2836
- const b = step6Matrix[1][3];
2837
- const c = step6Matrix[2][3];
2838
- return { a: a, b: b, c: c };
2839
- };
2840
- quadratic = calcQuadratic(points2d);
2843
+ }
2844
+ catch (e) {
2845
+ // console.error("Failed to union polygons.", e);
2846
+ return;
2847
+ }
2848
+ // Re-assign the geometry.
2849
+ if (collection.geometries.length == 1) {
2850
+ feature.geometry = collection.geometries[0];
2851
+ }
2852
+ else {
2853
+ feature.geometry = collection;
2854
+ }
2855
+ }
2856
+ function dedupeCoordinates(inputCoords) {
2857
+ return inputCoords.map(ring => {
2858
+ if (ring.length < 2) {
2859
+ return ring;
2860
+ }
2861
+ const dedupeCoords = [];
2862
+ const uniqueCoords = new Set();
2863
+ // Dedupe the points.
2864
+ ring.forEach(coord => {
2865
+ const key = coord.join(',');
2866
+ if (!uniqueCoords.has(key)) {
2867
+ uniqueCoords.add(key);
2868
+ dedupeCoords.push(coord);
2841
2869
  }
2842
- catch (e) {
2843
- console.error(e);
2870
+ });
2871
+ // Make sure the last point matches the first.
2872
+ if (dedupeCoords.length > 1) {
2873
+ if (dedupeCoords[0][0] != dedupeCoords[dedupeCoords.length - 1][0] ||
2874
+ dedupeCoords[0][1] != dedupeCoords[dedupeCoords.length - 1][1]) {
2875
+ dedupeCoords.push(dedupeCoords[0]);
2844
2876
  }
2845
- finally {
2846
- quadraticPreparing = false;
2847
- }
2848
- };
2849
- const getPosition = (increment) => {
2850
- if (!quadratic) {
2851
- return null;
2852
- }
2853
- let lengthAcross = POINT_LENGTH * increment;
2854
- if (lengthAcross > TOTAL_LENGTH) {
2855
- lengthAcross = TOTAL_LENGTH;
2856
- }
2857
- const getParabolaYFromX = (x, quadLetters) => {
2858
- let a = quadLetters.a;
2859
- let b = quadLetters.b;
2860
- let c = quadLetters.c;
2861
- return (-a * Math.pow(x, 2)) + (b * x) + c;
2862
- };
2863
- const { point: pos3d } = DrawingUtils.PointAcrossPolyline({
2864
- viewer: this.viewer,
2865
- distance: lengthAcross,
2866
- posses: [this.curPos1, this.curPos2]
2867
- });
2868
- const point = Cartographic.fromCartesian(pos3d);
2869
- const posHeight = getParabolaYFromX(lengthAcross, quadratic);
2870
- return Cartesian3.fromRadians(point.longitude, point.latitude, posHeight);
2871
- };
2872
- const updatePoints = () => {
2873
- if (!quadratic) {
2874
- return;
2875
- }
2876
- const increment = Math.floor(curPoint);
2877
- const chips = curPoint - Math.floor(curPoint);
2878
- const posses = [];
2879
- posses.push(getPosition(0));
2880
- const addLast = increment >= TOTAL_POINTS;
2881
- const totalCycles = addLast ? increment + 1 : increment;
2882
- for (let i = 0; i < totalCycles; i++) {
2883
- posses.push(getPosition(i));
2884
- }
2885
- if (chips) {
2886
- posses.push(getPosition(increment + chips));
2887
- }
2888
- if (posses.find(x => !x || !Cartes.ValidateCartes3(x))) {
2889
- return;
2890
- }
2891
- this.curPoints = posses;
2892
- };
2893
- let lastTickDate = new Date();
2894
- let finished = false;
2895
- const doTick = () => {
2896
- const curDate = new Date();
2897
- const seconds = (curDate.getTime() - lastTickDate.getTime()) / 1000;
2898
- const ticks = seconds * RATE_PER_SECOND;
2899
- if (!isNaN(ticks) && ticks >= 1) {
2900
- lastTickDate = curDate;
2901
- const p1 = this.curPos1;
2902
- const p2 = this.curPos2;
2903
- const newLength = p1 && p2 ? Cartesian3.distance(p1, p2) : -1;
2904
- if (newLength > 0 && newLength != TOTAL_LENGTH) {
2905
- TOTAL_LENGTH = newLength;
2906
- updateParams();
2907
- }
2908
- prepareQuadratic();
2909
- if (quadratic) {
2910
- if (curPoint < TOTAL_POINTS) {
2911
- curPoint += (TICK_LENGTH_INC * ticks);
2912
- }
2913
- updatePoints();
2914
- }
2915
- this.viewer.scene.requestRender();
2916
- if (curPoint >= TOTAL_POINTS && !finished) {
2917
- finished = true;
2918
- // We can make the interval update super slow now.
2919
- // We keep it updating in case the positions move.
2920
- clearInterval(this.animateInterval);
2921
- this.animateInterval = setInterval(doTick, 3000);
2922
- }
2923
- }
2924
- };
2925
- this.animateInterval = setInterval(doTick, RATE_PER_SECOND);
2926
- return {
2927
- parabola: this.parabola,
2928
- siblings: this.siblings
2929
- };
2877
+ }
2878
+ return dedupeCoords;
2879
+ });
2880
+ }
2881
+ function ensureRightHandRule(polygon) {
2882
+ // Ensure the outer ring follows the right-hand rule
2883
+ if (polygon.coordinates.length > 0) {
2884
+ const outerRing = polygon.coordinates[0];
2885
+ if (isClockwise(outerRing)) {
2886
+ polygon.coordinates[0] = outerRing.reverse();
2887
+ }
2930
2888
  }
2931
- Dispose() {
2932
- this.disposed = true;
2933
- clearTimeout(this.retryTimeout);
2934
- clearInterval(this.animateInterval);
2935
- const cEntities = [
2936
- this.parabola
2937
- ].concat(this.siblings);
2938
- cEntities.forEach(e => {
2939
- if (e && this.viewer.entities.contains(e)) {
2940
- this.viewer.entities.remove(e);
2941
- }
2942
- });
2889
+ // Ensure any inner rings (holes) follow the right-hand rule
2890
+ for (let i = 1; i < polygon.coordinates.length; i++) {
2891
+ const innerRing = polygon.coordinates[i];
2892
+ if (!isClockwise(innerRing)) {
2893
+ polygon.coordinates[i] = innerRing.reverse();
2894
+ }
2895
+ }
2896
+ }
2897
+ function isClockwise(ring) {
2898
+ let sum = 0;
2899
+ for (let i = 0; i < ring.length - 1; i++) {
2900
+ const p1 = ring[i];
2901
+ const p2 = ring[i + 1];
2902
+ sum += (p2[0] - p1[0]) * (p2[1] + p1[1]);
2943
2903
  }
2904
+ return sum > 0;
2944
2905
  }
2945
2906
 
2946
- function colorToCColor(color) {
2947
- return new Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
2907
+ function OnNextCRender(viewer, callback) {
2908
+ const removal = viewer.scene.postRender.addEventListener(() => {
2909
+ removal();
2910
+ callback();
2911
+ });
2948
2912
  }
2949
- async function getStyle(api, typeId, styleId) {
2950
- let style = null;
2951
- if (styleId && styleId != -1) {
2952
- try {
2953
- style = (await Style.Get({
2954
- api,
2955
- styleId
2956
- })).style;
2957
- }
2958
- // Probably deleted.
2959
- catch (e) {
2960
- console.error(e);
2913
+ function GetCValue(viewer, obj) {
2914
+ if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
2915
+ let date = viewer.scene.lastRenderTime;
2916
+ if (!date) {
2917
+ date = viewer.clock.currentTime;
2961
2918
  }
2919
+ return obj.getValue(date);
2962
2920
  }
2963
- if (!style && typeId) {
2964
- const { entityType: type } = await EntityType.Get({
2965
- api,
2966
- entityTypeId: typeId
2967
- });
2968
- if (type["DisplaySetting.ID"]) {
2969
- try {
2970
- style = (await Style.Get({
2971
- api,
2972
- styleId: type["DisplaySetting.ID"]
2973
- })).style;
2974
- }
2975
- catch (e) {
2976
- let hideError = false;
2977
- // TODO: we need a util for extracting code + message rather than writing all this every time.
2978
- if (e && typeof e == "object" && e.ERROR) {
2979
- const error = e.ERROR;
2980
- const code = error && typeof error == "object" ? error.Code : "";
2981
- // Avoiding logging a common error.
2982
- // This happens when rendering entities that don't have records.
2983
- hideError = String(code).toLowerCase() == "notfound";
2984
- }
2985
- if (!hideError) {
2986
- console.error(e);
2987
- }
2988
- }
2921
+ return obj;
2922
+ }
2923
+ function ColorToCColor(color) {
2924
+ return new Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
2925
+ }
2926
+ /**
2927
+ * Removes duplicate points in a row and returns a new array.
2928
+ * Passed array is not mutated.
2929
+ * @param posses
2930
+ */
2931
+ function CullDuplicateCPosses(posses) {
2932
+ const newPosses = [];
2933
+ let lastPos = null;
2934
+ for (let i = 0; i < posses.length; i++) {
2935
+ const pos = posses[i];
2936
+ // Avoiding 'Cesium.Cartesian3.equals' because passed data might be just a json blob in certain cases.
2937
+ if (pos && (!lastPos || (pos.x != lastPos.x || pos.y != lastPos.y || pos.z != lastPos.z))) {
2938
+ newPosses.push(pos);
2939
+ lastPos = pos;
2989
2940
  }
2990
2941
  }
2991
- return style;
2942
+ return newPosses;
2992
2943
  }
2993
- var RelationRenderEngine;
2994
- (function (RelationRenderEngine) {
2995
- function GetRenderGroupId(relation) {
2996
- return `${relation["Related.Entity.ID"]}-${relation["Principal.Entity.ID"]}-${relation["Relation.Type.ID"]}`;
2944
+ /**
2945
+ * Returns if the given positions are equal.
2946
+ * @param a
2947
+ * @param b
2948
+ */
2949
+ function CompareCPosses(a, b) {
2950
+ // Same reference.
2951
+ if (a == b) {
2952
+ return true;
2997
2953
  }
2998
- RelationRenderEngine.GetRenderGroupId = GetRenderGroupId;
2999
- async function Render(params) {
3000
- const { apiGetter, viewer, visualRegister, menuItemId, relations } = params;
3001
- const api = apiGetter.getApi(apiGetter.accountId);
3002
- const rendered = {};
3003
- let neededEntityIdsIds = [];
3004
- for (let i = 0; i < relations.length; i++) {
3005
- const relation = relations[i];
3006
- if (relation["Principal.Entity.ID"]) {
3007
- neededEntityIdsIds.push(relation["Principal.Entity.ID"]);
3008
- }
3009
- if (relation["Related.Entity.ID"]) {
3010
- neededEntityIdsIds.push(relation["Related.Entity.ID"]);
3011
- }
3012
- if (relation["Data.Entity.ID"]) {
3013
- neededEntityIdsIds.push(relation["Data.Entity.ID"]);
3014
- }
2954
+ // Different lengths or one is null.
2955
+ if ((!a || !b) || (a.length != b.length)) {
2956
+ return false;
2957
+ }
2958
+ for (let i = 0; i < a.length; i++) {
2959
+ const posA = a[i];
2960
+ const posB = b[i];
2961
+ // Null detected.
2962
+ if (!posA || !posB) {
2963
+ return false;
3015
2964
  }
3016
- // Turn the set unique.
3017
- neededEntityIdsIds = neededEntityIdsIds.filter((v, i, a) => a.indexOf(v) === i);
3018
- // Get all entities in one go.
3019
- let entities = (await Entity$1.GetListByIds({
3020
- entityIds: neededEntityIdsIds,
3021
- api: apiGetter.getApi(),
3022
- migrated: true,
3023
- maxSearchTimeSec: 60 * 2
3024
- })).entities;
3025
- // Create a map for quick reference.
3026
- const entitiesMap = {};
3027
- for (let i = 0; i < entities.length; i++) {
3028
- const entity = entities[i];
3029
- entitiesMap[entity.Bruce.ID] = entity;
2965
+ // Position values don't match.
2966
+ if (!Cartes.IsEqualCartes3(posA, posB)) {
2967
+ return false;
3030
2968
  }
3031
- entities = null;
3032
- // Gather needed relationship types.
3033
- // Right now this means just getting the full list.
3034
- const relationTypes = (await EntityRelationType.GetList({
3035
- api
3036
- })).relationTypes;
3037
- const relationTypesMap = {};
3038
- for (let i = 0; i < relationTypes.length; i++) {
3039
- const relationType = relationTypes[i];
3040
- relationTypesMap[relationType.ID] = relationType;
2969
+ }
2970
+ return true;
2971
+ }
2972
+ /**
2973
+ * Returns if the given polygon hierarchies are equal.
2974
+ * @param a
2975
+ * @param b
2976
+ */
2977
+ function CompareCPolygonHierarchies(a, b) {
2978
+ // Same reference.
2979
+ if (a == b) {
2980
+ return true;
2981
+ }
2982
+ // Different lengths or one is null.
2983
+ if ((!a || !b) || (a.positions.length != b.positions.length)) {
2984
+ return false;
2985
+ }
2986
+ // Positions don't match.
2987
+ if (!CompareCPosses(a.positions, b.positions)) {
2988
+ return false;
2989
+ }
2990
+ const holes = a.holes;
2991
+ const bHoles = b.holes;
2992
+ // Number of holes don't match.
2993
+ if (holes.length != bHoles.length) {
2994
+ return false;
2995
+ }
2996
+ for (let i = 0; i < holes.length; i++) {
2997
+ // Hole positions don't match.
2998
+ if (!CompareCPosses(holes[i].positions, bHoles[i].positions)) {
2999
+ return false;
3041
3000
  }
3042
- for (let i = 0; i < relations.length; i++) {
3043
- try {
3044
- const relation = relations[i];
3045
- const fromEntity = entitiesMap[relation["Principal.Entity.ID"]];
3046
- const toEntity = entitiesMap[relation["Related.Entity.ID"]];
3047
- const dataEntity = relation["Data.Entity.ID"] ? entitiesMap[relation["Data.Entity.ID"]] : null;
3048
- const relationType = relationTypesMap[relation["Relation.Type.ID"]];
3049
- const style = await getStyle(api, relationType === null || relationType === void 0 ? void 0 : relationType["Relation.EntityType.ID"], Number(relationType === null || relationType === void 0 ? void 0 : relationType.EntityDisplaySettingID));
3050
- const cEntity = await Parabola.Render({
3051
- dataEntity,
3052
- fromEntity,
3053
- relation,
3054
- style,
3055
- toEntity,
3056
- viewer,
3057
- visualRegister,
3058
- apiGetter
3001
+ }
3002
+ return true;
3003
+ }
3004
+
3005
+ const CESIUM_INSPECTOR_KEY = "_nextspace_inspector";
3006
+ const CESIUM_TIMELINE_KEY = "_nextspace_timeline";
3007
+ const CESIUM_TIMELINE_LIVE_KEY = "_nextspace_timeline_live";
3008
+ const CESIUM_TIMELINE_LIVE_PADDING_KEY = "_nextspace_timeline_live_padding";
3009
+ const CESIUM_TIMELINE_INTERVAL_KEY = "_nextspace_timeline_interval";
3010
+ const CESIUM_MODEL_SPACE_KEY = "_nextspace_model_space";
3011
+ const DEFAULT_LIVE_PADDING_SECONDS = 30 * 60;
3012
+ var ViewUtils;
3013
+ (function (ViewUtils) {
3014
+ function GatherLegacyMapTiles(params) {
3015
+ const viewer = params.viewer;
3016
+ const collection = viewer.imageryLayers;
3017
+ const tiles = [];
3018
+ for (let i = 0; i < collection.length; i++) {
3019
+ const layer = collection.get(i);
3020
+ if (layer._bName) {
3021
+ tiles.push({
3022
+ alpha: layer.alpha,
3023
+ brightness: layer.brightness,
3024
+ contrast: layer.contrast,
3025
+ hue: layer.hue,
3026
+ saturation: layer.saturation,
3027
+ gamma: layer.gamma,
3028
+ title: layer._bName,
3059
3029
  });
3060
- cEntity._renderGroup = GetRenderGroupId(relation);
3061
- rendered[GetRenderGroupId(relation)] = cEntity;
3062
- }
3063
- catch (e) {
3064
- console.error(e);
3065
3030
  }
3066
3031
  }
3067
- return rendered;
3032
+ return {
3033
+ imagery: tiles.reverse()
3034
+ };
3068
3035
  }
3069
- RelationRenderEngine.Render = Render;
3070
- let Parabola;
3071
- (function (Parabola) {
3072
- async function Render(params) {
3073
- var _a;
3074
- const style = (_a = params.style) === null || _a === void 0 ? void 0 : _a.Settings;
3075
- const entity = params.dataEntity;
3076
- const bColor = (style === null || style === void 0 ? void 0 : style.lineColor) ? Calculator.GetColor(style === null || style === void 0 ? void 0 : style.lineColor, entity, []) : null;
3077
- const cColor = bColor ? colorToCColor(bColor) : Color.WHITE;
3078
- let width = EnsureNumber((style === null || style === void 0 ? void 0 : style.lineWidth) ? Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.lineWidth, entity, []) : 4, 4);
3079
- if (width < 1) {
3080
- width = 1;
3081
- }
3082
- const duration = EnsureNumber((style === null || style === void 0 ? void 0 : style.duration) ? Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.duration, entity, []) : 2, 2);
3083
- const hDistanceRatio = EnsureNumber((style === null || style === void 0 ? void 0 : style.heightDistanceRatio) ? Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.heightDistanceRatio, entity, []) : 0.25, 0.25);
3084
- let fromPos = null;
3085
- let toPos = null;
3086
- let updatingPosses = false;
3087
- const updatePosses = async () => {
3088
- if (updatingPosses) {
3089
- return;
3090
- }
3091
- updatingPosses = true;
3092
- try {
3093
- const fromData = await EntityUtils.GetLocation({
3094
- samples: [{
3095
- entity: params.fromEntity,
3096
- entityId: params.fromEntity.Bruce.ID,
3097
- heightRef: HeightReference.CLAMP_TO_GROUND,
3098
- returnHeightRef: HeightReference.NONE
3099
- }],
3100
- viewer: params.viewer,
3101
- visualRegister: params.visualRegister,
3102
- api: params.apiGetter.getApi()
3103
- });
3104
- fromPos = fromData.pos3d;
3105
- const toData = await EntityUtils.GetLocation({
3106
- samples: [{
3107
- entity: params.toEntity,
3108
- entityId: params.toEntity.Bruce.ID,
3109
- heightRef: HeightReference.CLAMP_TO_GROUND,
3110
- returnHeightRef: HeightReference.NONE
3111
- }],
3112
- viewer: params.viewer,
3113
- visualRegister: params.visualRegister,
3114
- api: params.apiGetter.getApi()
3036
+ ViewUtils.GatherLegacyMapTiles = GatherLegacyMapTiles;
3037
+ function GatherLegacyTerrainTile(params) {
3038
+ const viewer = params.viewer;
3039
+ const enabled = viewer.terrainProvider;
3040
+ if (enabled === null || enabled === void 0 ? void 0 : enabled._bName) {
3041
+ return {
3042
+ terrain: enabled._bName
3043
+ };
3044
+ }
3045
+ return {
3046
+ terrain: "flatterrain"
3047
+ };
3048
+ }
3049
+ ViewUtils.GatherLegacyTerrainTile = GatherLegacyTerrainTile;
3050
+ function GatherMapTiles(params) {
3051
+ const viewer = params.viewer;
3052
+ const imagery = viewer.imageryLayers;
3053
+ const tiles = [];
3054
+ for (let i = 0; i < imagery.length; i++) {
3055
+ const provider = imagery.get(i);
3056
+ if (provider._bMeta) {
3057
+ const idCombo = provider._bMeta.accountId + provider._bMeta.tilesetId;
3058
+ if (!tiles.find(x => x.accountId + x.tilesetId === idCombo)) {
3059
+ tiles.push({
3060
+ accountId: provider._bMeta.accountId,
3061
+ tilesetId: provider._bMeta.tilesetId,
3062
+ alpha: provider.alpha,
3063
+ brightness: provider.brightness,
3064
+ contrast: provider.contrast,
3065
+ hue: provider.hue,
3066
+ saturation: provider.saturation,
3067
+ gamma: provider.gamma
3115
3068
  });
3116
- toPos = toData.pos3d;
3117
- }
3118
- catch (e) {
3119
- console.error(e);
3120
3069
  }
3121
- updatingPosses = false;
3122
- };
3123
- updatePosses();
3124
- const parabola = new CesiumParabola({
3125
- viewer: params.viewer,
3126
- pos1: () => fromPos,
3127
- pos2: () => toPos,
3128
- color: cColor.toCssColorString(),
3129
- width: width,
3130
- duration: duration,
3131
- heightDistanceRatio: hDistanceRatio
3132
- });
3133
- parabola.Hidden = true;
3134
- const cEntities = parabola.Animate();
3135
- const cEntity = cEntities.parabola;
3136
- cEntity._siblingGraphics = [];
3137
- for (let i = 0; i < cEntities.siblings.length; i++) {
3138
- const sibling = cEntities.siblings[i];
3139
- cEntity._siblingGraphics.push(sibling);
3140
3070
  }
3141
- let updateInterval = setInterval(() => {
3142
- var _a;
3143
- if (!((_a = params.viewer) === null || _a === void 0 ? void 0 : _a.scene) ||
3144
- params.viewer.isDestroyed() ||
3145
- (!parabola || parabola.Disposed)) {
3146
- clearInterval(updateInterval);
3147
- parabola.Dispose();
3148
- return;
3149
- }
3150
- if (parabola) {
3151
- const visible = cEntity && cEntity.show != false && params.viewer.entities.contains(cEntity);
3152
- parabola.Hidden = !visible;
3153
- }
3154
- updatePosses();
3155
- params.viewer.scene.requestRender();
3156
- }, 1000);
3157
- let disposed = false;
3158
- cEntity._dispose = () => {
3159
- if (disposed) {
3160
- return;
3161
- }
3162
- disposed = true;
3163
- clearInterval(updateInterval);
3164
- if (parabola) {
3165
- parabola.Dispose();
3071
+ }
3072
+ return {
3073
+ imagery: tiles
3074
+ };
3075
+ }
3076
+ ViewUtils.GatherMapTiles = GatherMapTiles;
3077
+ function GatherTerrainTile(params) {
3078
+ const viewer = params.viewer;
3079
+ const provider = viewer.terrainProvider;
3080
+ if (provider === null || provider === void 0 ? void 0 : provider._bMeta) {
3081
+ return {
3082
+ terrain: {
3083
+ accountId: provider._bMeta.accountId,
3084
+ tilesetId: provider._bMeta.tilesetId,
3166
3085
  }
3167
3086
  };
3168
- return cEntity;
3169
3087
  }
3170
- Parabola.Render = Render;
3171
- })(Parabola = RelationRenderEngine.Parabola || (RelationRenderEngine.Parabola = {}));
3172
- })(RelationRenderEngine || (RelationRenderEngine = {}));
3173
-
3174
- /**
3175
- * Returns cesium property's value.
3176
- * This will check if it's one that changes over time, or just a fixed value.
3177
- * Eg: const pos3d = getValue<Cesium.Cartesian3>(cViewer, cEntity.point.position);
3178
- * @param viewer
3179
- * @param obj
3180
- */
3181
- function getValue(viewer, obj) {
3182
- if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
3183
- let date = viewer.scene.lastRenderTime;
3184
- if (!date) {
3185
- date = viewer.clock.currentTime;
3088
+ else if (provider instanceof EllipsoidTerrainProvider) {
3089
+ return {
3090
+ terrain: {
3091
+ tilesetId: ProjectViewTile.EDefaultTerrain.FlatTerrain,
3092
+ accountId: null
3093
+ }
3094
+ };
3186
3095
  }
3187
- return obj.getValue(date);
3096
+ return null;
3097
+ }
3098
+ ViewUtils.GatherTerrainTile = GatherTerrainTile;
3099
+ function SetTerrainWireframeStatus(params) {
3100
+ if (!params.viewer[CESIUM_INSPECTOR_KEY]) {
3101
+ const InspectorClass = CesiumInspector;
3102
+ if (InspectorClass) {
3103
+ const inspector = new InspectorClass(document.createElement("div"), params.viewer.scene);
3104
+ inspector.container.style.display = "none";
3105
+ params.viewer[CESIUM_INSPECTOR_KEY] = inspector;
3106
+ params.viewer.scene.requestRender();
3107
+ }
3108
+ }
3109
+ if (params.viewer[CESIUM_INSPECTOR_KEY]) {
3110
+ params.viewer[CESIUM_INSPECTOR_KEY].viewModel.wireframe = params.status;
3111
+ }
3112
+ }
3113
+ ViewUtils.SetTerrainWireframeStatus = SetTerrainWireframeStatus;
3114
+ function GetTerrainWireframeStatus(params) {
3115
+ var _a, _b;
3116
+ if (!params.viewer[CESIUM_INSPECTOR_KEY]) {
3117
+ return false;
3118
+ }
3119
+ return (_b = (_a = params.viewer[CESIUM_INSPECTOR_KEY]) === null || _a === void 0 ? void 0 : _a.viewModel) === null || _b === void 0 ? void 0 : _b.wireframe;
3120
+ }
3121
+ ViewUtils.GetTerrainWireframeStatus = GetTerrainWireframeStatus;
3122
+ /**
3123
+ * Changes between perspective and orthographic view.
3124
+ * When Cesium stops being bad at picking positions in 2d mode we'll use the flat earth mode instead.
3125
+ * @param params
3126
+ */
3127
+ function Set2dStatus(params) {
3128
+ const { viewer, status: is2d, moveCamera } = params;
3129
+ const curLens2d = viewer.camera.frustum instanceof OrthographicFrustum;
3130
+ if (curLens2d && !is2d) {
3131
+ OnNextCRender(viewer, () => {
3132
+ viewer.camera.switchToPerspectiveFrustum();
3133
+ viewer.scene.screenSpaceCameraController.enableTilt = true;
3134
+ });
3135
+ viewer.scene.requestRender();
3136
+ }
3137
+ else if (!curLens2d && is2d) {
3138
+ OnNextCRender(viewer, () => {
3139
+ viewer.camera.switchToOrthographicFrustum();
3140
+ viewer.scene.screenSpaceCameraController.enableTilt = false;
3141
+ });
3142
+ if (moveCamera != false) {
3143
+ try {
3144
+ // Face camera downwards to make it look 2d.
3145
+ // We want to try make it look at the center-point of the current view.
3146
+ // If center cannot be calculated then we'll simply raise the camera and face it downwards.
3147
+ const scene = viewer.scene;
3148
+ const windowPosition = new Cartesian2(scene.canvas.clientWidth / 2, scene.canvas.clientHeight / 2);
3149
+ const ray = viewer.camera.getPickRay(windowPosition);
3150
+ const intersection = scene.globe.pick(ray, scene);
3151
+ let center;
3152
+ if (defined(intersection)) {
3153
+ center = Cartographic.fromCartesian(intersection);
3154
+ }
3155
+ // Use current camera position if we can't calculate the center.
3156
+ else {
3157
+ center = Cartographic.fromCartesian(viewer.camera.position);
3158
+ center.height = 0;
3159
+ }
3160
+ center.height = viewer.camera.positionCartographic.height + 100;
3161
+ viewer.camera.setView({
3162
+ destination: Cartographic.toCartesian(center),
3163
+ orientation: {
3164
+ heading: 0.0,
3165
+ pitch: Math$1.toRadians(-90.0),
3166
+ roll: 0.0
3167
+ }
3168
+ });
3169
+ }
3170
+ catch (e) {
3171
+ console.error(e);
3172
+ }
3173
+ }
3174
+ viewer.scene.requestRender();
3175
+ }
3176
+ }
3177
+ ViewUtils.Set2dStatus = Set2dStatus;
3178
+ function Get2dStatus(params) {
3179
+ const { viewer } = params;
3180
+ return viewer.camera.frustum instanceof OrthographicFrustum;
3181
+ }
3182
+ ViewUtils.Get2dStatus = Get2dStatus;
3183
+ function SetLockedCameraStatus(params) {
3184
+ const { viewer, status } = params;
3185
+ const scene = viewer === null || viewer === void 0 ? void 0 : viewer.scene;
3186
+ if (!scene) {
3187
+ return;
3188
+ }
3189
+ if (status) {
3190
+ scene.screenSpaceCameraController.enableInputs = false;
3191
+ scene.screenSpaceCameraController.enableTranslate = false;
3192
+ scene.screenSpaceCameraController.enableZoom = false;
3193
+ scene.screenSpaceCameraController.enableRotate = false;
3194
+ scene.screenSpaceCameraController.enableTilt = false;
3195
+ }
3196
+ else {
3197
+ scene.screenSpaceCameraController.enableInputs = true;
3198
+ scene.screenSpaceCameraController.enableTranslate = true;
3199
+ scene.screenSpaceCameraController.enableZoom = true;
3200
+ scene.screenSpaceCameraController.enableRotate = true;
3201
+ if (!ViewUtils.Get2dStatus({ viewer })) {
3202
+ scene.screenSpaceCameraController.enableTilt = true;
3203
+ }
3204
+ }
3205
+ viewer.scene.requestRender();
3206
+ }
3207
+ ViewUtils.SetLockedCameraStatus = SetLockedCameraStatus;
3208
+ function GetLockedCameraStatus(params) {
3209
+ var _a;
3210
+ const scene = (_a = params.viewer) === null || _a === void 0 ? void 0 : _a.scene;
3211
+ if (!scene) {
3212
+ return false;
3213
+ }
3214
+ return !scene.screenSpaceCameraController.enableTranslate;
3215
+ }
3216
+ ViewUtils.GetLockedCameraStatus = GetLockedCameraStatus;
3217
+ /**
3218
+ * Returns the current camera time and related settings.
3219
+ * @param params
3220
+ * @returns
3221
+ */
3222
+ function GetTimeDetails(params) {
3223
+ const { viewer } = params;
3224
+ const clock = viewer.clock;
3225
+ return {
3226
+ animationSpeed: clock.multiplier,
3227
+ isAnimating: clock.shouldAnimate,
3228
+ startTime: clock.startTime,
3229
+ startTimeIso: clock.startTime.toString(),
3230
+ currentTime: clock.currentTime,
3231
+ currentTimeIso: clock.currentTime.toString(),
3232
+ stopTime: clock.stopTime,
3233
+ stopTimeIso: clock.stopTime.toString(),
3234
+ areCesiumValues: clock[CESIUM_TIMELINE_KEY] != true,
3235
+ isLive: clock[CESIUM_TIMELINE_LIVE_KEY] == true,
3236
+ livePaddingSeconds: clock[CESIUM_TIMELINE_LIVE_PADDING_KEY] || DEFAULT_LIVE_PADDING_SECONDS
3237
+ };
3238
+ }
3239
+ ViewUtils.GetTimeDetails = GetTimeDetails;
3240
+ /**
3241
+ * Sets the Cesium clock values.
3242
+ * If a value is not provided, then 'areCesiumValues' checked to see if the values are Cesium values.
3243
+ * If they're currently Cesium set values then our defaults are used.
3244
+ * @param params
3245
+ */
3246
+ function SetTimeDetails(params) {
3247
+ let { viewer, animationSpeed, isAnimating, startTime, currentTime, stopTime, startTimeIso, stopTimeIso, currentTimeIso, isLive, livePaddingSeconds } = params;
3248
+ const clock = viewer.clock;
3249
+ if (startTime) {
3250
+ clock.startTime = startTime;
3251
+ }
3252
+ else if (startTimeIso) {
3253
+ const startDate = JulianDate.fromIso8601(startTimeIso);
3254
+ if (startDate) {
3255
+ clock.startTime = startDate;
3256
+ }
3257
+ }
3258
+ if (currentTime) {
3259
+ clock.currentTime = currentTime;
3260
+ }
3261
+ else if (currentTimeIso) {
3262
+ const currentDate = JulianDate.fromIso8601(currentTimeIso);
3263
+ if (currentDate) {
3264
+ clock.currentTime = currentDate;
3265
+ }
3266
+ }
3267
+ if (stopTime) {
3268
+ clock.stopTime = stopTime;
3269
+ }
3270
+ else if (stopTimeIso) {
3271
+ const stopDate = JulianDate.fromIso8601(stopTimeIso);
3272
+ if (stopDate) {
3273
+ clock.stopTime = stopDate;
3274
+ }
3275
+ }
3276
+ clock.clockRange = ClockRange.LOOP_STOP;
3277
+ const areCesiumValues = clock[CESIUM_TIMELINE_KEY] != true;
3278
+ if (areCesiumValues) {
3279
+ if (isNaN(animationSpeed) || animationSpeed == null) {
3280
+ animationSpeed = 1;
3281
+ }
3282
+ if (isAnimating == null) {
3283
+ isAnimating = false;
3284
+ }
3285
+ if (isLive == null) {
3286
+ isLive = false;
3287
+ }
3288
+ if (livePaddingSeconds == null) {
3289
+ livePaddingSeconds = DEFAULT_LIVE_PADDING_SECONDS;
3290
+ }
3291
+ }
3292
+ if (!isNaN(animationSpeed) && animationSpeed != null) {
3293
+ clock.multiplier = animationSpeed;
3294
+ }
3295
+ if (isAnimating != null) {
3296
+ clock.shouldAnimate = isAnimating;
3297
+ }
3298
+ viewer.scene.requestRender();
3299
+ clock[CESIUM_TIMELINE_KEY] = true;
3300
+ if (livePaddingSeconds != null) {
3301
+ clock[CESIUM_TIMELINE_LIVE_PADDING_KEY] = livePaddingSeconds || DEFAULT_LIVE_PADDING_SECONDS;
3302
+ }
3303
+ if (isLive != null) {
3304
+ clock[CESIUM_TIMELINE_LIVE_KEY] = params.isLive == true;
3305
+ }
3306
+ if (clock[CESIUM_TIMELINE_LIVE_KEY]) {
3307
+ startLive(viewer);
3308
+ }
3309
+ else {
3310
+ stopLive(viewer);
3311
+ }
3312
+ }
3313
+ ViewUtils.SetTimeDetails = SetTimeDetails;
3314
+ function startLive(viewer) {
3315
+ const doUpdate = () => {
3316
+ if (!viewer || viewer.isDestroyed() || !viewer.scene) {
3317
+ stopLive(viewer);
3318
+ return;
3319
+ }
3320
+ // Get the current settings.
3321
+ const tDetails = GetTimeDetails({ viewer });
3322
+ const clock = viewer.clock;
3323
+ if (clock) {
3324
+ clock.shouldAnimate = true;
3325
+ clock.multiplier = 1;
3326
+ clock.currentTime = JulianDate.now();
3327
+ clock.startTime = JulianDate.addSeconds(clock.currentTime, -tDetails.livePaddingSeconds, new JulianDate());
3328
+ clock.stopTime = JulianDate.addSeconds(clock.currentTime, tDetails.livePaddingSeconds, new JulianDate());
3329
+ clock.clockRange = ClockRange.UNBOUNDED;
3330
+ }
3331
+ };
3332
+ if (viewer[CESIUM_TIMELINE_INTERVAL_KEY]) {
3333
+ doUpdate();
3334
+ return;
3335
+ }
3336
+ // We'll start an interval that occasionally updates the Cesium clock to stay in the desired settings.
3337
+ // Since it moves live (1 second per second), we don't have to worry about the ranges being out of date quickly.
3338
+ viewer[CESIUM_TIMELINE_INTERVAL_KEY] = setInterval(() => {
3339
+ doUpdate();
3340
+ }, 800);
3341
+ viewer[CESIUM_TIMELINE_LIVE_KEY] = true;
3342
+ // Initial update.
3343
+ doUpdate();
3344
+ }
3345
+ function stopLive(viewer) {
3346
+ if (!viewer) {
3347
+ return;
3348
+ }
3349
+ let interval = viewer[CESIUM_TIMELINE_INTERVAL_KEY];
3350
+ if (interval) {
3351
+ clearInterval(interval);
3352
+ viewer[CESIUM_TIMELINE_INTERVAL_KEY] = null;
3353
+ }
3354
+ viewer[CESIUM_TIMELINE_LIVE_KEY] = false;
3355
+ }
3356
+ function SetGlobeDetails(params) {
3357
+ let { viewer, hidden, baseColor } = params;
3358
+ const scene = viewer === null || viewer === void 0 ? void 0 : viewer.scene;
3359
+ if (!(scene === null || scene === void 0 ? void 0 : scene.globe)) {
3360
+ return;
3361
+ }
3362
+ if (hidden == null) {
3363
+ hidden = !scene.globe.show;
3364
+ }
3365
+ else {
3366
+ scene.globe.show = !hidden;
3367
+ }
3368
+ if (baseColor == null) {
3369
+ baseColor = scene.globe.baseColor;
3370
+ }
3371
+ // When globe is off, we'll also hide the stars/moon.
3372
+ // We also grab the globe color and apply it to the sky.
3373
+ if (hidden && GetModelSpace(viewer)) {
3374
+ scene.skyBox.show = false;
3375
+ scene.skyAtmosphere.show = false;
3376
+ scene.sun.show = false;
3377
+ scene.moon.show = false;
3378
+ scene.backgroundColor = baseColor.clone();
3379
+ }
3380
+ else {
3381
+ scene.skyBox.show = true;
3382
+ scene.skyAtmosphere.show = true;
3383
+ scene.sun.show = true;
3384
+ scene.moon.show = true;
3385
+ scene.backgroundColor = Color.BLACK;
3386
+ }
3387
+ scene.globe.baseColor = baseColor;
3388
+ }
3389
+ ViewUtils.SetGlobeDetails = SetGlobeDetails;
3390
+ function SetModelSpace(viewer, modelSpace) {
3391
+ if (!viewer) {
3392
+ return;
3393
+ }
3394
+ if (viewer[CESIUM_MODEL_SPACE_KEY] === modelSpace) {
3395
+ return;
3396
+ }
3397
+ viewer[CESIUM_MODEL_SPACE_KEY] = modelSpace;
3398
+ // Reload globe since we display it differently between the two modes.
3399
+ SetGlobeDetails({ viewer });
3400
+ }
3401
+ ViewUtils.SetModelSpace = SetModelSpace;
3402
+ function GetModelSpace(viewer) {
3403
+ if (!viewer) {
3404
+ return false;
3405
+ }
3406
+ return Boolean(viewer[CESIUM_MODEL_SPACE_KEY]);
3407
+ }
3408
+ ViewUtils.GetModelSpace = GetModelSpace;
3409
+ })(ViewUtils || (ViewUtils = {}));
3410
+
3411
+ /**
3412
+ * Returns cesium property's value.
3413
+ * This will check if it's one that changes over time, or just a fixed value.
3414
+ * Eg: const pos3d = getValue<Cesium.Cartesian3>(cViewer, cEntity.point.position);
3415
+ * @param viewer
3416
+ * @param obj
3417
+ */
3418
+ function getValue(viewer, obj) {
3419
+ if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
3420
+ let date = viewer.scene.lastRenderTime;
3421
+ if (!date) {
3422
+ date = viewer.clock.currentTime;
3423
+ }
3424
+ return obj.getValue(date);
3188
3425
  }
3189
3426
  return obj;
3190
3427
  }
@@ -3872,509 +4109,594 @@ var EntityLabel;
3872
4109
  EntityLabel.GetLabel = GetLabel;
3873
4110
  })(EntityLabel || (EntityLabel = {}));
3874
4111
 
3875
- function OnNextCRender(viewer, callback) {
3876
- const removal = viewer.scene.postRender.addEventListener(() => {
3877
- removal();
3878
- callback();
3879
- });
3880
- }
3881
- function GetCValue(viewer, obj) {
3882
- if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
3883
- let date = viewer.scene.lastRenderTime;
3884
- if (!date) {
3885
- date = viewer.clock.currentTime;
3886
- }
3887
- return obj.getValue(date);
3888
- }
3889
- return obj;
3890
- }
3891
- function ColorToCColor(color) {
3892
- return new Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
3893
- }
3894
4112
  /**
3895
- * Removes duplicate points in a row and returns a new array.
3896
- * Passed array is not mutated.
3897
- * @param posses
4113
+ * Utility for rendering parabolas between two points on the map.
3898
4114
  */
3899
- function CullDuplicateCPosses(posses) {
3900
- const newPosses = [];
3901
- let lastPos = null;
3902
- for (let i = 0; i < posses.length; i++) {
3903
- const pos = posses[i];
3904
- // Avoiding 'Cesium.Cartesian3.equals' because passed data might be just a json blob in certain cases.
3905
- if (pos && (!lastPos || (pos.x != lastPos.x || pos.y != lastPos.y || pos.z != lastPos.z))) {
3906
- newPosses.push(pos);
3907
- lastPos = pos;
3908
- }
4115
+ class CesiumParabola {
4116
+ get Disposed() {
4117
+ return this.disposed;
3909
4118
  }
3910
- return newPosses;
3911
- }
3912
- /**
3913
- * Returns if the given positions are equal.
3914
- * @param a
3915
- * @param b
3916
- */
3917
- function CompareCPosses(a, b) {
3918
- // Same reference.
3919
- if (a == b) {
3920
- return true;
4119
+ set Hidden(value) {
4120
+ this.hidden = value;
3921
4121
  }
3922
- // Different lengths or one is null.
3923
- if ((!a || !b) || (a.length != b.length)) {
3924
- return false;
4122
+ get curPos1() {
4123
+ return this.pos1 instanceof Function ? this.pos1() : this.pos1;
3925
4124
  }
3926
- for (let i = 0; i < a.length; i++) {
3927
- const posA = a[i];
3928
- const posB = b[i];
3929
- // Null detected.
3930
- if (!posA || !posB) {
3931
- return false;
4125
+ get curPos2() {
4126
+ return this.pos2 instanceof Function ? this.pos2() : this.pos2;
4127
+ }
4128
+ constructor(params) {
4129
+ this.disposed = false;
4130
+ this.color = "white";
4131
+ this.width = 2;
4132
+ this.duration = 10;
4133
+ this.heightDistanceRatio = 0.25;
4134
+ this.curPoints = [];
4135
+ this.animateInterval = null;
4136
+ this.retryTimeout = null;
4137
+ this.hidden = false;
4138
+ this.viewer = params.viewer;
4139
+ this.pos1 = params.pos1;
4140
+ this.pos2 = params.pos2;
4141
+ if (params.color) {
4142
+ this.color = params.color;
3932
4143
  }
3933
- // Position values don't match.
3934
- if (!Cartes.IsEqualCartes3(posA, posB)) {
3935
- return false;
4144
+ if (!isNaN(params.width)) {
4145
+ this.width = params.width;
3936
4146
  }
3937
- }
3938
- return true;
3939
- }
3940
- /**
3941
- * Returns if the given polygon hierarchies are equal.
3942
- * @param a
3943
- * @param b
3944
- */
3945
- function CompareCPolygonHierarchies(a, b) {
3946
- // Same reference.
3947
- if (a == b) {
3948
- return true;
3949
- }
3950
- // Different lengths or one is null.
3951
- if ((!a || !b) || (a.positions.length != b.positions.length)) {
3952
- return false;
3953
- }
3954
- // Positions don't match.
3955
- if (!CompareCPosses(a.positions, b.positions)) {
3956
- return false;
3957
- }
3958
- const holes = a.holes;
3959
- const bHoles = b.holes;
3960
- // Number of holes don't match.
3961
- if (holes.length != bHoles.length) {
3962
- return false;
3963
- }
3964
- for (let i = 0; i < holes.length; i++) {
3965
- // Hole positions don't match.
3966
- if (!CompareCPosses(holes[i].positions, bHoles[i].positions)) {
3967
- return false;
4147
+ if (!isNaN(params.duration)) {
4148
+ this.duration = params.duration;
4149
+ }
4150
+ if (!isNaN(params.heightDistanceRatio)) {
4151
+ this.heightDistanceRatio = params.heightDistanceRatio;
3968
4152
  }
4153
+ this.prepareEntities();
3969
4154
  }
3970
- return true;
3971
- }
3972
-
3973
- const CESIUM_INSPECTOR_KEY = "_nextspace_inspector";
3974
- const CESIUM_TIMELINE_KEY = "_nextspace_timeline";
3975
- const CESIUM_TIMELINE_LIVE_KEY = "_nextspace_timeline_live";
3976
- const CESIUM_TIMELINE_LIVE_PADDING_KEY = "_nextspace_timeline_live_padding";
3977
- const CESIUM_TIMELINE_INTERVAL_KEY = "_nextspace_timeline_interval";
3978
- const CESIUM_MODEL_SPACE_KEY = "_nextspace_model_space";
3979
- const DEFAULT_LIVE_PADDING_SECONDS = 30 * 60;
3980
- var ViewUtils;
3981
- (function (ViewUtils) {
3982
- function GatherLegacyMapTiles(params) {
3983
- const viewer = params.viewer;
3984
- const collection = viewer.imageryLayers;
3985
- const tiles = [];
3986
- for (let i = 0; i < collection.length; i++) {
3987
- const layer = collection.get(i);
3988
- if (layer._bName) {
3989
- tiles.push({
3990
- alpha: layer.alpha,
3991
- brightness: layer.brightness,
3992
- contrast: layer.contrast,
3993
- hue: layer.hue,
3994
- saturation: layer.saturation,
3995
- gamma: layer.gamma,
3996
- title: layer._bName,
3997
- });
4155
+ prepareEntities() {
4156
+ const parabola = new Entity({
4157
+ polyline: {
4158
+ positions: new CallbackProperty(() => {
4159
+ return this.curPoints;
4160
+ }, false),
4161
+ width: this.width,
4162
+ material: Color.fromCssColorString(this.color),
4163
+ show: new CallbackProperty(() => {
4164
+ return !this.hidden;
4165
+ }, false)
3998
4166
  }
3999
- }
4000
- return {
4001
- imagery: tiles.reverse()
4002
- };
4167
+ });
4168
+ const p1Entity = new Entity({
4169
+ position: new CallbackProperty(() => {
4170
+ return this.curPoints.length ? this.curPoints[0] : new Cartesian3();
4171
+ }, false),
4172
+ point: {
4173
+ heightReference: HeightReference.NONE,
4174
+ pixelSize: this.width * 1.3,
4175
+ color: Color.fromCssColorString(this.color),
4176
+ outlineColor: Color.WHITE,
4177
+ outlineWidth: 2,
4178
+ show: new CallbackProperty(() => {
4179
+ return !this.hidden;
4180
+ }, false)
4181
+ }
4182
+ });
4183
+ const p2Entity = new Entity({
4184
+ position: new CallbackProperty(() => {
4185
+ return this.curPoints.length ? this.curPoints[this.curPoints.length - 1] : new Cartesian3();
4186
+ }, false),
4187
+ point: {
4188
+ heightReference: HeightReference.NONE,
4189
+ pixelSize: this.width * 1.8,
4190
+ color: Color.fromCssColorString(this.color),
4191
+ outlineColor: Color.WHITE,
4192
+ outlineWidth: 2,
4193
+ show: new CallbackProperty(() => {
4194
+ return !this.hidden;
4195
+ }, false)
4196
+ }
4197
+ });
4198
+ p1Entity.parent = parabola;
4199
+ p2Entity.parent = parabola;
4200
+ const siblings = [p1Entity, p2Entity];
4201
+ this.parabola = parabola;
4202
+ this.siblings = siblings;
4203
+ // The parabola is hidden while this entity is not added.
4204
+ // If we avoid adding it now, then the parent can control if the parabola is visible at first or not.
4205
+ // this.viewer.entities.add(this.parabola);
4206
+ this.viewer.entities.add(p1Entity);
4207
+ this.viewer.entities.add(p2Entity);
4003
4208
  }
4004
- ViewUtils.GatherLegacyMapTiles = GatherLegacyMapTiles;
4005
- function GatherLegacyTerrainTile(params) {
4006
- const viewer = params.viewer;
4007
- const enabled = viewer.terrainProvider;
4008
- if (enabled === null || enabled === void 0 ? void 0 : enabled._bName) {
4009
- return {
4010
- terrain: enabled._bName
4011
- };
4209
+ Animate() {
4210
+ if (this.disposed) {
4211
+ return null;
4012
4212
  }
4013
- return {
4014
- terrain: "flatterrain"
4015
- };
4016
- }
4017
- ViewUtils.GatherLegacyTerrainTile = GatherLegacyTerrainTile;
4018
- function GatherMapTiles(params) {
4019
- const viewer = params.viewer;
4020
- const imagery = viewer.imageryLayers;
4021
- const tiles = [];
4022
- for (let i = 0; i < imagery.length; i++) {
4023
- const provider = imagery.get(i);
4024
- if (provider._bMeta) {
4025
- const idCombo = provider._bMeta.accountId + provider._bMeta.tilesetId;
4026
- if (!tiles.find(x => x.accountId + x.tilesetId === idCombo)) {
4027
- tiles.push({
4028
- accountId: provider._bMeta.accountId,
4029
- tilesetId: provider._bMeta.tilesetId,
4030
- alpha: provider.alpha,
4031
- brightness: provider.brightness,
4032
- contrast: provider.contrast,
4033
- hue: provider.hue,
4034
- saturation: provider.saturation,
4035
- gamma: provider.gamma
4036
- });
4037
- }
4038
- }
4213
+ let retry = false;
4214
+ if (!this.curPos1 || !this.curPos2 || !Cartes.ValidateCartes3(this.curPos1) || !Cartes.ValidateCartes3(this.curPos2)) {
4215
+ retry = true;
4039
4216
  }
4040
- return {
4041
- imagery: tiles
4042
- };
4043
- }
4044
- ViewUtils.GatherMapTiles = GatherMapTiles;
4045
- function GatherTerrainTile(params) {
4046
- const viewer = params.viewer;
4047
- const provider = viewer.terrainProvider;
4048
- if (provider === null || provider === void 0 ? void 0 : provider._bMeta) {
4049
- return {
4050
- terrain: {
4051
- accountId: provider._bMeta.accountId,
4052
- tilesetId: provider._bMeta.tilesetId,
4053
- }
4054
- };
4217
+ let TOTAL_LENGTH = retry ? 0 : Cartesian3.distance(this.curPos1, this.curPos2);
4218
+ if (TOTAL_LENGTH <= 0) {
4219
+ retry = true;
4055
4220
  }
4056
- else if (provider instanceof EllipsoidTerrainProvider) {
4221
+ if (retry) {
4222
+ this.retryTimeout = setTimeout(() => {
4223
+ this.Animate();
4224
+ }, 2000);
4057
4225
  return {
4058
- terrain: {
4059
- tilesetId: ProjectViewTile.EDefaultTerrain.FlatTerrain,
4060
- accountId: null
4061
- }
4226
+ parabola: this.parabola,
4227
+ siblings: this.siblings
4062
4228
  };
4063
4229
  }
4064
- return null;
4065
- }
4066
- ViewUtils.GatherTerrainTile = GatherTerrainTile;
4067
- function SetTerrainWireframeStatus(params) {
4068
- if (!params.viewer[CESIUM_INSPECTOR_KEY]) {
4069
- const InspectorClass = CesiumInspector;
4070
- if (InspectorClass) {
4071
- const inspector = new InspectorClass(document.createElement("div"), params.viewer.scene);
4072
- inspector.container.style.display = "none";
4073
- params.viewer[CESIUM_INSPECTOR_KEY] = inspector;
4074
- params.viewer.scene.requestRender();
4230
+ const RATE_PER_SECOND = 1000 / 40;
4231
+ const SEC_DURATION = this.duration;
4232
+ const HEIGHT_DISTANCE_RATIO = this.heightDistanceRatio;
4233
+ let TOTAL_POINTS = null;
4234
+ let POINT_LENGTH = null;
4235
+ let TICK_LENGTH_INC = null;
4236
+ // Updates TOTAL_POINTS, POINT_LENGTH, and TICK_LENGTH_INC based on current TOTAL_LENGTH and camera position.
4237
+ // We want less points the further away the camera is.
4238
+ const updateParams = () => {
4239
+ var _a, _b;
4240
+ // TODO: Do distance to parabola line instead.
4241
+ const MIN_POINTS = 30;
4242
+ let totalPoints = 80;
4243
+ let cameraHeight = (_b = (_a = this.viewer.camera) === null || _a === void 0 ? void 0 : _a.positionCartographic) === null || _b === void 0 ? void 0 : _b.height;
4244
+ if (isNaN(cameraHeight) || cameraHeight >= 100000) {
4245
+ totalPoints = MIN_POINTS;
4075
4246
  }
4076
- }
4077
- if (params.viewer[CESIUM_INSPECTOR_KEY]) {
4078
- params.viewer[CESIUM_INSPECTOR_KEY].viewModel.wireframe = params.status;
4079
- }
4080
- }
4081
- ViewUtils.SetTerrainWireframeStatus = SetTerrainWireframeStatus;
4082
- function GetTerrainWireframeStatus(params) {
4083
- var _a, _b;
4084
- if (!params.viewer[CESIUM_INSPECTOR_KEY]) {
4085
- return false;
4086
- }
4087
- return (_b = (_a = params.viewer[CESIUM_INSPECTOR_KEY]) === null || _a === void 0 ? void 0 : _a.viewModel) === null || _b === void 0 ? void 0 : _b.wireframe;
4088
- }
4089
- ViewUtils.GetTerrainWireframeStatus = GetTerrainWireframeStatus;
4090
- /**
4091
- * Changes between perspective and orthographic view.
4092
- * When Cesium stops being bad at picking positions in 2d mode we'll use the flat earth mode instead.
4093
- * @param params
4094
- */
4095
- function Set2dStatus(params) {
4096
- const { viewer, status: is2d, moveCamera } = params;
4097
- const curLens2d = viewer.camera.frustum instanceof OrthographicFrustum;
4098
- if (curLens2d && !is2d) {
4099
- OnNextCRender(viewer, () => {
4100
- viewer.camera.switchToPerspectiveFrustum();
4101
- viewer.scene.screenSpaceCameraController.enableTilt = true;
4102
- });
4103
- viewer.scene.requestRender();
4104
- }
4105
- else if (!curLens2d && is2d) {
4106
- OnNextCRender(viewer, () => {
4107
- viewer.camera.switchToOrthographicFrustum();
4108
- viewer.scene.screenSpaceCameraController.enableTilt = false;
4109
- });
4110
- if (moveCamera != false) {
4111
- try {
4112
- // Face camera downwards to make it look 2d.
4113
- // We want to try make it look at the center-point of the current view.
4114
- // If center cannot be calculated then we'll simply raise the camera and face it downwards.
4115
- const scene = viewer.scene;
4116
- const windowPosition = new Cartesian2(scene.canvas.clientWidth / 2, scene.canvas.clientHeight / 2);
4117
- const ray = viewer.camera.getPickRay(windowPosition);
4118
- const intersection = scene.globe.pick(ray, scene);
4119
- let center;
4120
- if (defined(intersection)) {
4121
- center = Cartographic.fromCartesian(intersection);
4247
+ else if (cameraHeight >= 10000) {
4248
+ totalPoints = 50;
4249
+ }
4250
+ else if (cameraHeight >= 1000) {
4251
+ totalPoints = 80;
4252
+ }
4253
+ else if (cameraHeight >= 100) {
4254
+ totalPoints = 100;
4255
+ }
4256
+ TOTAL_POINTS = Math.max(MIN_POINTS, Math.min(totalPoints, TOTAL_LENGTH * 0.1));
4257
+ POINT_LENGTH = TOTAL_LENGTH / TOTAL_POINTS;
4258
+ TICK_LENGTH_INC = SEC_DURATION == 0 ? TOTAL_LENGTH : TOTAL_POINTS / (RATE_PER_SECOND * SEC_DURATION);
4259
+ };
4260
+ updateParams();
4261
+ let curPoint = 0;
4262
+ let quadraticKey = null;
4263
+ let quadratic = null;
4264
+ let quadraticPreparing = false;
4265
+ const prepareQuadratic = async () => {
4266
+ if (quadraticPreparing) {
4267
+ return;
4268
+ }
4269
+ quadraticPreparing = true;
4270
+ try {
4271
+ const p1 = this.curPos1;
4272
+ const p2 = this.curPos2;
4273
+ if (!p1 || !p2 || !Cartes.ValidateCartes3(p1) || !Cartes.ValidateCartes3(p2)) {
4274
+ return;
4275
+ }
4276
+ const height1 = Cartographic.fromCartesian(p1).height;
4277
+ const height2 = Cartographic.fromCartesian(p2).height;
4278
+ if (isNaN(height1) || isNaN(height2)) {
4279
+ return;
4280
+ }
4281
+ const totalHeight = height2 + height1;
4282
+ const curQuadraticKey = `${height1}-${height2}-${TOTAL_LENGTH}`;
4283
+ if (quadraticKey == curQuadraticKey) {
4284
+ return;
4285
+ }
4286
+ const points2d = [
4287
+ new Cartesian2(0, height1),
4288
+ new Cartesian2(TOTAL_LENGTH, height2)
4289
+ ];
4290
+ let vertexHeight = 0;
4291
+ // Flat line.
4292
+ if (HEIGHT_DISTANCE_RATIO == 0) {
4293
+ vertexHeight = totalHeight * 0.5;
4294
+ }
4295
+ else {
4296
+ const largestHeight = Math.max(height1, height2);
4297
+ vertexHeight = largestHeight + (TOTAL_LENGTH * HEIGHT_DISTANCE_RATIO);
4298
+ }
4299
+ points2d.push(new Cartesian2(TOTAL_LENGTH * 0.5, vertexHeight));
4300
+ const calcQuadratic = (points) => {
4301
+ // Swaps position of two rows in matrix.
4302
+ function swapRows(matrix, rowAIndex, rowBIndex) {
4303
+ const rowAVal = matrix[rowAIndex];
4304
+ matrix[rowAIndex] = matrix[rowBIndex];
4305
+ matrix[rowBIndex] = rowAVal;
4306
+ return matrix;
4122
4307
  }
4123
- // Use current camera position if we can't calculate the center.
4124
- else {
4125
- center = Cartographic.fromCartesian(viewer.camera.position);
4126
- center.height = 0;
4308
+ // Zeros rowA at colIndex by subtracting a multiplied rowB from it.
4309
+ function reduceMatrixRowByRow(matrix, zeroingIndex, parentIndex, colIndex) {
4310
+ const zeroRow = matrix[zeroingIndex];
4311
+ const parentRow = matrix[parentIndex];
4312
+ if (zeroRow[colIndex] == 0) {
4313
+ return matrix;
4314
+ }
4315
+ else if (parentRow[colIndex] == 0) {
4316
+ matrix = swapRows(matrix, parentIndex, zeroingIndex);
4317
+ return divideMatrixRow(matrix, parentIndex, colIndex);
4318
+ }
4319
+ // rowAIndex colIndex / rowBIndex colIndex = factor;
4320
+ let factor = zeroRow[colIndex] / parentRow[colIndex];
4321
+ for (let i = 0; i < zeroRow.length; i++) {
4322
+ if (i >= colIndex) {
4323
+ zeroRow[i] -= parentRow[i] * factor;
4324
+ }
4325
+ }
4326
+ return matrix;
4127
4327
  }
4128
- center.height = viewer.camera.positionCartographic.height + 100;
4129
- viewer.camera.setView({
4130
- destination: Cartographic.toCartesian(center),
4131
- orientation: {
4132
- heading: 0.0,
4133
- pitch: Math$1.toRadians(-90.0),
4134
- roll: 0.0
4328
+ // Makes a given row column equal 1 by diving while row by that column.
4329
+ function divideMatrixRow(matrix, rowIndex, colIndex) {
4330
+ const row = matrix[rowIndex];
4331
+ const colValue = row[colIndex];
4332
+ for (let i = 0; i < row.length; i++) {
4333
+ if (i >= colIndex) {
4334
+ row[i] /= colValue;
4335
+ }
4135
4336
  }
4136
- });
4137
- }
4138
- catch (e) {
4139
- console.error(e);
4140
- }
4337
+ return matrix;
4338
+ }
4339
+ // Returns initial matrix for calculating a, b and c for quadratic formula from given points.
4340
+ function matrixFromPoints(points) {
4341
+ const rows = [];
4342
+ const constructRow = (point) => {
4343
+ rows.push([
4344
+ -Math.pow(point.x, 2),
4345
+ point.x,
4346
+ 1,
4347
+ point.y
4348
+ ]);
4349
+ };
4350
+ for (let i = 0; i < points.length; i++) {
4351
+ constructRow(points[i]);
4352
+ }
4353
+ return rows;
4354
+ }
4355
+ const initialMatrix = matrixFromPoints(points);
4356
+ const step1Matrix = reduceMatrixRowByRow(initialMatrix, 1, 0, 0);
4357
+ const step2Matrix = reduceMatrixRowByRow(step1Matrix, 2, 0, 0);
4358
+ const step3Matrix = reduceMatrixRowByRow(step2Matrix, 2, 1, 1);
4359
+ const step4Matrix = reduceMatrixRowByRow(step3Matrix, 0, 1, 1);
4360
+ const step5Matrix = reduceMatrixRowByRow(step4Matrix, 0, 2, 2);
4361
+ const step6Matrix = reduceMatrixRowByRow(step5Matrix, 1, 2, 2);
4362
+ const a = step6Matrix[0][3];
4363
+ const b = step6Matrix[1][3];
4364
+ const c = step6Matrix[2][3];
4365
+ return { a: a, b: b, c: c };
4366
+ };
4367
+ quadratic = calcQuadratic(points2d);
4141
4368
  }
4142
- viewer.scene.requestRender();
4143
- }
4144
- }
4145
- ViewUtils.Set2dStatus = Set2dStatus;
4146
- function Get2dStatus(params) {
4147
- const { viewer } = params;
4148
- return viewer.camera.frustum instanceof OrthographicFrustum;
4149
- }
4150
- ViewUtils.Get2dStatus = Get2dStatus;
4151
- function SetLockedCameraStatus(params) {
4152
- const { viewer, status } = params;
4153
- const scene = viewer === null || viewer === void 0 ? void 0 : viewer.scene;
4154
- if (!scene) {
4155
- return;
4156
- }
4157
- if (status) {
4158
- scene.screenSpaceCameraController.enableInputs = false;
4159
- scene.screenSpaceCameraController.enableTranslate = false;
4160
- scene.screenSpaceCameraController.enableZoom = false;
4161
- scene.screenSpaceCameraController.enableRotate = false;
4162
- scene.screenSpaceCameraController.enableTilt = false;
4163
- }
4164
- else {
4165
- scene.screenSpaceCameraController.enableInputs = true;
4166
- scene.screenSpaceCameraController.enableTranslate = true;
4167
- scene.screenSpaceCameraController.enableZoom = true;
4168
- scene.screenSpaceCameraController.enableRotate = true;
4169
- if (!ViewUtils.Get2dStatus({ viewer })) {
4170
- scene.screenSpaceCameraController.enableTilt = true;
4369
+ catch (e) {
4370
+ console.error(e);
4171
4371
  }
4172
- }
4173
- viewer.scene.requestRender();
4174
- }
4175
- ViewUtils.SetLockedCameraStatus = SetLockedCameraStatus;
4176
- function GetLockedCameraStatus(params) {
4177
- var _a;
4178
- const scene = (_a = params.viewer) === null || _a === void 0 ? void 0 : _a.scene;
4179
- if (!scene) {
4180
- return false;
4181
- }
4182
- return !scene.screenSpaceCameraController.enableTranslate;
4183
- }
4184
- ViewUtils.GetLockedCameraStatus = GetLockedCameraStatus;
4185
- /**
4186
- * Returns the current camera time and related settings.
4187
- * @param params
4188
- * @returns
4189
- */
4190
- function GetTimeDetails(params) {
4191
- const { viewer } = params;
4192
- const clock = viewer.clock;
4372
+ finally {
4373
+ quadraticPreparing = false;
4374
+ }
4375
+ };
4376
+ const getPosition = (increment) => {
4377
+ if (!quadratic) {
4378
+ return null;
4379
+ }
4380
+ let lengthAcross = POINT_LENGTH * increment;
4381
+ if (lengthAcross > TOTAL_LENGTH) {
4382
+ lengthAcross = TOTAL_LENGTH;
4383
+ }
4384
+ const getParabolaYFromX = (x, quadLetters) => {
4385
+ let a = quadLetters.a;
4386
+ let b = quadLetters.b;
4387
+ let c = quadLetters.c;
4388
+ return (-a * Math.pow(x, 2)) + (b * x) + c;
4389
+ };
4390
+ const { point: pos3d } = DrawingUtils.PointAcrossPolyline({
4391
+ viewer: this.viewer,
4392
+ distance: lengthAcross,
4393
+ posses: [this.curPos1, this.curPos2]
4394
+ });
4395
+ const point = Cartographic.fromCartesian(pos3d);
4396
+ const posHeight = getParabolaYFromX(lengthAcross, quadratic);
4397
+ return Cartesian3.fromRadians(point.longitude, point.latitude, posHeight);
4398
+ };
4399
+ const updatePoints = () => {
4400
+ if (!quadratic) {
4401
+ return;
4402
+ }
4403
+ const increment = Math.floor(curPoint);
4404
+ const chips = curPoint - Math.floor(curPoint);
4405
+ const posses = [];
4406
+ posses.push(getPosition(0));
4407
+ const addLast = increment >= TOTAL_POINTS;
4408
+ const totalCycles = addLast ? increment + 1 : increment;
4409
+ for (let i = 0; i < totalCycles; i++) {
4410
+ posses.push(getPosition(i));
4411
+ }
4412
+ if (chips) {
4413
+ posses.push(getPosition(increment + chips));
4414
+ }
4415
+ if (posses.find(x => !x || !Cartes.ValidateCartes3(x))) {
4416
+ return;
4417
+ }
4418
+ this.curPoints = posses;
4419
+ };
4420
+ let lastTickDate = new Date();
4421
+ let finished = false;
4422
+ const doTick = () => {
4423
+ const curDate = new Date();
4424
+ const seconds = (curDate.getTime() - lastTickDate.getTime()) / 1000;
4425
+ const ticks = seconds * RATE_PER_SECOND;
4426
+ if (!isNaN(ticks) && ticks >= 1) {
4427
+ lastTickDate = curDate;
4428
+ const p1 = this.curPos1;
4429
+ const p2 = this.curPos2;
4430
+ const newLength = p1 && p2 ? Cartesian3.distance(p1, p2) : -1;
4431
+ if (newLength > 0 && newLength != TOTAL_LENGTH) {
4432
+ TOTAL_LENGTH = newLength;
4433
+ updateParams();
4434
+ }
4435
+ prepareQuadratic();
4436
+ if (quadratic) {
4437
+ if (curPoint < TOTAL_POINTS) {
4438
+ curPoint += (TICK_LENGTH_INC * ticks);
4439
+ }
4440
+ updatePoints();
4441
+ }
4442
+ this.viewer.scene.requestRender();
4443
+ if (curPoint >= TOTAL_POINTS && !finished) {
4444
+ finished = true;
4445
+ // We can make the interval update super slow now.
4446
+ // We keep it updating in case the positions move.
4447
+ clearInterval(this.animateInterval);
4448
+ this.animateInterval = setInterval(doTick, 3000);
4449
+ }
4450
+ }
4451
+ };
4452
+ this.animateInterval = setInterval(doTick, RATE_PER_SECOND);
4193
4453
  return {
4194
- animationSpeed: clock.multiplier,
4195
- isAnimating: clock.shouldAnimate,
4196
- startTime: clock.startTime,
4197
- startTimeIso: clock.startTime.toString(),
4198
- currentTime: clock.currentTime,
4199
- currentTimeIso: clock.currentTime.toString(),
4200
- stopTime: clock.stopTime,
4201
- stopTimeIso: clock.stopTime.toString(),
4202
- areCesiumValues: clock[CESIUM_TIMELINE_KEY] != true,
4203
- isLive: clock[CESIUM_TIMELINE_LIVE_KEY] == true,
4204
- livePaddingSeconds: clock[CESIUM_TIMELINE_LIVE_PADDING_KEY] || DEFAULT_LIVE_PADDING_SECONDS
4454
+ parabola: this.parabola,
4455
+ siblings: this.siblings
4205
4456
  };
4206
4457
  }
4207
- ViewUtils.GetTimeDetails = GetTimeDetails;
4208
- /**
4209
- * Sets the Cesium clock values.
4210
- * If a value is not provided, then 'areCesiumValues' checked to see if the values are Cesium values.
4211
- * If they're currently Cesium set values then our defaults are used.
4212
- * @param params
4213
- */
4214
- function SetTimeDetails(params) {
4215
- let { viewer, animationSpeed, isAnimating, startTime, currentTime, stopTime, startTimeIso, stopTimeIso, currentTimeIso, isLive, livePaddingSeconds } = params;
4216
- const clock = viewer.clock;
4217
- if (startTime) {
4218
- clock.startTime = startTime;
4219
- }
4220
- else if (startTimeIso) {
4221
- const startDate = JulianDate.fromIso8601(startTimeIso);
4222
- if (startDate) {
4223
- clock.startTime = startDate;
4458
+ Dispose() {
4459
+ this.disposed = true;
4460
+ clearTimeout(this.retryTimeout);
4461
+ clearInterval(this.animateInterval);
4462
+ const cEntities = [
4463
+ this.parabola
4464
+ ].concat(this.siblings);
4465
+ cEntities.forEach(e => {
4466
+ if (e && this.viewer.entities.contains(e)) {
4467
+ this.viewer.entities.remove(e);
4224
4468
  }
4469
+ });
4470
+ }
4471
+ }
4472
+
4473
+ function colorToCColor(color) {
4474
+ return new Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
4475
+ }
4476
+ async function getStyle(api, typeId, styleId) {
4477
+ let style = null;
4478
+ if (styleId && styleId != -1) {
4479
+ try {
4480
+ style = (await Style.Get({
4481
+ api,
4482
+ styleId
4483
+ })).style;
4225
4484
  }
4226
- if (currentTime) {
4227
- clock.currentTime = currentTime;
4485
+ // Probably deleted.
4486
+ catch (e) {
4487
+ console.error(e);
4228
4488
  }
4229
- else if (currentTimeIso) {
4230
- const currentDate = JulianDate.fromIso8601(currentTimeIso);
4231
- if (currentDate) {
4232
- clock.currentTime = currentDate;
4489
+ }
4490
+ if (!style && typeId) {
4491
+ const { entityType: type } = await EntityType.Get({
4492
+ api,
4493
+ entityTypeId: typeId
4494
+ });
4495
+ if (type["DisplaySetting.ID"]) {
4496
+ try {
4497
+ style = (await Style.Get({
4498
+ api,
4499
+ styleId: type["DisplaySetting.ID"]
4500
+ })).style;
4233
4501
  }
4234
- }
4235
- if (stopTime) {
4236
- clock.stopTime = stopTime;
4237
- }
4238
- else if (stopTimeIso) {
4239
- const stopDate = JulianDate.fromIso8601(stopTimeIso);
4240
- if (stopDate) {
4241
- clock.stopTime = stopDate;
4502
+ catch (e) {
4503
+ let hideError = false;
4504
+ // TODO: we need a util for extracting code + message rather than writing all this every time.
4505
+ if (e && typeof e == "object" && e.ERROR) {
4506
+ const error = e.ERROR;
4507
+ const code = error && typeof error == "object" ? error.Code : "";
4508
+ // Avoiding logging a common error.
4509
+ // This happens when rendering entities that don't have records.
4510
+ hideError = String(code).toLowerCase() == "notfound";
4511
+ }
4512
+ if (!hideError) {
4513
+ console.error(e);
4514
+ }
4242
4515
  }
4243
4516
  }
4244
- clock.clockRange = ClockRange.LOOP_STOP;
4245
- const areCesiumValues = clock[CESIUM_TIMELINE_KEY] != true;
4246
- if (areCesiumValues) {
4247
- if (isNaN(animationSpeed) || animationSpeed == null) {
4248
- animationSpeed = 1;
4249
- }
4250
- if (isAnimating == null) {
4251
- isAnimating = false;
4517
+ }
4518
+ return style;
4519
+ }
4520
+ var RelationRenderEngine;
4521
+ (function (RelationRenderEngine) {
4522
+ function GetRenderGroupId(relation) {
4523
+ return `${relation["Related.Entity.ID"]}-${relation["Principal.Entity.ID"]}-${relation["Relation.Type.ID"]}`;
4524
+ }
4525
+ RelationRenderEngine.GetRenderGroupId = GetRenderGroupId;
4526
+ async function Render(params) {
4527
+ const { apiGetter, viewer, visualRegister, menuItemId, relations } = params;
4528
+ const api = apiGetter.getApi(apiGetter.accountId);
4529
+ const rendered = {};
4530
+ let neededEntityIdsIds = [];
4531
+ for (let i = 0; i < relations.length; i++) {
4532
+ const relation = relations[i];
4533
+ if (relation["Principal.Entity.ID"]) {
4534
+ neededEntityIdsIds.push(relation["Principal.Entity.ID"]);
4252
4535
  }
4253
- if (isLive == null) {
4254
- isLive = false;
4536
+ if (relation["Related.Entity.ID"]) {
4537
+ neededEntityIdsIds.push(relation["Related.Entity.ID"]);
4255
4538
  }
4256
- if (livePaddingSeconds == null) {
4257
- livePaddingSeconds = DEFAULT_LIVE_PADDING_SECONDS;
4539
+ if (relation["Data.Entity.ID"]) {
4540
+ neededEntityIdsIds.push(relation["Data.Entity.ID"]);
4258
4541
  }
4259
4542
  }
4260
- if (!isNaN(animationSpeed) && animationSpeed != null) {
4261
- clock.multiplier = animationSpeed;
4262
- }
4263
- if (isAnimating != null) {
4264
- clock.shouldAnimate = isAnimating;
4265
- }
4266
- viewer.scene.requestRender();
4267
- clock[CESIUM_TIMELINE_KEY] = true;
4268
- if (livePaddingSeconds != null) {
4269
- clock[CESIUM_TIMELINE_LIVE_PADDING_KEY] = livePaddingSeconds || DEFAULT_LIVE_PADDING_SECONDS;
4270
- }
4271
- if (isLive != null) {
4272
- clock[CESIUM_TIMELINE_LIVE_KEY] = params.isLive == true;
4273
- }
4274
- if (clock[CESIUM_TIMELINE_LIVE_KEY]) {
4275
- startLive(viewer);
4543
+ // Turn the set unique.
4544
+ neededEntityIdsIds = neededEntityIdsIds.filter((v, i, a) => a.indexOf(v) === i);
4545
+ // Get all entities in one go.
4546
+ let entities = (await Entity$1.GetListByIds({
4547
+ entityIds: neededEntityIdsIds,
4548
+ api: apiGetter.getApi(),
4549
+ migrated: true,
4550
+ maxSearchTimeSec: 60 * 2
4551
+ })).entities;
4552
+ // Create a map for quick reference.
4553
+ const entitiesMap = {};
4554
+ for (let i = 0; i < entities.length; i++) {
4555
+ const entity = entities[i];
4556
+ entitiesMap[entity.Bruce.ID] = entity;
4276
4557
  }
4277
- else {
4278
- stopLive(viewer);
4558
+ entities = null;
4559
+ // Gather needed relationship types.
4560
+ // Right now this means just getting the full list.
4561
+ const relationTypes = (await EntityRelationType.GetList({
4562
+ api
4563
+ })).relationTypes;
4564
+ const relationTypesMap = {};
4565
+ for (let i = 0; i < relationTypes.length; i++) {
4566
+ const relationType = relationTypes[i];
4567
+ relationTypesMap[relationType.ID] = relationType;
4279
4568
  }
4280
- }
4281
- ViewUtils.SetTimeDetails = SetTimeDetails;
4282
- function startLive(viewer) {
4283
- const doUpdate = () => {
4284
- if (!viewer || viewer.isDestroyed() || !viewer.scene) {
4285
- stopLive(viewer);
4286
- return;
4569
+ for (let i = 0; i < relations.length; i++) {
4570
+ try {
4571
+ const relation = relations[i];
4572
+ const fromEntity = entitiesMap[relation["Principal.Entity.ID"]];
4573
+ const toEntity = entitiesMap[relation["Related.Entity.ID"]];
4574
+ const dataEntity = relation["Data.Entity.ID"] ? entitiesMap[relation["Data.Entity.ID"]] : null;
4575
+ const relationType = relationTypesMap[relation["Relation.Type.ID"]];
4576
+ const style = await getStyle(api, relationType === null || relationType === void 0 ? void 0 : relationType["Relation.EntityType.ID"], Number(relationType === null || relationType === void 0 ? void 0 : relationType.EntityDisplaySettingID));
4577
+ const cEntity = await Parabola.Render({
4578
+ dataEntity,
4579
+ fromEntity,
4580
+ relation,
4581
+ style,
4582
+ toEntity,
4583
+ viewer,
4584
+ visualRegister,
4585
+ apiGetter
4586
+ });
4587
+ cEntity._renderGroup = GetRenderGroupId(relation);
4588
+ rendered[GetRenderGroupId(relation)] = cEntity;
4287
4589
  }
4288
- // Get the current settings.
4289
- const tDetails = GetTimeDetails({ viewer });
4290
- const clock = viewer.clock;
4291
- if (clock) {
4292
- clock.shouldAnimate = true;
4293
- clock.multiplier = 1;
4294
- clock.currentTime = JulianDate.now();
4295
- clock.startTime = JulianDate.addSeconds(clock.currentTime, -tDetails.livePaddingSeconds, new JulianDate());
4296
- clock.stopTime = JulianDate.addSeconds(clock.currentTime, tDetails.livePaddingSeconds, new JulianDate());
4297
- clock.clockRange = ClockRange.UNBOUNDED;
4590
+ catch (e) {
4591
+ console.error(e);
4298
4592
  }
4299
- };
4300
- if (viewer[CESIUM_TIMELINE_INTERVAL_KEY]) {
4301
- doUpdate();
4302
- return;
4303
- }
4304
- // We'll start an interval that occasionally updates the Cesium clock to stay in the desired settings.
4305
- // Since it moves live (1 second per second), we don't have to worry about the ranges being out of date quickly.
4306
- viewer[CESIUM_TIMELINE_INTERVAL_KEY] = setInterval(() => {
4307
- doUpdate();
4308
- }, 800);
4309
- viewer[CESIUM_TIMELINE_LIVE_KEY] = true;
4310
- // Initial update.
4311
- doUpdate();
4312
- }
4313
- function stopLive(viewer) {
4314
- if (!viewer) {
4315
- return;
4316
- }
4317
- let interval = viewer[CESIUM_TIMELINE_INTERVAL_KEY];
4318
- if (interval) {
4319
- clearInterval(interval);
4320
- viewer[CESIUM_TIMELINE_INTERVAL_KEY] = null;
4321
- }
4322
- viewer[CESIUM_TIMELINE_LIVE_KEY] = false;
4323
- }
4324
- function SetGlobeDetails(params) {
4325
- let { viewer, hidden, baseColor } = params;
4326
- const scene = viewer === null || viewer === void 0 ? void 0 : viewer.scene;
4327
- if (!(scene === null || scene === void 0 ? void 0 : scene.globe)) {
4328
- return;
4329
- }
4330
- if (hidden == null) {
4331
- hidden = !scene.globe.show;
4332
- }
4333
- else {
4334
- scene.globe.show = !hidden;
4335
- }
4336
- if (baseColor == null) {
4337
- baseColor = scene.globe.baseColor;
4338
- }
4339
- // When globe is off, we'll also hide the stars/moon.
4340
- // We also grab the globe color and apply it to the sky.
4341
- if (hidden && GetModelSpace(viewer)) {
4342
- scene.skyBox.show = false;
4343
- scene.skyAtmosphere.show = false;
4344
- scene.sun.show = false;
4345
- scene.moon.show = false;
4346
- scene.backgroundColor = baseColor.clone();
4347
- }
4348
- else {
4349
- scene.skyBox.show = true;
4350
- scene.skyAtmosphere.show = true;
4351
- scene.sun.show = true;
4352
- scene.moon.show = true;
4353
- scene.backgroundColor = Color.BLACK;
4354
- }
4355
- scene.globe.baseColor = baseColor;
4356
- }
4357
- ViewUtils.SetGlobeDetails = SetGlobeDetails;
4358
- function SetModelSpace(viewer, modelSpace) {
4359
- if (!viewer) {
4360
- return;
4361
4593
  }
4362
- if (viewer[CESIUM_MODEL_SPACE_KEY] === modelSpace) {
4363
- return;
4364
- }
4365
- viewer[CESIUM_MODEL_SPACE_KEY] = modelSpace;
4366
- // Reload globe since we display it differently between the two modes.
4367
- SetGlobeDetails({ viewer });
4594
+ return rendered;
4368
4595
  }
4369
- ViewUtils.SetModelSpace = SetModelSpace;
4370
- function GetModelSpace(viewer) {
4371
- if (!viewer) {
4372
- return false;
4596
+ RelationRenderEngine.Render = Render;
4597
+ let Parabola;
4598
+ (function (Parabola) {
4599
+ async function Render(params) {
4600
+ var _a;
4601
+ const style = (_a = params.style) === null || _a === void 0 ? void 0 : _a.Settings;
4602
+ const entity = params.dataEntity;
4603
+ const bColor = (style === null || style === void 0 ? void 0 : style.lineColor) ? Calculator.GetColor(style === null || style === void 0 ? void 0 : style.lineColor, entity, []) : null;
4604
+ const cColor = bColor ? colorToCColor(bColor) : Color.WHITE;
4605
+ let width = EnsureNumber((style === null || style === void 0 ? void 0 : style.lineWidth) ? Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.lineWidth, entity, []) : 4, 4);
4606
+ if (width < 1) {
4607
+ width = 1;
4608
+ }
4609
+ const duration = EnsureNumber((style === null || style === void 0 ? void 0 : style.duration) ? Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.duration, entity, []) : 2, 2);
4610
+ const hDistanceRatio = EnsureNumber((style === null || style === void 0 ? void 0 : style.heightDistanceRatio) ? Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.heightDistanceRatio, entity, []) : 0.25, 0.25);
4611
+ let fromPos = null;
4612
+ let toPos = null;
4613
+ let updatingPosses = false;
4614
+ const updatePosses = async () => {
4615
+ if (updatingPosses) {
4616
+ return;
4617
+ }
4618
+ updatingPosses = true;
4619
+ try {
4620
+ const fromData = await EntityUtils.GetLocation({
4621
+ samples: [{
4622
+ entity: params.fromEntity,
4623
+ entityId: params.fromEntity.Bruce.ID,
4624
+ heightRef: HeightReference.CLAMP_TO_GROUND,
4625
+ returnHeightRef: HeightReference.NONE
4626
+ }],
4627
+ viewer: params.viewer,
4628
+ visualRegister: params.visualRegister,
4629
+ api: params.apiGetter.getApi()
4630
+ });
4631
+ fromPos = fromData.pos3d;
4632
+ const toData = await EntityUtils.GetLocation({
4633
+ samples: [{
4634
+ entity: params.toEntity,
4635
+ entityId: params.toEntity.Bruce.ID,
4636
+ heightRef: HeightReference.CLAMP_TO_GROUND,
4637
+ returnHeightRef: HeightReference.NONE
4638
+ }],
4639
+ viewer: params.viewer,
4640
+ visualRegister: params.visualRegister,
4641
+ api: params.apiGetter.getApi()
4642
+ });
4643
+ toPos = toData.pos3d;
4644
+ }
4645
+ catch (e) {
4646
+ console.error(e);
4647
+ }
4648
+ updatingPosses = false;
4649
+ };
4650
+ updatePosses();
4651
+ const parabola = new CesiumParabola({
4652
+ viewer: params.viewer,
4653
+ pos1: () => fromPos,
4654
+ pos2: () => toPos,
4655
+ color: cColor.toCssColorString(),
4656
+ width: width,
4657
+ duration: duration,
4658
+ heightDistanceRatio: hDistanceRatio
4659
+ });
4660
+ parabola.Hidden = true;
4661
+ const cEntities = parabola.Animate();
4662
+ const cEntity = cEntities.parabola;
4663
+ cEntity._siblingGraphics = [];
4664
+ for (let i = 0; i < cEntities.siblings.length; i++) {
4665
+ const sibling = cEntities.siblings[i];
4666
+ cEntity._siblingGraphics.push(sibling);
4667
+ }
4668
+ let updateInterval = setInterval(() => {
4669
+ var _a;
4670
+ if (!((_a = params.viewer) === null || _a === void 0 ? void 0 : _a.scene) ||
4671
+ params.viewer.isDestroyed() ||
4672
+ (!parabola || parabola.Disposed)) {
4673
+ clearInterval(updateInterval);
4674
+ parabola.Dispose();
4675
+ return;
4676
+ }
4677
+ if (parabola) {
4678
+ const visible = cEntity && cEntity.show != false && params.viewer.entities.contains(cEntity);
4679
+ parabola.Hidden = !visible;
4680
+ }
4681
+ updatePosses();
4682
+ params.viewer.scene.requestRender();
4683
+ }, 1000);
4684
+ let disposed = false;
4685
+ cEntity._dispose = () => {
4686
+ if (disposed) {
4687
+ return;
4688
+ }
4689
+ disposed = true;
4690
+ clearInterval(updateInterval);
4691
+ if (parabola) {
4692
+ parabola.Dispose();
4693
+ }
4694
+ };
4695
+ return cEntity;
4373
4696
  }
4374
- return Boolean(viewer[CESIUM_MODEL_SPACE_KEY]);
4375
- }
4376
- ViewUtils.GetModelSpace = GetModelSpace;
4377
- })(ViewUtils || (ViewUtils = {}));
4697
+ Parabola.Render = Render;
4698
+ })(Parabola = RelationRenderEngine.Parabola || (RelationRenderEngine.Parabola = {}));
4699
+ })(RelationRenderEngine || (RelationRenderEngine = {}));
4378
4700
 
4379
4701
  const MODEL_MIN_RADIUS = 10;
4380
4702
  const POINT_MIN_RADIUS = 15;
@@ -7038,6 +7360,116 @@ var VisualsRegister;
7038
7360
  VisualsRegister.Register = Register;
7039
7361
  })(VisualsRegister || (VisualsRegister = {}));
7040
7362
 
7363
+ /**
7364
+ * Tracks per-entity rerender state for unsaved blob maintenance and stale API response suppression.
7365
+ */
7366
+ class EntityReRenderMaintainState {
7367
+ constructor() {
7368
+ this.maintainedEntitiesById = {};
7369
+ this.apiRevisionByEntityId = {};
7370
+ this.skipApiRunByEntityId = {};
7371
+ this.checkRunId = 0;
7372
+ }
7373
+ setMaintainedEntities(entities) {
7374
+ var _a;
7375
+ for (let i = 0; i < entities.length; i++) {
7376
+ const entity = entities[i];
7377
+ const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
7378
+ if (!id) {
7379
+ continue;
7380
+ }
7381
+ this.maintainedEntitiesById[id] = entity;
7382
+ }
7383
+ }
7384
+ clearMaintainedEntities(entityIds) {
7385
+ for (let i = 0; i < entityIds.length; i++) {
7386
+ const id = entityIds[i];
7387
+ if (!id) {
7388
+ continue;
7389
+ }
7390
+ delete this.maintainedEntitiesById[id];
7391
+ }
7392
+ }
7393
+ getMaintainedEntities(entityIds) {
7394
+ const entities = [];
7395
+ for (let i = 0; i < entityIds.length; i++) {
7396
+ const id = entityIds[i];
7397
+ if (!id) {
7398
+ continue;
7399
+ }
7400
+ const entity = this.maintainedEntitiesById[id];
7401
+ if (entity) {
7402
+ entities.push(entity);
7403
+ }
7404
+ }
7405
+ return entities;
7406
+ }
7407
+ bumpApiRevisions(entityIds) {
7408
+ var _a;
7409
+ for (let i = 0; i < entityIds.length; i++) {
7410
+ const id = entityIds[i];
7411
+ if (!id) {
7412
+ continue;
7413
+ }
7414
+ this.apiRevisionByEntityId[id] = ((_a = this.apiRevisionByEntityId[id]) !== null && _a !== void 0 ? _a : 0) + 1;
7415
+ }
7416
+ }
7417
+ captureApiRevisions(entityIds) {
7418
+ var _a;
7419
+ const revisions = {};
7420
+ for (let i = 0; i < entityIds.length; i++) {
7421
+ const id = entityIds[i];
7422
+ if (!id) {
7423
+ continue;
7424
+ }
7425
+ revisions[id] = (_a = this.apiRevisionByEntityId[id]) !== null && _a !== void 0 ? _a : 0;
7426
+ }
7427
+ return revisions;
7428
+ }
7429
+ startCheckRun() {
7430
+ this.checkRunId += 1;
7431
+ return this.checkRunId;
7432
+ }
7433
+ getCurrentCheckRun() {
7434
+ return this.checkRunId;
7435
+ }
7436
+ markSkipForCurrentRun(entityIds, isRunningCheck) {
7437
+ if (!isRunningCheck) {
7438
+ return;
7439
+ }
7440
+ const runId = this.checkRunId;
7441
+ for (let i = 0; i < entityIds.length; i++) {
7442
+ const id = entityIds[i];
7443
+ if (!id) {
7444
+ continue;
7445
+ }
7446
+ this.skipApiRunByEntityId[id] = runId;
7447
+ }
7448
+ }
7449
+ shouldSkipInRun(entityId, runId) {
7450
+ return this.skipApiRunByEntityId[entityId] === runId;
7451
+ }
7452
+ filterNonSkippedIds(entityIds, runId) {
7453
+ return entityIds.filter((id) => {
7454
+ return id && !this.shouldSkipInRun(id, runId);
7455
+ });
7456
+ }
7457
+ filterCurrentApiEntities(params) {
7458
+ const { entities, revisions, runId } = params;
7459
+ return entities.filter((entity) => {
7460
+ var _a, _b, _c;
7461
+ const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
7462
+ if (!id) {
7463
+ return false;
7464
+ }
7465
+ if (runId != null && this.shouldSkipInRun(id, runId)) {
7466
+ return false;
7467
+ }
7468
+ return ((_b = this.apiRevisionByEntityId[id]) !== null && _b !== void 0 ? _b : 0) === ((_c = revisions[id]) !== null && _c !== void 0 ? _c : 0);
7469
+ });
7470
+ }
7471
+ }
7472
+
7041
7473
  function GetValue(viewer, obj) {
7042
7474
  if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
7043
7475
  let date = viewer.scene.lastRenderTime;
@@ -7857,438 +8289,6 @@ class PointClustering {
7857
8289
  }
7858
8290
  }
7859
8291
 
7860
- /**
7861
- * Tracks per-entity rerender state for unsaved blob maintenance and stale API response suppression.
7862
- */
7863
- class EntityReRenderMaintainState {
7864
- constructor() {
7865
- this.maintainedEntitiesById = {};
7866
- this.apiRevisionByEntityId = {};
7867
- this.skipApiRunByEntityId = {};
7868
- this.checkRunId = 0;
7869
- }
7870
- setMaintainedEntities(entities) {
7871
- var _a;
7872
- for (let i = 0; i < entities.length; i++) {
7873
- const entity = entities[i];
7874
- const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
7875
- if (!id) {
7876
- continue;
7877
- }
7878
- this.maintainedEntitiesById[id] = entity;
7879
- }
7880
- }
7881
- clearMaintainedEntities(entityIds) {
7882
- for (let i = 0; i < entityIds.length; i++) {
7883
- const id = entityIds[i];
7884
- if (!id) {
7885
- continue;
7886
- }
7887
- delete this.maintainedEntitiesById[id];
7888
- }
7889
- }
7890
- getMaintainedEntities(entityIds) {
7891
- const entities = [];
7892
- for (let i = 0; i < entityIds.length; i++) {
7893
- const id = entityIds[i];
7894
- if (!id) {
7895
- continue;
7896
- }
7897
- const entity = this.maintainedEntitiesById[id];
7898
- if (entity) {
7899
- entities.push(entity);
7900
- }
7901
- }
7902
- return entities;
7903
- }
7904
- bumpApiRevisions(entityIds) {
7905
- var _a;
7906
- for (let i = 0; i < entityIds.length; i++) {
7907
- const id = entityIds[i];
7908
- if (!id) {
7909
- continue;
7910
- }
7911
- this.apiRevisionByEntityId[id] = ((_a = this.apiRevisionByEntityId[id]) !== null && _a !== void 0 ? _a : 0) + 1;
7912
- }
7913
- }
7914
- captureApiRevisions(entityIds) {
7915
- var _a;
7916
- const revisions = {};
7917
- for (let i = 0; i < entityIds.length; i++) {
7918
- const id = entityIds[i];
7919
- if (!id) {
7920
- continue;
7921
- }
7922
- revisions[id] = (_a = this.apiRevisionByEntityId[id]) !== null && _a !== void 0 ? _a : 0;
7923
- }
7924
- return revisions;
7925
- }
7926
- startCheckRun() {
7927
- this.checkRunId += 1;
7928
- return this.checkRunId;
7929
- }
7930
- getCurrentCheckRun() {
7931
- return this.checkRunId;
7932
- }
7933
- markSkipForCurrentRun(entityIds, isRunningCheck) {
7934
- if (!isRunningCheck) {
7935
- return;
7936
- }
7937
- const runId = this.checkRunId;
7938
- for (let i = 0; i < entityIds.length; i++) {
7939
- const id = entityIds[i];
7940
- if (!id) {
7941
- continue;
7942
- }
7943
- this.skipApiRunByEntityId[id] = runId;
7944
- }
7945
- }
7946
- shouldSkipInRun(entityId, runId) {
7947
- return this.skipApiRunByEntityId[entityId] === runId;
7948
- }
7949
- filterNonSkippedIds(entityIds, runId) {
7950
- return entityIds.filter((id) => {
7951
- return id && !this.shouldSkipInRun(id, runId);
7952
- });
7953
- }
7954
- filterCurrentApiEntities(params) {
7955
- const { entities, revisions, runId } = params;
7956
- return entities.filter((entity) => {
7957
- var _a, _b, _c;
7958
- const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
7959
- if (!id) {
7960
- return false;
7961
- }
7962
- if (runId != null && this.shouldSkipInRun(id, runId)) {
7963
- return false;
7964
- }
7965
- return ((_b = this.apiRevisionByEntityId[id]) !== null && _b !== void 0 ? _b : 0) === ((_c = revisions[id]) !== null && _c !== void 0 ? _c : 0);
7966
- });
7967
- }
7968
- }
7969
-
7970
- function isTurfAvailable() {
7971
- return window && window.turf != null;
7972
- }
7973
- /**
7974
- * Util for simplifying geometry on the fly.
7975
- */
7976
- var SimplifyGeometry;
7977
- (function (SimplifyGeometry) {
7978
- /**
7979
- * Returns the total number of points in the geometry.
7980
- * @param geometry
7981
- * @param limit number to count up to before returning.
7982
- * @returns
7983
- */
7984
- function CountPoints(geometry, limit) {
7985
- let count = 0;
7986
- const traverse = (geometry) => {
7987
- if (geometry.MultiGeometry) {
7988
- for (let i = 0; i < geometry.MultiGeometry.length; i++) {
7989
- traverse(geometry.MultiGeometry[i]);
7990
- // Reached the limit, return.
7991
- if (limit && count >= limit) {
7992
- return;
7993
- }
7994
- }
7995
- }
7996
- else if (geometry.Polygon) {
7997
- for (let i = 0; i < geometry.Polygon.length; i++) {
7998
- const polygon = geometry.Polygon[i];
7999
- count += Geometry.ParsePoints(polygon.LinearRing).length;
8000
- }
8001
- }
8002
- else if (geometry.LineString) {
8003
- count += Geometry.ParsePoints(geometry.LineString).length;
8004
- }
8005
- else if (geometry.Point) {
8006
- count += 1;
8007
- }
8008
- };
8009
- traverse(geometry);
8010
- return count;
8011
- }
8012
- SimplifyGeometry.CountPoints = CountPoints;
8013
- /**
8014
- * Simplifies input geometry.
8015
- * This will turn it into GeoJSON, run it through turf, then back to Bruce geometry.
8016
- * @param geometry
8017
- */
8018
- function Simplify(entityId, geometry, tolerance) {
8019
- var _a;
8020
- if (!geometry || !isTurfAvailable() || !turf.simplify) {
8021
- return geometry;
8022
- }
8023
- // Convert to geojson so that we can interact with turf.
8024
- const gFeature = Geometry.ToGeoJsonFeature({
8025
- geometry: geometry
8026
- });
8027
- // Unkink the geometry.
8028
- // This removes overlapping polygons before we start merging and simplifying.
8029
- // Commented out because it has crashes and doesn't handle holes.
8030
- untangleFeature(gFeature);
8031
- // Union the geometry.
8032
- // This merges overlapping polygons.
8033
- unionFeature(gFeature);
8034
- // Simplify the geometry.
8035
- if (tolerance > 0) {
8036
- gFeature.geometry = turf.simplify(gFeature.geometry, {
8037
- tolerance: tolerance,
8038
- highQuality: true,
8039
- mutate: true
8040
- });
8041
- }
8042
- // Converting back to Bruce geometry.
8043
- geometry = (_a = Geometry.FromGeoJson({
8044
- geoJson: gFeature
8045
- })) === null || _a === void 0 ? void 0 : _a.geometry;
8046
- return geometry;
8047
- }
8048
- SimplifyGeometry.Simplify = Simplify;
8049
- })(SimplifyGeometry || (SimplifyGeometry = {}));
8050
- /**
8051
- * Runs through all found polygons and runs unkink through turf on them.
8052
- * @param feature
8053
- */
8054
- function untangleFeature(feature) {
8055
- // Collection to add to because the result might be multiple from an unkink.
8056
- const collection = {
8057
- geometries: [],
8058
- type: "GeometryCollection"
8059
- };
8060
- // Runs a dedupe and unkink on the coordinates.
8061
- // Returns if the coordinates were added to the collection.
8062
- const processCoordinates = (coords) => {
8063
- try {
8064
- // Dedupe the coordinates to avoid issues with unkink.
8065
- coords = dedupeCoordinates(coords);
8066
- const outer = [];
8067
- let inner = [];
8068
- // We'll unkink each ring separately as this is killing the holes when it is done as a whole.
8069
- // So we'll do it separate then recombine.
8070
- for (let i = 0; i < coords.length; i++) {
8071
- const ring = coords[i];
8072
- const unkink = turf.unkinkPolygon({
8073
- type: "Polygon",
8074
- coordinates: [ring]
8075
- });
8076
- if (unkink.type == "FeatureCollection") {
8077
- let target = i == 0 ? outer : inner;
8078
- for (let j = 0; j < unkink.features.length; j++) {
8079
- const unkinked = unkink.features[j].geometry.coordinates;
8080
- if (unkinked.length > 0) {
8081
- target.push(unkinked[0]);
8082
- }
8083
- }
8084
- }
8085
- else {
8086
- console.error("Unexpected unkink result.", unkink);
8087
- }
8088
- }
8089
- // Recreate the rings and reapply to the collection.
8090
- if (outer.length > 0) {
8091
- const combinedCoords = [outer[0]];
8092
- for (let i = 0; i < inner.length; i++) {
8093
- combinedCoords.push(inner[i]);
8094
- }
8095
- // Add the combined coordinates to the collection
8096
- const polygon = {
8097
- type: "Polygon",
8098
- coordinates: combinedCoords
8099
- };
8100
- // Ensure right-hand rule is followed.
8101
- ensureRightHandRule(polygon);
8102
- // Add to the collection.
8103
- collection.geometries.push(polygon);
8104
- return true;
8105
- }
8106
- }
8107
- catch (e) {
8108
- // console.error("Failed to unkink polygon.", e);
8109
- }
8110
- return false;
8111
- };
8112
- const processGeometry = (geometry) => {
8113
- let added = false;
8114
- if (geometry.type == "Polygon") {
8115
- added = processCoordinates(geometry.coordinates);
8116
- }
8117
- else if (geometry.type == "MultiPolygon") {
8118
- for (let i = 0; i < geometry.coordinates.length; i++) {
8119
- added = processCoordinates(geometry.coordinates[i]) || added;
8120
- }
8121
- }
8122
- if (!added) {
8123
- // Adding original since we can't unkink it.
8124
- collection.geometries.push(geometry);
8125
- }
8126
- };
8127
- if (feature.geometry.type == "GeometryCollection") {
8128
- feature.geometry.geometries.forEach((geometry) => {
8129
- processGeometry(geometry);
8130
- });
8131
- }
8132
- else {
8133
- processGeometry(feature.geometry);
8134
- }
8135
- // Re-assign the geometry.
8136
- if (collection.geometries.length == 1) {
8137
- feature.geometry = collection.geometries[0];
8138
- }
8139
- else {
8140
- feature.geometry = collection;
8141
- }
8142
- }
8143
- /**
8144
- * Runs through all found polygons and unions them using turf.
8145
- * Failed unions are ignored and the original is kept.
8146
- * @param feature
8147
- */
8148
- function unionFeature(feature) {
8149
- // Collection to add to because the result might be multiple from an unkink.
8150
- const collection = {
8151
- geometries: [],
8152
- type: "GeometryCollection"
8153
- };
8154
- // We'll turn each geometry into a feature and union them.
8155
- const tmpCollection = {
8156
- features: [],
8157
- type: "FeatureCollection"
8158
- };
8159
- if (feature.geometry.type == "GeometryCollection") {
8160
- feature.geometry.geometries.forEach((geometry) => {
8161
- if (geometry.type == "Polygon") {
8162
- tmpCollection.features.push({
8163
- type: "Feature",
8164
- geometry: geometry,
8165
- properties: {}
8166
- });
8167
- }
8168
- else if (geometry.type == "MultiPolygon") {
8169
- for (let i = 0; i < geometry.coordinates.length; i++) {
8170
- tmpCollection.features.push({
8171
- type: "Feature",
8172
- geometry: {
8173
- type: "Polygon",
8174
- coordinates: geometry.coordinates[i]
8175
- },
8176
- properties: {}
8177
- });
8178
- }
8179
- }
8180
- // Only focusing on polygons.
8181
- else {
8182
- collection.geometries.push(geometry);
8183
- }
8184
- });
8185
- }
8186
- else if (feature.geometry.type == "Polygon") {
8187
- tmpCollection.features.push({
8188
- type: "Feature",
8189
- geometry: feature.geometry,
8190
- properties: {}
8191
- });
8192
- }
8193
- else if (feature.geometry.type == "MultiPolygon") {
8194
- for (let i = 0; i < feature.geometry.coordinates.length; i++) {
8195
- tmpCollection.features.push({
8196
- type: "Feature",
8197
- geometry: {
8198
- type: "Polygon",
8199
- coordinates: feature.geometry.coordinates[i]
8200
- },
8201
- properties: {}
8202
- });
8203
- }
8204
- }
8205
- // No polygons to union.
8206
- // Need at least 2 to union.
8207
- if (tmpCollection.features.length < 2) {
8208
- return;
8209
- }
8210
- // Now we'll union them.
8211
- try {
8212
- const union = turf.union(tmpCollection);
8213
- if (union.geometry.type == "Polygon") {
8214
- collection.geometries.push(union.geometry);
8215
- }
8216
- else if (union.geometry.type == "MultiPolygon") {
8217
- for (let i = 0; i < union.geometry.coordinates.length; i++) {
8218
- collection.geometries.push({
8219
- type: "Polygon",
8220
- coordinates: union.geometry.coordinates[i]
8221
- });
8222
- }
8223
- }
8224
- else {
8225
- // Returning early because the result is unexpected.
8226
- return;
8227
- }
8228
- }
8229
- catch (e) {
8230
- // console.error("Failed to union polygons.", e);
8231
- return;
8232
- }
8233
- // Re-assign the geometry.
8234
- if (collection.geometries.length == 1) {
8235
- feature.geometry = collection.geometries[0];
8236
- }
8237
- else {
8238
- feature.geometry = collection;
8239
- }
8240
- }
8241
- function dedupeCoordinates(inputCoords) {
8242
- return inputCoords.map(ring => {
8243
- if (ring.length < 2) {
8244
- return ring;
8245
- }
8246
- const dedupeCoords = [];
8247
- const uniqueCoords = new Set();
8248
- // Dedupe the points.
8249
- ring.forEach(coord => {
8250
- const key = coord.join(',');
8251
- if (!uniqueCoords.has(key)) {
8252
- uniqueCoords.add(key);
8253
- dedupeCoords.push(coord);
8254
- }
8255
- });
8256
- // Make sure the last point matches the first.
8257
- if (dedupeCoords.length > 1) {
8258
- if (dedupeCoords[0][0] != dedupeCoords[dedupeCoords.length - 1][0] ||
8259
- dedupeCoords[0][1] != dedupeCoords[dedupeCoords.length - 1][1]) {
8260
- dedupeCoords.push(dedupeCoords[0]);
8261
- }
8262
- }
8263
- return dedupeCoords;
8264
- });
8265
- }
8266
- function ensureRightHandRule(polygon) {
8267
- // Ensure the outer ring follows the right-hand rule
8268
- if (polygon.coordinates.length > 0) {
8269
- const outerRing = polygon.coordinates[0];
8270
- if (isClockwise(outerRing)) {
8271
- polygon.coordinates[0] = outerRing.reverse();
8272
- }
8273
- }
8274
- // Ensure any inner rings (holes) follow the right-hand rule
8275
- for (let i = 1; i < polygon.coordinates.length; i++) {
8276
- const innerRing = polygon.coordinates[i];
8277
- if (!isClockwise(innerRing)) {
8278
- polygon.coordinates[i] = innerRing.reverse();
8279
- }
8280
- }
8281
- }
8282
- function isClockwise(ring) {
8283
- let sum = 0;
8284
- for (let i = 0; i < ring.length - 1; i++) {
8285
- const p1 = ring[i];
8286
- const p2 = ring[i + 1];
8287
- sum += (p2[0] - p1[0]) * (p2[1] + p1[1]);
8288
- }
8289
- return sum > 0;
8290
- }
8291
-
8292
8292
  const BATCH_SIZE = 500;
8293
8293
  const CHECK_BATCH_SIZE = 250;
8294
8294
  function getValue$2(viewer, obj) {
@@ -8333,6 +8333,16 @@ var EntitiesRenderManager;
8333
8333
  this.getterSub = null;
8334
8334
  this.disposed = false;
8335
8335
  this.renderedEntities = {};
8336
+ // InternalID to public Entity ID, populated when Entity blob is available.
8337
+ // Used to match WS entity-change events (which carry internal ID ranges) to rendered Entities.
8338
+ this.renderedByInternalId = new Map();
8339
+ // Entity ID to internal ID, reverse lookup for cleanup.
8340
+ this.internalByEntityId = new Map();
8341
+ // Cleanup function for the RecordChangeFeed subscription.
8342
+ this.feedSub = null;
8343
+ // Entity IDs waiting for a throttled re-render pass (1s rate limit).
8344
+ this.feedPendingUpdateIds = new Set();
8345
+ this.feedUpdateThrottleTimer = null;
8336
8346
  this.entityCheckQueue = null;
8337
8347
  this.entityCheckQueueIds = [];
8338
8348
  this.entityCheckRemoval = null;
@@ -8497,7 +8507,7 @@ var EntitiesRenderManager;
8497
8507
  }
8498
8508
  }
8499
8509
  setGetter() {
8500
- var _a, _b, _c, _d;
8510
+ var _a, _b, _c, _d, _e;
8501
8511
  this.unsetGetter();
8502
8512
  const isTagItem = Boolean(this.item.BruceEntity.ExpandLayers);
8503
8513
  let tagsToRender = isTagItem ? this.item.BruceEntity.SelectedExpandLayers : null;
@@ -8555,15 +8565,90 @@ var EntitiesRenderManager;
8555
8565
  this.entityCheckQueue = new DelayQueue(() => {
8556
8566
  this.doEntityCheck(Object.keys(this.renderedEntities));
8557
8567
  }, shouldCheck ? 3000 : 30000);
8568
+ const feed = (_e = this.apiGetter.getApi()) === null || _e === void 0 ? void 0 : _e.RecordChangeFeed;
8569
+ if (feed) {
8570
+ this.feedSub = feed.Subscribe({
8571
+ concepts: [AccountConcept.EConcept.ENTITY],
8572
+ actions: ["U", "D"]
8573
+ }, (event) => {
8574
+ var _a;
8575
+ if (!this.renderedByInternalId.size) {
8576
+ return;
8577
+ }
8578
+ const rangeStr = typeof event.data === "string" ? event.data : "";
8579
+ if (!rangeStr) {
8580
+ return;
8581
+ }
8582
+ const affectedIds = [];
8583
+ for (const [internalId, entityId] of this.renderedByInternalId) {
8584
+ if (RecordChangeFeed.isEntityInternalIdInRangeString(rangeStr, internalId)) {
8585
+ affectedIds.push(entityId);
8586
+ }
8587
+ }
8588
+ if (!affectedIds.length) {
8589
+ return;
8590
+ }
8591
+ // Remove regos directly.
8592
+ if (event.action === "D") {
8593
+ for (const entityId of affectedIds) {
8594
+ this.visualsManager.RemoveRegos({
8595
+ entityId,
8596
+ menuItemId: this.item.id,
8597
+ requestRender: false
8598
+ });
8599
+ delete this.renderedEntities[entityId];
8600
+ (_a = this.clustering) === null || _a === void 0 ? void 0 : _a.RemoveEntity(entityId, false);
8601
+ const knownId = this.internalByEntityId.get(entityId);
8602
+ if (knownId != null) {
8603
+ this.renderedByInternalId.delete(knownId);
8604
+ this.internalByEntityId.delete(entityId);
8605
+ }
8606
+ }
8607
+ if (this.clustering) {
8608
+ this.clustering.Update();
8609
+ }
8610
+ this.viewer.scene.requestRender();
8611
+ }
8612
+ // Accumulate IDs and flush at most once per second.
8613
+ else {
8614
+ for (const entityId of affectedIds) {
8615
+ this.feedPendingUpdateIds.add(entityId);
8616
+ }
8617
+ if (!this.feedUpdateThrottleTimer) {
8618
+ this.feedUpdateThrottleTimer = setTimeout(() => {
8619
+ this.feedUpdateThrottleTimer = null;
8620
+ if (this.disposed || !this.feedPendingUpdateIds.size) {
8621
+ return;
8622
+ }
8623
+ const ids = [...this.feedPendingUpdateIds];
8624
+ this.feedPendingUpdateIds.clear();
8625
+ this.ReRender({
8626
+ entityIds: ids,
8627
+ force: true
8628
+ });
8629
+ }, 1000);
8630
+ }
8631
+ }
8632
+ });
8633
+ }
8558
8634
  }
8559
8635
  unsetGetter() {
8560
- var _a, _b, _c;
8636
+ var _a, _b, _c, _d;
8561
8637
  (_a = this.getter) === null || _a === void 0 ? void 0 : _a.ExcludeMenuItem(this.item.id);
8562
8638
  this.getter = null;
8563
8639
  (_b = this.getterSub) === null || _b === void 0 ? void 0 : _b.call(this);
8564
8640
  this.getterSub = null;
8565
8641
  (_c = this.entityCheckQueue) === null || _c === void 0 ? void 0 : _c.Dispose();
8566
8642
  this.entityCheckQueue = null;
8643
+ (_d = this.feedSub) === null || _d === void 0 ? void 0 : _d.call(this);
8644
+ this.feedSub = null;
8645
+ if (this.feedUpdateThrottleTimer) {
8646
+ clearTimeout(this.feedUpdateThrottleTimer);
8647
+ this.feedUpdateThrottleTimer = null;
8648
+ }
8649
+ this.feedPendingUpdateIds.clear();
8650
+ this.renderedByInternalId.clear();
8651
+ this.internalByEntityId.clear();
8567
8652
  }
8568
8653
  preventCurrentCheckApiRefresh(entityIds) {
8569
8654
  var _a;
@@ -9116,7 +9201,7 @@ var EntitiesRenderManager;
9116
9201
  * @returns
9117
9202
  */
9118
9203
  const register = (thing) => {
9119
- var _a, _b, _c, _d, _e, _f;
9204
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
9120
9205
  // See if the cesium entity already exists in a group.
9121
9206
  let group = groups.find((x) => { var _a; return ((_a = x.visual) === null || _a === void 0 ? void 0 : _a.id) == thing.id || x.siblings.find(x => (x === null || x === void 0 ? void 0 : x.id) == thing.id); });
9122
9207
  if (group) {
@@ -9160,8 +9245,14 @@ var EntitiesRenderManager;
9160
9245
  cdn: this.item.cdnEnabled,
9161
9246
  collection: source.entities,
9162
9247
  outline: (_f = (_e = group.data) === null || _e === void 0 ? void 0 : _e.Bruce) === null || _f === void 0 ? void 0 : _f.Outline,
9248
+ internalId: (_j = (_h = (_g = group.data) === null || _g === void 0 ? void 0 : _g.Bruce) === null || _h === void 0 ? void 0 : _h.InternalID) !== null && _j !== void 0 ? _j : undefined,
9163
9249
  };
9164
9250
  group.rego = rego;
9251
+ const groupInternalId = (_l = (_k = group.data) === null || _k === void 0 ? void 0 : _k.Bruce) === null || _l === void 0 ? void 0 : _l.InternalID;
9252
+ if (groupInternalId != null) {
9253
+ this.renderedByInternalId.set(groupInternalId, entityId);
9254
+ this.internalByEntityId.set(entityId, groupInternalId);
9255
+ }
9165
9256
  this.visualsManager.AddRego({
9166
9257
  rego,
9167
9258
  requestRender: false
@@ -9205,7 +9296,7 @@ var EntitiesRenderManager;
9205
9296
  * @returns
9206
9297
  */
9207
9298
  async renderAsIndividuals(entities, force = false) {
9208
- var _a, _b, _c, _d, _e, _f;
9299
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
9209
9300
  // When live we just want to show the latest pos.
9210
9301
  // When not live, the user might scroll the timeline and want to see it a fluid animation between points in time.
9211
9302
  const isLive = ViewUtils.GetTimeDetails({
@@ -9259,13 +9350,25 @@ var EntitiesRenderManager;
9259
9350
  const id = entity.Bruce.ID;
9260
9351
  const cEntity = cEntities.get(id);
9261
9352
  this.renderedEntities[id] = !!cEntity;
9353
+ const internalId = (_c = entity.Bruce) === null || _c === void 0 ? void 0 : _c.InternalID;
9354
+ if (cEntity && internalId != null) {
9355
+ this.renderedByInternalId.set(internalId, id);
9356
+ this.internalByEntityId.set(id, internalId);
9357
+ }
9358
+ else if (!cEntity) {
9359
+ const knownInternalId = this.internalByEntityId.get(id);
9360
+ if (knownInternalId != null) {
9361
+ this.renderedByInternalId.delete(knownInternalId);
9362
+ this.internalByEntityId.delete(id);
9363
+ }
9364
+ }
9262
9365
  if (cEntity) {
9263
9366
  const rego = this.visualsManager.GetRego({
9264
9367
  entityId: id,
9265
9368
  menuItemId: this.item.id
9266
9369
  });
9267
9370
  // The baseline data source must be editable.
9268
- const canEdit = !((_c = entity.Bruce.Outline) === null || _c === void 0 ? void 0 : _c.find(x => x.Baseline && !x.Editable));
9371
+ const canEdit = !((_d = entity.Bruce.Outline) === null || _d === void 0 ? void 0 : _d.find(x => x.Baseline && !x.Editable));
9269
9372
  const visual = rego === null || rego === void 0 ? void 0 : rego.visual;
9270
9373
  if (!visual || visual != cEntity) {
9271
9374
  const wasClustered = this.clustering ? this.clustering.AddEntity(id, cEntity, false) : false;
@@ -9284,7 +9387,8 @@ var EntitiesRenderManager;
9284
9387
  overrideShow: wasClustered ? false : null,
9285
9388
  name: cEntity.name,
9286
9389
  cdn: this.item.cdnEnabled,
9287
- outline: entity.Bruce.Outline
9390
+ outline: entity.Bruce.Outline,
9391
+ internalId: (_f = (_e = entity.Bruce) === null || _e === void 0 ? void 0 : _e.InternalID) !== null && _f !== void 0 ? _f : undefined,
9288
9392
  };
9289
9393
  this.visualsManager.AddRego({
9290
9394
  rego,
@@ -9296,10 +9400,11 @@ var EntitiesRenderManager;
9296
9400
  rego.visual = cEntity;
9297
9401
  rego.entityTypeId = entity.Bruce["EntityType.ID"];
9298
9402
  rego.tagIds = entity.Bruce["Layer.ID"] ? [].concat(entity.Bruce["Layer.ID"]) : [];
9299
- rego.outline = (_d = entity.Bruce) === null || _d === void 0 ? void 0 : _d.Outline;
9403
+ rego.outline = (_g = entity.Bruce) === null || _g === void 0 ? void 0 : _g.Outline;
9300
9404
  rego.cdn = this.item.cdnEnabled;
9301
- rego.schema = (_e = entity.Bruce) === null || _e === void 0 ? void 0 : _e.Schema;
9405
+ rego.schema = (_h = entity.Bruce) === null || _h === void 0 ? void 0 : _h.Schema;
9302
9406
  rego.canEdit = canEdit;
9407
+ rego.internalId = (_k = (_j = entity.Bruce) === null || _j === void 0 ? void 0 : _j.InternalID) !== null && _k !== void 0 ? _k : rego.internalId;
9303
9408
  // Marked as stale meaning some change was performed that requires a refresh.
9304
9409
  // This usually means a new sibling was added that we need to update.
9305
9410
  if (rego.stale) {
@@ -9329,7 +9434,7 @@ var EntitiesRenderManager;
9329
9434
  menuItemId: this.item.id,
9330
9435
  requestRender: false
9331
9436
  });
9332
- (_f = this.clustering) === null || _f === void 0 ? void 0 : _f.RemoveEntity(id, false);
9437
+ (_l = this.clustering) === null || _l === void 0 ? void 0 : _l.RemoveEntity(id, false);
9333
9438
  }
9334
9439
  }
9335
9440
  this.viewer.scene.requestRender();
@@ -11382,6 +11487,14 @@ class TilesetStyler {
11382
11487
  // Entity ID -> styled status.
11383
11488
  // Helps us emit progress events.
11384
11489
  this.styledEntityIds = new Map();
11490
+ // InternalID to Entity ID for Styled Tileset Entities.
11491
+ // Populated when Entity data is available in styleTilesetFeatureFullData.
11492
+ this.styledByInternalId = new Map();
11493
+ // Cleanup function for the RecordChangeFeed subscription.
11494
+ this.feedSub = null;
11495
+ // Entity IDs waiting for a throttled re-style pass (1s rate limit).
11496
+ this.feedPendingRestyleIds = new Set();
11497
+ this.feedRestyleThrottleTimer = null;
11385
11498
  // % progress for how many Entities have been styled so far.
11386
11499
  // This can change as Tiles load in and more queue.
11387
11500
  this._styleProgress = 0;
@@ -11401,7 +11514,7 @@ class TilesetStyler {
11401
11514
  return this._styleProgress;
11402
11515
  }
11403
11516
  Init(params) {
11404
- var _a;
11517
+ var _a, _b;
11405
11518
  let { viewer, api, cTileset, fallbackStyleId, styleMapping, expandSources, menuItemId, register, scenario, historic } = params;
11406
11519
  this.viewer = viewer;
11407
11520
  this.api = api;
@@ -11457,6 +11570,37 @@ class TilesetStyler {
11457
11570
  });
11458
11571
  this.loaded = true;
11459
11572
  this.loadStyles();
11573
+ const feed = (_b = this.api) === null || _b === void 0 ? void 0 : _b.RecordChangeFeed;
11574
+ if (feed) {
11575
+ this.feedSub = feed.Subscribe({
11576
+ concepts: [AccountConcept.EConcept.ENTITY],
11577
+ actions: ["U"]
11578
+ }, (event) => {
11579
+ if (!this.styledByInternalId.size || !this.entityGatherer) {
11580
+ return;
11581
+ }
11582
+ const rangeStr = typeof event.data === "string" ? event.data : "";
11583
+ if (!rangeStr) {
11584
+ return;
11585
+ }
11586
+ for (const [internalId, entityId] of this.styledByInternalId) {
11587
+ if (RecordChangeFeed.isEntityInternalIdInRangeString(rangeStr, internalId)) {
11588
+ this.feedPendingRestyleIds.add(entityId);
11589
+ }
11590
+ }
11591
+ if (this.feedPendingRestyleIds.size && !this.feedRestyleThrottleTimer) {
11592
+ this.feedRestyleThrottleTimer = setTimeout(() => {
11593
+ this.feedRestyleThrottleTimer = null;
11594
+ if (this.disposed || !this.feedPendingRestyleIds.size || !this.entityGatherer) {
11595
+ return;
11596
+ }
11597
+ const ids = [...this.feedPendingRestyleIds];
11598
+ this.feedPendingRestyleIds.clear();
11599
+ this.entityGatherer.Queue(ids, true);
11600
+ }, 1000);
11601
+ }
11602
+ });
11603
+ }
11460
11604
  }
11461
11605
  /**
11462
11606
  * Updates style mapping and fallback style.
@@ -11609,11 +11753,19 @@ class TilesetStyler {
11609
11753
  });
11610
11754
  }
11611
11755
  Dispose() {
11756
+ var _a;
11612
11757
  if (this.disposed) {
11613
11758
  return;
11614
11759
  }
11615
11760
  this.disposed = true;
11616
11761
  this._styleProgressQueue.Dispose();
11762
+ (_a = this.feedSub) === null || _a === void 0 ? void 0 : _a.call(this);
11763
+ this.feedSub = null;
11764
+ if (this.feedRestyleThrottleTimer) {
11765
+ clearTimeout(this.feedRestyleThrottleTimer);
11766
+ this.feedRestyleThrottleTimer = null;
11767
+ }
11768
+ this.feedPendingRestyleIds.clear();
11617
11769
  this.disposeGatherer();
11618
11770
  }
11619
11771
  async loadStyles() {
@@ -11789,6 +11941,12 @@ class TilesetStyler {
11789
11941
  }
11790
11942
  }
11791
11943
  disposeGatherer() {
11944
+ if (this.feedRestyleThrottleTimer) {
11945
+ clearTimeout(this.feedRestyleThrottleTimer);
11946
+ this.feedRestyleThrottleTimer = null;
11947
+ }
11948
+ this.feedPendingRestyleIds.clear();
11949
+ this.styledByInternalId.clear();
11792
11950
  if (this.entityGatherer) {
11793
11951
  this.entityGatherer.Dispose();
11794
11952
  this.entityGatherer = null;
@@ -11851,7 +12009,7 @@ class TilesetStyler {
11851
12009
  this.styleTilesetFeatureFullData(rego, null, []);
11852
12010
  }
11853
12011
  styleTilesetFeatureFullData(rego, data, tags) {
11854
- var _a, _b;
12012
+ var _a, _b, _c;
11855
12013
  const visual = rego.visual;
11856
12014
  if (!visual || !(visual instanceof Cesium3DTileFeature)) {
11857
12015
  return;
@@ -11873,6 +12031,10 @@ class TilesetStyler {
11873
12031
  override: override
11874
12032
  });
11875
12033
  this.overrideFeatureColor.set(rego.entityId, true);
12034
+ if (((_b = data === null || data === void 0 ? void 0 : data.Bruce) === null || _b === void 0 ? void 0 : _b.InternalID) != null) {
12035
+ rego.internalId = data.Bruce.InternalID;
12036
+ this.styledByInternalId.set(data.Bruce.InternalID, rego.entityId);
12037
+ }
11876
12038
  this.styledEntityIds.set(rego.entityId, true);
11877
12039
  this._styleProgressQueue.Call();
11878
12040
  // Since we only need to update it for scenarios right now.
@@ -11881,7 +12043,7 @@ class TilesetStyler {
11881
12043
  // Update the Entity's rego state.
11882
12044
  let changed = false;
11883
12045
  if (isOutlineChanged(rego, data)) {
11884
- rego.outline = (_b = data === null || data === void 0 ? void 0 : data.Bruce) === null || _b === void 0 ? void 0 : _b.Outline;
12046
+ rego.outline = (_c = data === null || data === void 0 ? void 0 : data.Bruce) === null || _c === void 0 ? void 0 : _c.Outline;
11885
12047
  changed = true;
11886
12048
  }
11887
12049
  // Something changed, trigger a rego update.
@@ -13200,6 +13362,9 @@ var TilesetCadRenderManager;
13200
13362
  else if (lowered === "brucepath") {
13201
13363
  this.featurePropCache.set("brucePath", prop);
13202
13364
  }
13365
+ else if (lowered === "internalid") {
13366
+ this.featurePropCache.set("internalId", prop);
13367
+ }
13203
13368
  }
13204
13369
  }
13205
13370
  /**
@@ -13328,6 +13493,14 @@ var TilesetCadRenderManager;
13328
13493
  }
13329
13494
  }
13330
13495
  }
13496
+ const internalIdProp = this.featurePropCache.get("internalId");
13497
+ if (internalIdProp) {
13498
+ const raw = feature.getProperty(internalIdProp);
13499
+ const parsed = raw != null ? +raw : NaN;
13500
+ if (Number.isInteger(parsed)) {
13501
+ rego.internalId = parsed;
13502
+ }
13503
+ }
13331
13504
  this.loadedCesiumEntities[rego.entityId] = rego;
13332
13505
  this.visualsManager.AddRego({
13333
13506
  rego,
@@ -16536,6 +16709,9 @@ var TilesetEntitiesRenderManager;
16536
16709
  else if (lowered === "building_id" || lowered === "buildingid") {
16537
16710
  this.featurePropCache.set("BuildingID", prop);
16538
16711
  }
16712
+ else if (lowered === "internalid") {
16713
+ this.featurePropCache.set("internalId", prop);
16714
+ }
16539
16715
  }
16540
16716
  }
16541
16717
  Dispose() {
@@ -16646,6 +16822,14 @@ var TilesetEntitiesRenderManager;
16646
16822
  }
16647
16823
  }
16648
16824
  }
16825
+ const internalIdProp = this.featurePropCache.get("internalId");
16826
+ if (internalIdProp) {
16827
+ const raw = feature.getProperty(internalIdProp);
16828
+ const parsed = raw != null ? +raw : NaN;
16829
+ if (Number.isInteger(parsed)) {
16830
+ rego.internalId = parsed;
16831
+ }
16832
+ }
16649
16833
  this.loadedCesiumEntities[rego.entityId] = rego;
16650
16834
  this.visualsManager.AddRego({
16651
16835
  rego,
@@ -36186,7 +36370,7 @@ class WidgetViewBar extends Widget.AWidget {
36186
36370
  }
36187
36371
  }
36188
36372
 
36189
- const VERSION = "6.6.5";
36373
+ const VERSION = "6.6.6";
36190
36374
  /**
36191
36375
  * Updates the environment instance used by bruce-cesium to one specified.
36192
36376
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.