bruce-cesium 6.6.4 → 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.
@@ -2576,609 +2576,845 @@
2576
2576
  CesiumEntityStyler.Unhighlight = Unhighlight;
2577
2577
  })(exports.CesiumEntityStyler || (exports.CesiumEntityStyler = {}));
2578
2578
 
2579
+ function isTurfAvailable() {
2580
+ return window && window.turf != null;
2581
+ }
2579
2582
  /**
2580
- * Utility for rendering parabolas between two points on the map.
2583
+ * Util for simplifying geometry on the fly.
2581
2584
  */
2582
- class CesiumParabola {
2583
- get Disposed() {
2584
- return this.disposed;
2585
- }
2586
- set Hidden(value) {
2587
- this.hidden = value;
2588
- }
2589
- get curPos1() {
2590
- return this.pos1 instanceof Function ? this.pos1() : this.pos1;
2585
+ var SimplifyGeometry;
2586
+ (function (SimplifyGeometry) {
2587
+ /**
2588
+ * Returns the total number of points in the geometry.
2589
+ * @param geometry
2590
+ * @param limit number to count up to before returning.
2591
+ * @returns
2592
+ */
2593
+ function CountPoints(geometry, limit) {
2594
+ let count = 0;
2595
+ const traverse = (geometry) => {
2596
+ if (geometry.MultiGeometry) {
2597
+ for (let i = 0; i < geometry.MultiGeometry.length; i++) {
2598
+ traverse(geometry.MultiGeometry[i]);
2599
+ // Reached the limit, return.
2600
+ if (limit && count >= limit) {
2601
+ return;
2602
+ }
2603
+ }
2604
+ }
2605
+ else if (geometry.Polygon) {
2606
+ for (let i = 0; i < geometry.Polygon.length; i++) {
2607
+ const polygon = geometry.Polygon[i];
2608
+ count += BModels.Geometry.ParsePoints(polygon.LinearRing).length;
2609
+ }
2610
+ }
2611
+ else if (geometry.LineString) {
2612
+ count += BModels.Geometry.ParsePoints(geometry.LineString).length;
2613
+ }
2614
+ else if (geometry.Point) {
2615
+ count += 1;
2616
+ }
2617
+ };
2618
+ traverse(geometry);
2619
+ return count;
2591
2620
  }
2592
- get curPos2() {
2593
- return this.pos2 instanceof Function ? this.pos2() : this.pos2;
2621
+ SimplifyGeometry.CountPoints = CountPoints;
2622
+ /**
2623
+ * Simplifies input geometry.
2624
+ * This will turn it into GeoJSON, run it through turf, then back to Bruce geometry.
2625
+ * @param geometry
2626
+ */
2627
+ function Simplify(entityId, geometry, tolerance) {
2628
+ var _a;
2629
+ if (!geometry || !isTurfAvailable() || !turf.simplify) {
2630
+ return geometry;
2631
+ }
2632
+ // Convert to geojson so that we can interact with turf.
2633
+ const gFeature = BModels.Geometry.ToGeoJsonFeature({
2634
+ geometry: geometry
2635
+ });
2636
+ // Unkink the geometry.
2637
+ // This removes overlapping polygons before we start merging and simplifying.
2638
+ // Commented out because it has crashes and doesn't handle holes.
2639
+ untangleFeature(gFeature);
2640
+ // Union the geometry.
2641
+ // This merges overlapping polygons.
2642
+ unionFeature(gFeature);
2643
+ // Simplify the geometry.
2644
+ if (tolerance > 0) {
2645
+ gFeature.geometry = turf.simplify(gFeature.geometry, {
2646
+ tolerance: tolerance,
2647
+ highQuality: true,
2648
+ mutate: true
2649
+ });
2650
+ }
2651
+ // Converting back to Bruce geometry.
2652
+ geometry = (_a = BModels.Geometry.FromGeoJson({
2653
+ geoJson: gFeature
2654
+ })) === null || _a === void 0 ? void 0 : _a.geometry;
2655
+ return geometry;
2594
2656
  }
2595
- constructor(params) {
2596
- this.disposed = false;
2597
- this.color = "white";
2598
- this.width = 2;
2599
- this.duration = 10;
2600
- this.heightDistanceRatio = 0.25;
2601
- this.curPoints = [];
2602
- this.animateInterval = null;
2603
- this.retryTimeout = null;
2604
- this.hidden = false;
2605
- this.viewer = params.viewer;
2606
- this.pos1 = params.pos1;
2607
- this.pos2 = params.pos2;
2608
- if (params.color) {
2609
- this.color = params.color;
2657
+ SimplifyGeometry.Simplify = Simplify;
2658
+ })(SimplifyGeometry || (SimplifyGeometry = {}));
2659
+ /**
2660
+ * Runs through all found polygons and runs unkink through turf on them.
2661
+ * @param feature
2662
+ */
2663
+ function untangleFeature(feature) {
2664
+ // Collection to add to because the result might be multiple from an unkink.
2665
+ const collection = {
2666
+ geometries: [],
2667
+ type: "GeometryCollection"
2668
+ };
2669
+ // Runs a dedupe and unkink on the coordinates.
2670
+ // Returns if the coordinates were added to the collection.
2671
+ const processCoordinates = (coords) => {
2672
+ try {
2673
+ // Dedupe the coordinates to avoid issues with unkink.
2674
+ coords = dedupeCoordinates(coords);
2675
+ const outer = [];
2676
+ let inner = [];
2677
+ // We'll unkink each ring separately as this is killing the holes when it is done as a whole.
2678
+ // So we'll do it separate then recombine.
2679
+ for (let i = 0; i < coords.length; i++) {
2680
+ const ring = coords[i];
2681
+ const unkink = turf.unkinkPolygon({
2682
+ type: "Polygon",
2683
+ coordinates: [ring]
2684
+ });
2685
+ if (unkink.type == "FeatureCollection") {
2686
+ let target = i == 0 ? outer : inner;
2687
+ for (let j = 0; j < unkink.features.length; j++) {
2688
+ const unkinked = unkink.features[j].geometry.coordinates;
2689
+ if (unkinked.length > 0) {
2690
+ target.push(unkinked[0]);
2691
+ }
2692
+ }
2693
+ }
2694
+ else {
2695
+ console.error("Unexpected unkink result.", unkink);
2696
+ }
2697
+ }
2698
+ // Recreate the rings and reapply to the collection.
2699
+ if (outer.length > 0) {
2700
+ const combinedCoords = [outer[0]];
2701
+ for (let i = 0; i < inner.length; i++) {
2702
+ combinedCoords.push(inner[i]);
2703
+ }
2704
+ // Add the combined coordinates to the collection
2705
+ const polygon = {
2706
+ type: "Polygon",
2707
+ coordinates: combinedCoords
2708
+ };
2709
+ // Ensure right-hand rule is followed.
2710
+ ensureRightHandRule(polygon);
2711
+ // Add to the collection.
2712
+ collection.geometries.push(polygon);
2713
+ return true;
2714
+ }
2610
2715
  }
2611
- if (!isNaN(params.width)) {
2612
- this.width = params.width;
2716
+ catch (e) {
2717
+ // console.error("Failed to unkink polygon.", e);
2613
2718
  }
2614
- if (!isNaN(params.duration)) {
2615
- this.duration = params.duration;
2719
+ return false;
2720
+ };
2721
+ const processGeometry = (geometry) => {
2722
+ let added = false;
2723
+ if (geometry.type == "Polygon") {
2724
+ added = processCoordinates(geometry.coordinates);
2616
2725
  }
2617
- if (!isNaN(params.heightDistanceRatio)) {
2618
- this.heightDistanceRatio = params.heightDistanceRatio;
2726
+ else if (geometry.type == "MultiPolygon") {
2727
+ for (let i = 0; i < geometry.coordinates.length; i++) {
2728
+ added = processCoordinates(geometry.coordinates[i]) || added;
2729
+ }
2619
2730
  }
2620
- this.prepareEntities();
2731
+ if (!added) {
2732
+ // Adding original since we can't unkink it.
2733
+ collection.geometries.push(geometry);
2734
+ }
2735
+ };
2736
+ if (feature.geometry.type == "GeometryCollection") {
2737
+ feature.geometry.geometries.forEach((geometry) => {
2738
+ processGeometry(geometry);
2739
+ });
2621
2740
  }
2622
- prepareEntities() {
2623
- const parabola = new Cesium.Entity({
2624
- polyline: {
2625
- positions: new Cesium.CallbackProperty(() => {
2626
- return this.curPoints;
2627
- }, false),
2628
- width: this.width,
2629
- material: Cesium.Color.fromCssColorString(this.color),
2630
- show: new Cesium.CallbackProperty(() => {
2631
- return !this.hidden;
2632
- }, false)
2741
+ else {
2742
+ processGeometry(feature.geometry);
2743
+ }
2744
+ // Re-assign the geometry.
2745
+ if (collection.geometries.length == 1) {
2746
+ feature.geometry = collection.geometries[0];
2747
+ }
2748
+ else {
2749
+ feature.geometry = collection;
2750
+ }
2751
+ }
2752
+ /**
2753
+ * Runs through all found polygons and unions them using turf.
2754
+ * Failed unions are ignored and the original is kept.
2755
+ * @param feature
2756
+ */
2757
+ function unionFeature(feature) {
2758
+ // Collection to add to because the result might be multiple from an unkink.
2759
+ const collection = {
2760
+ geometries: [],
2761
+ type: "GeometryCollection"
2762
+ };
2763
+ // We'll turn each geometry into a feature and union them.
2764
+ const tmpCollection = {
2765
+ features: [],
2766
+ type: "FeatureCollection"
2767
+ };
2768
+ if (feature.geometry.type == "GeometryCollection") {
2769
+ feature.geometry.geometries.forEach((geometry) => {
2770
+ if (geometry.type == "Polygon") {
2771
+ tmpCollection.features.push({
2772
+ type: "Feature",
2773
+ geometry: geometry,
2774
+ properties: {}
2775
+ });
2633
2776
  }
2634
- });
2635
- const p1Entity = new Cesium.Entity({
2636
- position: new Cesium.CallbackProperty(() => {
2637
- return this.curPoints.length ? this.curPoints[0] : new Cesium.Cartesian3();
2638
- }, false),
2639
- point: {
2640
- heightReference: Cesium.HeightReference.NONE,
2641
- pixelSize: this.width * 1.3,
2642
- color: Cesium.Color.fromCssColorString(this.color),
2643
- outlineColor: Cesium.Color.WHITE,
2644
- outlineWidth: 2,
2645
- show: new Cesium.CallbackProperty(() => {
2646
- return !this.hidden;
2647
- }, false)
2777
+ else if (geometry.type == "MultiPolygon") {
2778
+ for (let i = 0; i < geometry.coordinates.length; i++) {
2779
+ tmpCollection.features.push({
2780
+ type: "Feature",
2781
+ geometry: {
2782
+ type: "Polygon",
2783
+ coordinates: geometry.coordinates[i]
2784
+ },
2785
+ properties: {}
2786
+ });
2787
+ }
2648
2788
  }
2649
- });
2650
- const p2Entity = new Cesium.Entity({
2651
- position: new Cesium.CallbackProperty(() => {
2652
- return this.curPoints.length ? this.curPoints[this.curPoints.length - 1] : new Cesium.Cartesian3();
2653
- }, false),
2654
- point: {
2655
- heightReference: Cesium.HeightReference.NONE,
2656
- pixelSize: this.width * 1.8,
2657
- color: Cesium.Color.fromCssColorString(this.color),
2658
- outlineColor: Cesium.Color.WHITE,
2659
- outlineWidth: 2,
2660
- show: new Cesium.CallbackProperty(() => {
2661
- return !this.hidden;
2662
- }, false)
2789
+ // Only focusing on polygons.
2790
+ else {
2791
+ collection.geometries.push(geometry);
2663
2792
  }
2664
2793
  });
2665
- p1Entity.parent = parabola;
2666
- p2Entity.parent = parabola;
2667
- const siblings = [p1Entity, p2Entity];
2668
- this.parabola = parabola;
2669
- this.siblings = siblings;
2670
- // The parabola is hidden while this entity is not added.
2671
- // If we avoid adding it now, then the parent can control if the parabola is visible at first or not.
2672
- // this.viewer.entities.add(this.parabola);
2673
- this.viewer.entities.add(p1Entity);
2674
- this.viewer.entities.add(p2Entity);
2675
2794
  }
2676
- Animate() {
2677
- if (this.disposed) {
2678
- return null;
2795
+ else if (feature.geometry.type == "Polygon") {
2796
+ tmpCollection.features.push({
2797
+ type: "Feature",
2798
+ geometry: feature.geometry,
2799
+ properties: {}
2800
+ });
2801
+ }
2802
+ else if (feature.geometry.type == "MultiPolygon") {
2803
+ for (let i = 0; i < feature.geometry.coordinates.length; i++) {
2804
+ tmpCollection.features.push({
2805
+ type: "Feature",
2806
+ geometry: {
2807
+ type: "Polygon",
2808
+ coordinates: feature.geometry.coordinates[i]
2809
+ },
2810
+ properties: {}
2811
+ });
2679
2812
  }
2680
- let retry = false;
2681
- if (!this.curPos1 || !this.curPos2 || !BModels.Cartes.ValidateCartes3(this.curPos1) || !BModels.Cartes.ValidateCartes3(this.curPos2)) {
2682
- retry = true;
2813
+ }
2814
+ // No polygons to union.
2815
+ // Need at least 2 to union.
2816
+ if (tmpCollection.features.length < 2) {
2817
+ return;
2818
+ }
2819
+ // Now we'll union them.
2820
+ try {
2821
+ const union = turf.union(tmpCollection);
2822
+ if (union.geometry.type == "Polygon") {
2823
+ collection.geometries.push(union.geometry);
2683
2824
  }
2684
- let TOTAL_LENGTH = retry ? 0 : Cesium.Cartesian3.distance(this.curPos1, this.curPos2);
2685
- if (TOTAL_LENGTH <= 0) {
2686
- retry = true;
2825
+ else if (union.geometry.type == "MultiPolygon") {
2826
+ for (let i = 0; i < union.geometry.coordinates.length; i++) {
2827
+ collection.geometries.push({
2828
+ type: "Polygon",
2829
+ coordinates: union.geometry.coordinates[i]
2830
+ });
2831
+ }
2687
2832
  }
2688
- if (retry) {
2689
- this.retryTimeout = setTimeout(() => {
2690
- this.Animate();
2691
- }, 2000);
2692
- return {
2693
- parabola: this.parabola,
2694
- siblings: this.siblings
2695
- };
2833
+ else {
2834
+ // Returning early because the result is unexpected.
2835
+ return;
2696
2836
  }
2697
- const RATE_PER_SECOND = 1000 / 40;
2698
- const SEC_DURATION = this.duration;
2699
- const HEIGHT_DISTANCE_RATIO = this.heightDistanceRatio;
2700
- let TOTAL_POINTS = null;
2701
- let POINT_LENGTH = null;
2702
- let TICK_LENGTH_INC = null;
2703
- // Updates TOTAL_POINTS, POINT_LENGTH, and TICK_LENGTH_INC based on current TOTAL_LENGTH and camera position.
2704
- // We want less points the further away the camera is.
2705
- const updateParams = () => {
2706
- var _a, _b;
2707
- // TODO: Do distance to parabola line instead.
2708
- const MIN_POINTS = 30;
2709
- let totalPoints = 80;
2710
- let cameraHeight = (_b = (_a = this.viewer.camera) === null || _a === void 0 ? void 0 : _a.positionCartographic) === null || _b === void 0 ? void 0 : _b.height;
2711
- if (isNaN(cameraHeight) || cameraHeight >= 100000) {
2712
- totalPoints = MIN_POINTS;
2713
- }
2714
- else if (cameraHeight >= 10000) {
2715
- totalPoints = 50;
2716
- }
2717
- else if (cameraHeight >= 1000) {
2718
- totalPoints = 80;
2719
- }
2720
- else if (cameraHeight >= 100) {
2721
- totalPoints = 100;
2722
- }
2723
- TOTAL_POINTS = Math.max(MIN_POINTS, Math.min(totalPoints, TOTAL_LENGTH * 0.1));
2724
- POINT_LENGTH = TOTAL_LENGTH / TOTAL_POINTS;
2725
- TICK_LENGTH_INC = SEC_DURATION == 0 ? TOTAL_LENGTH : TOTAL_POINTS / (RATE_PER_SECOND * SEC_DURATION);
2726
- };
2727
- updateParams();
2728
- let curPoint = 0;
2729
- let quadraticKey = null;
2730
- let quadratic = null;
2731
- let quadraticPreparing = false;
2732
- const prepareQuadratic = async () => {
2733
- if (quadraticPreparing) {
2734
- return;
2735
- }
2736
- quadraticPreparing = true;
2737
- try {
2738
- const p1 = this.curPos1;
2739
- const p2 = this.curPos2;
2740
- if (!p1 || !p2 || !BModels.Cartes.ValidateCartes3(p1) || !BModels.Cartes.ValidateCartes3(p2)) {
2741
- return;
2742
- }
2743
- const height1 = Cesium.Cartographic.fromCartesian(p1).height;
2744
- const height2 = Cesium.Cartographic.fromCartesian(p2).height;
2745
- if (isNaN(height1) || isNaN(height2)) {
2746
- return;
2747
- }
2748
- const totalHeight = height2 + height1;
2749
- const curQuadraticKey = `${height1}-${height2}-${TOTAL_LENGTH}`;
2750
- if (quadraticKey == curQuadraticKey) {
2751
- return;
2752
- }
2753
- const points2d = [
2754
- new Cesium.Cartesian2(0, height1),
2755
- new Cesium.Cartesian2(TOTAL_LENGTH, height2)
2756
- ];
2757
- let vertexHeight = 0;
2758
- // Flat line.
2759
- if (HEIGHT_DISTANCE_RATIO == 0) {
2760
- vertexHeight = totalHeight * 0.5;
2761
- }
2762
- else {
2763
- const largestHeight = Math.max(height1, height2);
2764
- vertexHeight = largestHeight + (TOTAL_LENGTH * HEIGHT_DISTANCE_RATIO);
2765
- }
2766
- points2d.push(new Cesium.Cartesian2(TOTAL_LENGTH * 0.5, vertexHeight));
2767
- const calcQuadratic = (points) => {
2768
- // Swaps position of two rows in matrix.
2769
- function swapRows(matrix, rowAIndex, rowBIndex) {
2770
- const rowAVal = matrix[rowAIndex];
2771
- matrix[rowAIndex] = matrix[rowBIndex];
2772
- matrix[rowBIndex] = rowAVal;
2773
- return matrix;
2774
- }
2775
- // Zeros rowA at colIndex by subtracting a multiplied rowB from it.
2776
- function reduceMatrixRowByRow(matrix, zeroingIndex, parentIndex, colIndex) {
2777
- const zeroRow = matrix[zeroingIndex];
2778
- const parentRow = matrix[parentIndex];
2779
- if (zeroRow[colIndex] == 0) {
2780
- return matrix;
2781
- }
2782
- else if (parentRow[colIndex] == 0) {
2783
- matrix = swapRows(matrix, parentIndex, zeroingIndex);
2784
- return divideMatrixRow(matrix, parentIndex, colIndex);
2785
- }
2786
- // rowAIndex colIndex / rowBIndex colIndex = factor;
2787
- let factor = zeroRow[colIndex] / parentRow[colIndex];
2788
- for (let i = 0; i < zeroRow.length; i++) {
2789
- if (i >= colIndex) {
2790
- zeroRow[i] -= parentRow[i] * factor;
2791
- }
2792
- }
2793
- return matrix;
2794
- }
2795
- // Makes a given row column equal 1 by diving while row by that column.
2796
- function divideMatrixRow(matrix, rowIndex, colIndex) {
2797
- const row = matrix[rowIndex];
2798
- const colValue = row[colIndex];
2799
- for (let i = 0; i < row.length; i++) {
2800
- if (i >= colIndex) {
2801
- row[i] /= colValue;
2802
- }
2803
- }
2804
- return matrix;
2805
- }
2806
- // Returns initial matrix for calculating a, b and c for quadratic formula from given points.
2807
- function matrixFromPoints(points) {
2808
- const rows = [];
2809
- const constructRow = (point) => {
2810
- rows.push([
2811
- -Math.pow(point.x, 2),
2812
- point.x,
2813
- 1,
2814
- point.y
2815
- ]);
2816
- };
2817
- for (let i = 0; i < points.length; i++) {
2818
- constructRow(points[i]);
2819
- }
2820
- return rows;
2821
- }
2822
- const initialMatrix = matrixFromPoints(points);
2823
- const step1Matrix = reduceMatrixRowByRow(initialMatrix, 1, 0, 0);
2824
- const step2Matrix = reduceMatrixRowByRow(step1Matrix, 2, 0, 0);
2825
- const step3Matrix = reduceMatrixRowByRow(step2Matrix, 2, 1, 1);
2826
- const step4Matrix = reduceMatrixRowByRow(step3Matrix, 0, 1, 1);
2827
- const step5Matrix = reduceMatrixRowByRow(step4Matrix, 0, 2, 2);
2828
- const step6Matrix = reduceMatrixRowByRow(step5Matrix, 1, 2, 2);
2829
- const a = step6Matrix[0][3];
2830
- const b = step6Matrix[1][3];
2831
- const c = step6Matrix[2][3];
2832
- return { a: a, b: b, c: c };
2833
- };
2834
- quadratic = calcQuadratic(points2d);
2837
+ }
2838
+ catch (e) {
2839
+ // console.error("Failed to union polygons.", e);
2840
+ return;
2841
+ }
2842
+ // Re-assign the geometry.
2843
+ if (collection.geometries.length == 1) {
2844
+ feature.geometry = collection.geometries[0];
2845
+ }
2846
+ else {
2847
+ feature.geometry = collection;
2848
+ }
2849
+ }
2850
+ function dedupeCoordinates(inputCoords) {
2851
+ return inputCoords.map(ring => {
2852
+ if (ring.length < 2) {
2853
+ return ring;
2854
+ }
2855
+ const dedupeCoords = [];
2856
+ const uniqueCoords = new Set();
2857
+ // Dedupe the points.
2858
+ ring.forEach(coord => {
2859
+ const key = coord.join(',');
2860
+ if (!uniqueCoords.has(key)) {
2861
+ uniqueCoords.add(key);
2862
+ dedupeCoords.push(coord);
2835
2863
  }
2836
- catch (e) {
2837
- console.error(e);
2864
+ });
2865
+ // Make sure the last point matches the first.
2866
+ if (dedupeCoords.length > 1) {
2867
+ if (dedupeCoords[0][0] != dedupeCoords[dedupeCoords.length - 1][0] ||
2868
+ dedupeCoords[0][1] != dedupeCoords[dedupeCoords.length - 1][1]) {
2869
+ dedupeCoords.push(dedupeCoords[0]);
2838
2870
  }
2839
- finally {
2840
- quadraticPreparing = false;
2841
- }
2842
- };
2843
- const getPosition = (increment) => {
2844
- if (!quadratic) {
2845
- return null;
2846
- }
2847
- let lengthAcross = POINT_LENGTH * increment;
2848
- if (lengthAcross > TOTAL_LENGTH) {
2849
- lengthAcross = TOTAL_LENGTH;
2850
- }
2851
- const getParabolaYFromX = (x, quadLetters) => {
2852
- let a = quadLetters.a;
2853
- let b = quadLetters.b;
2854
- let c = quadLetters.c;
2855
- return (-a * Math.pow(x, 2)) + (b * x) + c;
2856
- };
2857
- const { point: pos3d } = exports.DrawingUtils.PointAcrossPolyline({
2858
- viewer: this.viewer,
2859
- distance: lengthAcross,
2860
- posses: [this.curPos1, this.curPos2]
2861
- });
2862
- const point = Cesium.Cartographic.fromCartesian(pos3d);
2863
- const posHeight = getParabolaYFromX(lengthAcross, quadratic);
2864
- return Cesium.Cartesian3.fromRadians(point.longitude, point.latitude, posHeight);
2865
- };
2866
- const updatePoints = () => {
2867
- if (!quadratic) {
2868
- return;
2869
- }
2870
- const increment = Math.floor(curPoint);
2871
- const chips = curPoint - Math.floor(curPoint);
2872
- const posses = [];
2873
- posses.push(getPosition(0));
2874
- const addLast = increment >= TOTAL_POINTS;
2875
- const totalCycles = addLast ? increment + 1 : increment;
2876
- for (let i = 0; i < totalCycles; i++) {
2877
- posses.push(getPosition(i));
2878
- }
2879
- if (chips) {
2880
- posses.push(getPosition(increment + chips));
2881
- }
2882
- if (posses.find(x => !x || !BModels.Cartes.ValidateCartes3(x))) {
2883
- return;
2884
- }
2885
- this.curPoints = posses;
2886
- };
2887
- let lastTickDate = new Date();
2888
- let finished = false;
2889
- const doTick = () => {
2890
- const curDate = new Date();
2891
- const seconds = (curDate.getTime() - lastTickDate.getTime()) / 1000;
2892
- const ticks = seconds * RATE_PER_SECOND;
2893
- if (!isNaN(ticks) && ticks >= 1) {
2894
- lastTickDate = curDate;
2895
- const p1 = this.curPos1;
2896
- const p2 = this.curPos2;
2897
- const newLength = p1 && p2 ? Cesium.Cartesian3.distance(p1, p2) : -1;
2898
- if (newLength > 0 && newLength != TOTAL_LENGTH) {
2899
- TOTAL_LENGTH = newLength;
2900
- updateParams();
2901
- }
2902
- prepareQuadratic();
2903
- if (quadratic) {
2904
- if (curPoint < TOTAL_POINTS) {
2905
- curPoint += (TICK_LENGTH_INC * ticks);
2906
- }
2907
- updatePoints();
2908
- }
2909
- this.viewer.scene.requestRender();
2910
- if (curPoint >= TOTAL_POINTS && !finished) {
2911
- finished = true;
2912
- // We can make the interval update super slow now.
2913
- // We keep it updating in case the positions move.
2914
- clearInterval(this.animateInterval);
2915
- this.animateInterval = setInterval(doTick, 3000);
2916
- }
2917
- }
2918
- };
2919
- this.animateInterval = setInterval(doTick, RATE_PER_SECOND);
2920
- return {
2921
- parabola: this.parabola,
2922
- siblings: this.siblings
2923
- };
2871
+ }
2872
+ return dedupeCoords;
2873
+ });
2874
+ }
2875
+ function ensureRightHandRule(polygon) {
2876
+ // Ensure the outer ring follows the right-hand rule
2877
+ if (polygon.coordinates.length > 0) {
2878
+ const outerRing = polygon.coordinates[0];
2879
+ if (isClockwise(outerRing)) {
2880
+ polygon.coordinates[0] = outerRing.reverse();
2881
+ }
2924
2882
  }
2925
- Dispose() {
2926
- this.disposed = true;
2927
- clearTimeout(this.retryTimeout);
2928
- clearInterval(this.animateInterval);
2929
- const cEntities = [
2930
- this.parabola
2931
- ].concat(this.siblings);
2932
- cEntities.forEach(e => {
2933
- if (e && this.viewer.entities.contains(e)) {
2934
- this.viewer.entities.remove(e);
2935
- }
2936
- });
2883
+ // Ensure any inner rings (holes) follow the right-hand rule
2884
+ for (let i = 1; i < polygon.coordinates.length; i++) {
2885
+ const innerRing = polygon.coordinates[i];
2886
+ if (!isClockwise(innerRing)) {
2887
+ polygon.coordinates[i] = innerRing.reverse();
2888
+ }
2889
+ }
2890
+ }
2891
+ function isClockwise(ring) {
2892
+ let sum = 0;
2893
+ for (let i = 0; i < ring.length - 1; i++) {
2894
+ const p1 = ring[i];
2895
+ const p2 = ring[i + 1];
2896
+ sum += (p2[0] - p1[0]) * (p2[1] + p1[1]);
2937
2897
  }
2898
+ return sum > 0;
2938
2899
  }
2939
2900
 
2940
- function colorToCColor(color) {
2941
- return new Cesium.Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
2901
+ function OnNextCRender(viewer, callback) {
2902
+ const removal = viewer.scene.postRender.addEventListener(() => {
2903
+ removal();
2904
+ callback();
2905
+ });
2942
2906
  }
2943
- async function getStyle(api, typeId, styleId) {
2944
- let style = null;
2945
- if (styleId && styleId != -1) {
2946
- try {
2947
- style = (await BModels.Style.Get({
2948
- api,
2949
- styleId
2950
- })).style;
2951
- }
2952
- // Probably deleted.
2953
- catch (e) {
2954
- console.error(e);
2907
+ function GetCValue(viewer, obj) {
2908
+ if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
2909
+ let date = viewer.scene.lastRenderTime;
2910
+ if (!date) {
2911
+ date = viewer.clock.currentTime;
2955
2912
  }
2913
+ return obj.getValue(date);
2956
2914
  }
2957
- if (!style && typeId) {
2958
- const { entityType: type } = await BModels.EntityType.Get({
2959
- api,
2960
- entityTypeId: typeId
2961
- });
2962
- if (type["DisplaySetting.ID"]) {
2963
- try {
2964
- style = (await BModels.Style.Get({
2965
- api,
2966
- styleId: type["DisplaySetting.ID"]
2967
- })).style;
2968
- }
2969
- catch (e) {
2970
- let hideError = false;
2971
- // TODO: we need a util for extracting code + message rather than writing all this every time.
2972
- if (e && typeof e == "object" && e.ERROR) {
2973
- const error = e.ERROR;
2974
- const code = error && typeof error == "object" ? error.Code : "";
2975
- // Avoiding logging a common error.
2976
- // This happens when rendering entities that don't have records.
2977
- hideError = String(code).toLowerCase() == "notfound";
2978
- }
2979
- if (!hideError) {
2980
- console.error(e);
2981
- }
2982
- }
2915
+ return obj;
2916
+ }
2917
+ function ColorToCColor(color) {
2918
+ return new Cesium.Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
2919
+ }
2920
+ /**
2921
+ * Removes duplicate points in a row and returns a new array.
2922
+ * Passed array is not mutated.
2923
+ * @param posses
2924
+ */
2925
+ function CullDuplicateCPosses(posses) {
2926
+ const newPosses = [];
2927
+ let lastPos = null;
2928
+ for (let i = 0; i < posses.length; i++) {
2929
+ const pos = posses[i];
2930
+ // Avoiding 'Cesium.Cartesian3.equals' because passed data might be just a json blob in certain cases.
2931
+ if (pos && (!lastPos || (pos.x != lastPos.x || pos.y != lastPos.y || pos.z != lastPos.z))) {
2932
+ newPosses.push(pos);
2933
+ lastPos = pos;
2983
2934
  }
2984
2935
  }
2985
- return style;
2936
+ return newPosses;
2986
2937
  }
2987
- var RelationRenderEngine;
2988
- (function (RelationRenderEngine) {
2989
- function GetRenderGroupId(relation) {
2990
- return `${relation["Related.Entity.ID"]}-${relation["Principal.Entity.ID"]}-${relation["Relation.Type.ID"]}`;
2938
+ /**
2939
+ * Returns if the given positions are equal.
2940
+ * @param a
2941
+ * @param b
2942
+ */
2943
+ function CompareCPosses(a, b) {
2944
+ // Same reference.
2945
+ if (a == b) {
2946
+ return true;
2991
2947
  }
2992
- RelationRenderEngine.GetRenderGroupId = GetRenderGroupId;
2993
- async function Render(params) {
2994
- const { apiGetter, viewer, visualRegister, menuItemId, relations } = params;
2995
- const api = apiGetter.getApi(apiGetter.accountId);
2996
- const rendered = {};
2997
- let neededEntityIdsIds = [];
2998
- for (let i = 0; i < relations.length; i++) {
2999
- const relation = relations[i];
3000
- if (relation["Principal.Entity.ID"]) {
3001
- neededEntityIdsIds.push(relation["Principal.Entity.ID"]);
3002
- }
3003
- if (relation["Related.Entity.ID"]) {
3004
- neededEntityIdsIds.push(relation["Related.Entity.ID"]);
3005
- }
3006
- if (relation["Data.Entity.ID"]) {
3007
- neededEntityIdsIds.push(relation["Data.Entity.ID"]);
3008
- }
2948
+ // Different lengths or one is null.
2949
+ if ((!a || !b) || (a.length != b.length)) {
2950
+ return false;
2951
+ }
2952
+ for (let i = 0; i < a.length; i++) {
2953
+ const posA = a[i];
2954
+ const posB = b[i];
2955
+ // Null detected.
2956
+ if (!posA || !posB) {
2957
+ return false;
3009
2958
  }
3010
- // Turn the set unique.
3011
- neededEntityIdsIds = neededEntityIdsIds.filter((v, i, a) => a.indexOf(v) === i);
3012
- // Get all entities in one go.
3013
- let entities = (await BModels.Entity.GetListByIds({
3014
- entityIds: neededEntityIdsIds,
3015
- api: apiGetter.getApi(),
3016
- migrated: true,
3017
- maxSearchTimeSec: 60 * 2
3018
- })).entities;
3019
- // Create a map for quick reference.
3020
- const entitiesMap = {};
3021
- for (let i = 0; i < entities.length; i++) {
3022
- const entity = entities[i];
3023
- entitiesMap[entity.Bruce.ID] = entity;
2959
+ // Position values don't match.
2960
+ if (!BModels.Cartes.IsEqualCartes3(posA, posB)) {
2961
+ return false;
3024
2962
  }
3025
- entities = null;
3026
- // Gather needed relationship types.
3027
- // Right now this means just getting the full list.
3028
- const relationTypes = (await BModels.EntityRelationType.GetList({
3029
- api
3030
- })).relationTypes;
3031
- const relationTypesMap = {};
3032
- for (let i = 0; i < relationTypes.length; i++) {
3033
- const relationType = relationTypes[i];
3034
- relationTypesMap[relationType.ID] = relationType;
2963
+ }
2964
+ return true;
2965
+ }
2966
+ /**
2967
+ * Returns if the given polygon hierarchies are equal.
2968
+ * @param a
2969
+ * @param b
2970
+ */
2971
+ function CompareCPolygonHierarchies(a, b) {
2972
+ // Same reference.
2973
+ if (a == b) {
2974
+ return true;
2975
+ }
2976
+ // Different lengths or one is null.
2977
+ if ((!a || !b) || (a.positions.length != b.positions.length)) {
2978
+ return false;
2979
+ }
2980
+ // Positions don't match.
2981
+ if (!CompareCPosses(a.positions, b.positions)) {
2982
+ return false;
2983
+ }
2984
+ const holes = a.holes;
2985
+ const bHoles = b.holes;
2986
+ // Number of holes don't match.
2987
+ if (holes.length != bHoles.length) {
2988
+ return false;
2989
+ }
2990
+ for (let i = 0; i < holes.length; i++) {
2991
+ // Hole positions don't match.
2992
+ if (!CompareCPosses(holes[i].positions, bHoles[i].positions)) {
2993
+ return false;
3035
2994
  }
3036
- for (let i = 0; i < relations.length; i++) {
3037
- try {
3038
- const relation = relations[i];
3039
- const fromEntity = entitiesMap[relation["Principal.Entity.ID"]];
3040
- const toEntity = entitiesMap[relation["Related.Entity.ID"]];
3041
- const dataEntity = relation["Data.Entity.ID"] ? entitiesMap[relation["Data.Entity.ID"]] : null;
3042
- const relationType = relationTypesMap[relation["Relation.Type.ID"]];
3043
- 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));
3044
- const cEntity = await Parabola.Render({
3045
- dataEntity,
3046
- fromEntity,
3047
- relation,
3048
- style,
3049
- toEntity,
3050
- viewer,
3051
- visualRegister,
3052
- apiGetter
2995
+ }
2996
+ return true;
2997
+ }
2998
+
2999
+ const CESIUM_INSPECTOR_KEY = "_nextspace_inspector";
3000
+ const CESIUM_TIMELINE_KEY = "_nextspace_timeline";
3001
+ const CESIUM_TIMELINE_LIVE_KEY = "_nextspace_timeline_live";
3002
+ const CESIUM_TIMELINE_LIVE_PADDING_KEY = "_nextspace_timeline_live_padding";
3003
+ const CESIUM_TIMELINE_INTERVAL_KEY = "_nextspace_timeline_interval";
3004
+ const CESIUM_MODEL_SPACE_KEY = "_nextspace_model_space";
3005
+ const DEFAULT_LIVE_PADDING_SECONDS = 30 * 60;
3006
+ (function (ViewUtils) {
3007
+ function GatherLegacyMapTiles(params) {
3008
+ const viewer = params.viewer;
3009
+ const collection = viewer.imageryLayers;
3010
+ const tiles = [];
3011
+ for (let i = 0; i < collection.length; i++) {
3012
+ const layer = collection.get(i);
3013
+ if (layer._bName) {
3014
+ tiles.push({
3015
+ alpha: layer.alpha,
3016
+ brightness: layer.brightness,
3017
+ contrast: layer.contrast,
3018
+ hue: layer.hue,
3019
+ saturation: layer.saturation,
3020
+ gamma: layer.gamma,
3021
+ title: layer._bName,
3053
3022
  });
3054
- cEntity._renderGroup = GetRenderGroupId(relation);
3055
- rendered[GetRenderGroupId(relation)] = cEntity;
3056
- }
3057
- catch (e) {
3058
- console.error(e);
3059
3023
  }
3060
3024
  }
3061
- return rendered;
3025
+ return {
3026
+ imagery: tiles.reverse()
3027
+ };
3062
3028
  }
3063
- RelationRenderEngine.Render = Render;
3064
- let Parabola;
3065
- (function (Parabola) {
3066
- async function Render(params) {
3067
- var _a;
3068
- const style = (_a = params.style) === null || _a === void 0 ? void 0 : _a.Settings;
3069
- const entity = params.dataEntity;
3070
- const bColor = (style === null || style === void 0 ? void 0 : style.lineColor) ? BModels.Calculator.GetColor(style === null || style === void 0 ? void 0 : style.lineColor, entity, []) : null;
3071
- const cColor = bColor ? colorToCColor(bColor) : Cesium.Color.WHITE;
3072
- let width = EnsureNumber((style === null || style === void 0 ? void 0 : style.lineWidth) ? BModels.Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.lineWidth, entity, []) : 4, 4);
3073
- if (width < 1) {
3074
- width = 1;
3075
- }
3076
- const duration = EnsureNumber((style === null || style === void 0 ? void 0 : style.duration) ? BModels.Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.duration, entity, []) : 2, 2);
3077
- const hDistanceRatio = EnsureNumber((style === null || style === void 0 ? void 0 : style.heightDistanceRatio) ? BModels.Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.heightDistanceRatio, entity, []) : 0.25, 0.25);
3078
- let fromPos = null;
3079
- let toPos = null;
3080
- let updatingPosses = false;
3081
- const updatePosses = async () => {
3082
- if (updatingPosses) {
3083
- return;
3084
- }
3085
- updatingPosses = true;
3086
- try {
3087
- const fromData = await exports.EntityUtils.GetLocation({
3088
- samples: [{
3089
- entity: params.fromEntity,
3090
- entityId: params.fromEntity.Bruce.ID,
3091
- heightRef: Cesium.HeightReference.CLAMP_TO_GROUND,
3092
- returnHeightRef: Cesium.HeightReference.NONE
3093
- }],
3094
- viewer: params.viewer,
3095
- visualRegister: params.visualRegister,
3096
- api: params.apiGetter.getApi()
3097
- });
3098
- fromPos = fromData.pos3d;
3099
- const toData = await exports.EntityUtils.GetLocation({
3100
- samples: [{
3101
- entity: params.toEntity,
3102
- entityId: params.toEntity.Bruce.ID,
3103
- heightRef: Cesium.HeightReference.CLAMP_TO_GROUND,
3104
- returnHeightRef: Cesium.HeightReference.NONE
3105
- }],
3106
- viewer: params.viewer,
3107
- visualRegister: params.visualRegister,
3108
- api: params.apiGetter.getApi()
3029
+ ViewUtils.GatherLegacyMapTiles = GatherLegacyMapTiles;
3030
+ function GatherLegacyTerrainTile(params) {
3031
+ const viewer = params.viewer;
3032
+ const enabled = viewer.terrainProvider;
3033
+ if (enabled === null || enabled === void 0 ? void 0 : enabled._bName) {
3034
+ return {
3035
+ terrain: enabled._bName
3036
+ };
3037
+ }
3038
+ return {
3039
+ terrain: "flatterrain"
3040
+ };
3041
+ }
3042
+ ViewUtils.GatherLegacyTerrainTile = GatherLegacyTerrainTile;
3043
+ function GatherMapTiles(params) {
3044
+ const viewer = params.viewer;
3045
+ const imagery = viewer.imageryLayers;
3046
+ const tiles = [];
3047
+ for (let i = 0; i < imagery.length; i++) {
3048
+ const provider = imagery.get(i);
3049
+ if (provider._bMeta) {
3050
+ const idCombo = provider._bMeta.accountId + provider._bMeta.tilesetId;
3051
+ if (!tiles.find(x => x.accountId + x.tilesetId === idCombo)) {
3052
+ tiles.push({
3053
+ accountId: provider._bMeta.accountId,
3054
+ tilesetId: provider._bMeta.tilesetId,
3055
+ alpha: provider.alpha,
3056
+ brightness: provider.brightness,
3057
+ contrast: provider.contrast,
3058
+ hue: provider.hue,
3059
+ saturation: provider.saturation,
3060
+ gamma: provider.gamma
3109
3061
  });
3110
- toPos = toData.pos3d;
3111
- }
3112
- catch (e) {
3113
- console.error(e);
3114
3062
  }
3115
- updatingPosses = false;
3116
- };
3117
- updatePosses();
3118
- const parabola = new CesiumParabola({
3119
- viewer: params.viewer,
3120
- pos1: () => fromPos,
3121
- pos2: () => toPos,
3122
- color: cColor.toCssColorString(),
3123
- width: width,
3124
- duration: duration,
3125
- heightDistanceRatio: hDistanceRatio
3126
- });
3127
- parabola.Hidden = true;
3128
- const cEntities = parabola.Animate();
3129
- const cEntity = cEntities.parabola;
3130
- cEntity._siblingGraphics = [];
3131
- for (let i = 0; i < cEntities.siblings.length; i++) {
3132
- const sibling = cEntities.siblings[i];
3133
- cEntity._siblingGraphics.push(sibling);
3134
3063
  }
3135
- let updateInterval = setInterval(() => {
3136
- var _a;
3137
- if (!((_a = params.viewer) === null || _a === void 0 ? void 0 : _a.scene) ||
3138
- params.viewer.isDestroyed() ||
3139
- (!parabola || parabola.Disposed)) {
3140
- clearInterval(updateInterval);
3141
- parabola.Dispose();
3142
- return;
3143
- }
3144
- if (parabola) {
3145
- const visible = cEntity && cEntity.show != false && params.viewer.entities.contains(cEntity);
3146
- parabola.Hidden = !visible;
3147
- }
3148
- updatePosses();
3149
- params.viewer.scene.requestRender();
3150
- }, 1000);
3151
- let disposed = false;
3152
- cEntity._dispose = () => {
3153
- if (disposed) {
3154
- return;
3155
- }
3156
- disposed = true;
3157
- clearInterval(updateInterval);
3158
- if (parabola) {
3159
- parabola.Dispose();
3064
+ }
3065
+ return {
3066
+ imagery: tiles
3067
+ };
3068
+ }
3069
+ ViewUtils.GatherMapTiles = GatherMapTiles;
3070
+ function GatherTerrainTile(params) {
3071
+ const viewer = params.viewer;
3072
+ const provider = viewer.terrainProvider;
3073
+ if (provider === null || provider === void 0 ? void 0 : provider._bMeta) {
3074
+ return {
3075
+ terrain: {
3076
+ accountId: provider._bMeta.accountId,
3077
+ tilesetId: provider._bMeta.tilesetId,
3160
3078
  }
3161
3079
  };
3162
- return cEntity;
3163
3080
  }
3164
- Parabola.Render = Render;
3165
- })(Parabola = RelationRenderEngine.Parabola || (RelationRenderEngine.Parabola = {}));
3166
- })(RelationRenderEngine || (RelationRenderEngine = {}));
3167
-
3168
- /**
3169
- * Returns cesium property's value.
3170
- * This will check if it's one that changes over time, or just a fixed value.
3171
- * Eg: const pos3d = getValue<Cesium.Cartesian3>(cViewer, cEntity.point.position);
3172
- * @param viewer
3173
- * @param obj
3174
- */
3175
- function getValue(viewer, obj) {
3176
- if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
3177
- let date = viewer.scene.lastRenderTime;
3178
- if (!date) {
3179
- date = viewer.clock.currentTime;
3081
+ else if (provider instanceof Cesium.EllipsoidTerrainProvider) {
3082
+ return {
3083
+ terrain: {
3084
+ tilesetId: BModels.ProjectViewTile.EDefaultTerrain.FlatTerrain,
3085
+ accountId: null
3086
+ }
3087
+ };
3180
3088
  }
3181
- return obj.getValue(date);
3089
+ return null;
3090
+ }
3091
+ ViewUtils.GatherTerrainTile = GatherTerrainTile;
3092
+ function SetTerrainWireframeStatus(params) {
3093
+ if (!params.viewer[CESIUM_INSPECTOR_KEY]) {
3094
+ const InspectorClass = Cesium.CesiumInspector;
3095
+ if (InspectorClass) {
3096
+ const inspector = new InspectorClass(document.createElement("div"), params.viewer.scene);
3097
+ inspector.container.style.display = "none";
3098
+ params.viewer[CESIUM_INSPECTOR_KEY] = inspector;
3099
+ params.viewer.scene.requestRender();
3100
+ }
3101
+ }
3102
+ if (params.viewer[CESIUM_INSPECTOR_KEY]) {
3103
+ params.viewer[CESIUM_INSPECTOR_KEY].viewModel.wireframe = params.status;
3104
+ }
3105
+ }
3106
+ ViewUtils.SetTerrainWireframeStatus = SetTerrainWireframeStatus;
3107
+ function GetTerrainWireframeStatus(params) {
3108
+ var _a, _b;
3109
+ if (!params.viewer[CESIUM_INSPECTOR_KEY]) {
3110
+ return false;
3111
+ }
3112
+ return (_b = (_a = params.viewer[CESIUM_INSPECTOR_KEY]) === null || _a === void 0 ? void 0 : _a.viewModel) === null || _b === void 0 ? void 0 : _b.wireframe;
3113
+ }
3114
+ ViewUtils.GetTerrainWireframeStatus = GetTerrainWireframeStatus;
3115
+ /**
3116
+ * Changes between perspective and orthographic view.
3117
+ * When Cesium stops being bad at picking positions in 2d mode we'll use the flat earth mode instead.
3118
+ * @param params
3119
+ */
3120
+ function Set2dStatus(params) {
3121
+ const { viewer, status: is2d, moveCamera } = params;
3122
+ const curLens2d = viewer.camera.frustum instanceof Cesium.OrthographicFrustum;
3123
+ if (curLens2d && !is2d) {
3124
+ OnNextCRender(viewer, () => {
3125
+ viewer.camera.switchToPerspectiveFrustum();
3126
+ viewer.scene.screenSpaceCameraController.enableTilt = true;
3127
+ });
3128
+ viewer.scene.requestRender();
3129
+ }
3130
+ else if (!curLens2d && is2d) {
3131
+ OnNextCRender(viewer, () => {
3132
+ viewer.camera.switchToOrthographicFrustum();
3133
+ viewer.scene.screenSpaceCameraController.enableTilt = false;
3134
+ });
3135
+ if (moveCamera != false) {
3136
+ try {
3137
+ // Face camera downwards to make it look 2d.
3138
+ // We want to try make it look at the center-point of the current view.
3139
+ // If center cannot be calculated then we'll simply raise the camera and face it downwards.
3140
+ const scene = viewer.scene;
3141
+ const windowPosition = new Cesium.Cartesian2(scene.canvas.clientWidth / 2, scene.canvas.clientHeight / 2);
3142
+ const ray = viewer.camera.getPickRay(windowPosition);
3143
+ const intersection = scene.globe.pick(ray, scene);
3144
+ let center;
3145
+ if (Cesium.defined(intersection)) {
3146
+ center = Cesium.Cartographic.fromCartesian(intersection);
3147
+ }
3148
+ // Use current camera position if we can't calculate the center.
3149
+ else {
3150
+ center = Cesium.Cartographic.fromCartesian(viewer.camera.position);
3151
+ center.height = 0;
3152
+ }
3153
+ center.height = viewer.camera.positionCartographic.height + 100;
3154
+ viewer.camera.setView({
3155
+ destination: Cesium.Cartographic.toCartesian(center),
3156
+ orientation: {
3157
+ heading: 0.0,
3158
+ pitch: Cesium.Math.toRadians(-90.0),
3159
+ roll: 0.0
3160
+ }
3161
+ });
3162
+ }
3163
+ catch (e) {
3164
+ console.error(e);
3165
+ }
3166
+ }
3167
+ viewer.scene.requestRender();
3168
+ }
3169
+ }
3170
+ ViewUtils.Set2dStatus = Set2dStatus;
3171
+ function Get2dStatus(params) {
3172
+ const { viewer } = params;
3173
+ return viewer.camera.frustum instanceof Cesium.OrthographicFrustum;
3174
+ }
3175
+ ViewUtils.Get2dStatus = Get2dStatus;
3176
+ function SetLockedCameraStatus(params) {
3177
+ const { viewer, status } = params;
3178
+ const scene = viewer === null || viewer === void 0 ? void 0 : viewer.scene;
3179
+ if (!scene) {
3180
+ return;
3181
+ }
3182
+ if (status) {
3183
+ scene.screenSpaceCameraController.enableInputs = false;
3184
+ scene.screenSpaceCameraController.enableTranslate = false;
3185
+ scene.screenSpaceCameraController.enableZoom = false;
3186
+ scene.screenSpaceCameraController.enableRotate = false;
3187
+ scene.screenSpaceCameraController.enableTilt = false;
3188
+ }
3189
+ else {
3190
+ scene.screenSpaceCameraController.enableInputs = true;
3191
+ scene.screenSpaceCameraController.enableTranslate = true;
3192
+ scene.screenSpaceCameraController.enableZoom = true;
3193
+ scene.screenSpaceCameraController.enableRotate = true;
3194
+ if (!ViewUtils.Get2dStatus({ viewer })) {
3195
+ scene.screenSpaceCameraController.enableTilt = true;
3196
+ }
3197
+ }
3198
+ viewer.scene.requestRender();
3199
+ }
3200
+ ViewUtils.SetLockedCameraStatus = SetLockedCameraStatus;
3201
+ function GetLockedCameraStatus(params) {
3202
+ var _a;
3203
+ const scene = (_a = params.viewer) === null || _a === void 0 ? void 0 : _a.scene;
3204
+ if (!scene) {
3205
+ return false;
3206
+ }
3207
+ return !scene.screenSpaceCameraController.enableTranslate;
3208
+ }
3209
+ ViewUtils.GetLockedCameraStatus = GetLockedCameraStatus;
3210
+ /**
3211
+ * Returns the current camera time and related settings.
3212
+ * @param params
3213
+ * @returns
3214
+ */
3215
+ function GetTimeDetails(params) {
3216
+ const { viewer } = params;
3217
+ const clock = viewer.clock;
3218
+ return {
3219
+ animationSpeed: clock.multiplier,
3220
+ isAnimating: clock.shouldAnimate,
3221
+ startTime: clock.startTime,
3222
+ startTimeIso: clock.startTime.toString(),
3223
+ currentTime: clock.currentTime,
3224
+ currentTimeIso: clock.currentTime.toString(),
3225
+ stopTime: clock.stopTime,
3226
+ stopTimeIso: clock.stopTime.toString(),
3227
+ areCesiumValues: clock[CESIUM_TIMELINE_KEY] != true,
3228
+ isLive: clock[CESIUM_TIMELINE_LIVE_KEY] == true,
3229
+ livePaddingSeconds: clock[CESIUM_TIMELINE_LIVE_PADDING_KEY] || DEFAULT_LIVE_PADDING_SECONDS
3230
+ };
3231
+ }
3232
+ ViewUtils.GetTimeDetails = GetTimeDetails;
3233
+ /**
3234
+ * Sets the Cesium clock values.
3235
+ * If a value is not provided, then 'areCesiumValues' checked to see if the values are Cesium values.
3236
+ * If they're currently Cesium set values then our defaults are used.
3237
+ * @param params
3238
+ */
3239
+ function SetTimeDetails(params) {
3240
+ let { viewer, animationSpeed, isAnimating, startTime, currentTime, stopTime, startTimeIso, stopTimeIso, currentTimeIso, isLive, livePaddingSeconds } = params;
3241
+ const clock = viewer.clock;
3242
+ if (startTime) {
3243
+ clock.startTime = startTime;
3244
+ }
3245
+ else if (startTimeIso) {
3246
+ const startDate = Cesium.JulianDate.fromIso8601(startTimeIso);
3247
+ if (startDate) {
3248
+ clock.startTime = startDate;
3249
+ }
3250
+ }
3251
+ if (currentTime) {
3252
+ clock.currentTime = currentTime;
3253
+ }
3254
+ else if (currentTimeIso) {
3255
+ const currentDate = Cesium.JulianDate.fromIso8601(currentTimeIso);
3256
+ if (currentDate) {
3257
+ clock.currentTime = currentDate;
3258
+ }
3259
+ }
3260
+ if (stopTime) {
3261
+ clock.stopTime = stopTime;
3262
+ }
3263
+ else if (stopTimeIso) {
3264
+ const stopDate = Cesium.JulianDate.fromIso8601(stopTimeIso);
3265
+ if (stopDate) {
3266
+ clock.stopTime = stopDate;
3267
+ }
3268
+ }
3269
+ clock.clockRange = Cesium.ClockRange.LOOP_STOP;
3270
+ const areCesiumValues = clock[CESIUM_TIMELINE_KEY] != true;
3271
+ if (areCesiumValues) {
3272
+ if (isNaN(animationSpeed) || animationSpeed == null) {
3273
+ animationSpeed = 1;
3274
+ }
3275
+ if (isAnimating == null) {
3276
+ isAnimating = false;
3277
+ }
3278
+ if (isLive == null) {
3279
+ isLive = false;
3280
+ }
3281
+ if (livePaddingSeconds == null) {
3282
+ livePaddingSeconds = DEFAULT_LIVE_PADDING_SECONDS;
3283
+ }
3284
+ }
3285
+ if (!isNaN(animationSpeed) && animationSpeed != null) {
3286
+ clock.multiplier = animationSpeed;
3287
+ }
3288
+ if (isAnimating != null) {
3289
+ clock.shouldAnimate = isAnimating;
3290
+ }
3291
+ viewer.scene.requestRender();
3292
+ clock[CESIUM_TIMELINE_KEY] = true;
3293
+ if (livePaddingSeconds != null) {
3294
+ clock[CESIUM_TIMELINE_LIVE_PADDING_KEY] = livePaddingSeconds || DEFAULT_LIVE_PADDING_SECONDS;
3295
+ }
3296
+ if (isLive != null) {
3297
+ clock[CESIUM_TIMELINE_LIVE_KEY] = params.isLive == true;
3298
+ }
3299
+ if (clock[CESIUM_TIMELINE_LIVE_KEY]) {
3300
+ startLive(viewer);
3301
+ }
3302
+ else {
3303
+ stopLive(viewer);
3304
+ }
3305
+ }
3306
+ ViewUtils.SetTimeDetails = SetTimeDetails;
3307
+ function startLive(viewer) {
3308
+ const doUpdate = () => {
3309
+ if (!viewer || viewer.isDestroyed() || !viewer.scene) {
3310
+ stopLive(viewer);
3311
+ return;
3312
+ }
3313
+ // Get the current settings.
3314
+ const tDetails = GetTimeDetails({ viewer });
3315
+ const clock = viewer.clock;
3316
+ if (clock) {
3317
+ clock.shouldAnimate = true;
3318
+ clock.multiplier = 1;
3319
+ clock.currentTime = Cesium.JulianDate.now();
3320
+ clock.startTime = Cesium.JulianDate.addSeconds(clock.currentTime, -tDetails.livePaddingSeconds, new Cesium.JulianDate());
3321
+ clock.stopTime = Cesium.JulianDate.addSeconds(clock.currentTime, tDetails.livePaddingSeconds, new Cesium.JulianDate());
3322
+ clock.clockRange = Cesium.ClockRange.UNBOUNDED;
3323
+ }
3324
+ };
3325
+ if (viewer[CESIUM_TIMELINE_INTERVAL_KEY]) {
3326
+ doUpdate();
3327
+ return;
3328
+ }
3329
+ // We'll start an interval that occasionally updates the Cesium clock to stay in the desired settings.
3330
+ // Since it moves live (1 second per second), we don't have to worry about the ranges being out of date quickly.
3331
+ viewer[CESIUM_TIMELINE_INTERVAL_KEY] = setInterval(() => {
3332
+ doUpdate();
3333
+ }, 800);
3334
+ viewer[CESIUM_TIMELINE_LIVE_KEY] = true;
3335
+ // Initial update.
3336
+ doUpdate();
3337
+ }
3338
+ function stopLive(viewer) {
3339
+ if (!viewer) {
3340
+ return;
3341
+ }
3342
+ let interval = viewer[CESIUM_TIMELINE_INTERVAL_KEY];
3343
+ if (interval) {
3344
+ clearInterval(interval);
3345
+ viewer[CESIUM_TIMELINE_INTERVAL_KEY] = null;
3346
+ }
3347
+ viewer[CESIUM_TIMELINE_LIVE_KEY] = false;
3348
+ }
3349
+ function SetGlobeDetails(params) {
3350
+ let { viewer, hidden, baseColor } = params;
3351
+ const scene = viewer === null || viewer === void 0 ? void 0 : viewer.scene;
3352
+ if (!(scene === null || scene === void 0 ? void 0 : scene.globe)) {
3353
+ return;
3354
+ }
3355
+ if (hidden == null) {
3356
+ hidden = !scene.globe.show;
3357
+ }
3358
+ else {
3359
+ scene.globe.show = !hidden;
3360
+ }
3361
+ if (baseColor == null) {
3362
+ baseColor = scene.globe.baseColor;
3363
+ }
3364
+ // When globe is off, we'll also hide the stars/moon.
3365
+ // We also grab the globe color and apply it to the sky.
3366
+ if (hidden && GetModelSpace(viewer)) {
3367
+ scene.skyBox.show = false;
3368
+ scene.skyAtmosphere.show = false;
3369
+ scene.sun.show = false;
3370
+ scene.moon.show = false;
3371
+ scene.backgroundColor = baseColor.clone();
3372
+ }
3373
+ else {
3374
+ scene.skyBox.show = true;
3375
+ scene.skyAtmosphere.show = true;
3376
+ scene.sun.show = true;
3377
+ scene.moon.show = true;
3378
+ scene.backgroundColor = Cesium.Color.BLACK;
3379
+ }
3380
+ scene.globe.baseColor = baseColor;
3381
+ }
3382
+ ViewUtils.SetGlobeDetails = SetGlobeDetails;
3383
+ function SetModelSpace(viewer, modelSpace) {
3384
+ if (!viewer) {
3385
+ return;
3386
+ }
3387
+ if (viewer[CESIUM_MODEL_SPACE_KEY] === modelSpace) {
3388
+ return;
3389
+ }
3390
+ viewer[CESIUM_MODEL_SPACE_KEY] = modelSpace;
3391
+ // Reload globe since we display it differently between the two modes.
3392
+ SetGlobeDetails({ viewer });
3393
+ }
3394
+ ViewUtils.SetModelSpace = SetModelSpace;
3395
+ function GetModelSpace(viewer) {
3396
+ if (!viewer) {
3397
+ return false;
3398
+ }
3399
+ return Boolean(viewer[CESIUM_MODEL_SPACE_KEY]);
3400
+ }
3401
+ ViewUtils.GetModelSpace = GetModelSpace;
3402
+ })(exports.ViewUtils || (exports.ViewUtils = {}));
3403
+
3404
+ /**
3405
+ * Returns cesium property's value.
3406
+ * This will check if it's one that changes over time, or just a fixed value.
3407
+ * Eg: const pos3d = getValue<Cesium.Cartesian3>(cViewer, cEntity.point.position);
3408
+ * @param viewer
3409
+ * @param obj
3410
+ */
3411
+ function getValue(viewer, obj) {
3412
+ if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
3413
+ let date = viewer.scene.lastRenderTime;
3414
+ if (!date) {
3415
+ date = viewer.clock.currentTime;
3416
+ }
3417
+ return obj.getValue(date);
3182
3418
  }
3183
3419
  return obj;
3184
3420
  }
@@ -3862,508 +4098,594 @@
3862
4098
  EntityLabel.GetLabel = GetLabel;
3863
4099
  })(exports.EntityLabel || (exports.EntityLabel = {}));
3864
4100
 
3865
- function OnNextCRender(viewer, callback) {
3866
- const removal = viewer.scene.postRender.addEventListener(() => {
3867
- removal();
3868
- callback();
3869
- });
3870
- }
3871
- function GetCValue(viewer, obj) {
3872
- if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
3873
- let date = viewer.scene.lastRenderTime;
3874
- if (!date) {
3875
- date = viewer.clock.currentTime;
3876
- }
3877
- return obj.getValue(date);
3878
- }
3879
- return obj;
3880
- }
3881
- function ColorToCColor(color) {
3882
- return new Cesium.Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
3883
- }
3884
4101
  /**
3885
- * Removes duplicate points in a row and returns a new array.
3886
- * Passed array is not mutated.
3887
- * @param posses
4102
+ * Utility for rendering parabolas between two points on the map.
3888
4103
  */
3889
- function CullDuplicateCPosses(posses) {
3890
- const newPosses = [];
3891
- let lastPos = null;
3892
- for (let i = 0; i < posses.length; i++) {
3893
- const pos = posses[i];
3894
- // Avoiding 'Cesium.Cartesian3.equals' because passed data might be just a json blob in certain cases.
3895
- if (pos && (!lastPos || (pos.x != lastPos.x || pos.y != lastPos.y || pos.z != lastPos.z))) {
3896
- newPosses.push(pos);
3897
- lastPos = pos;
3898
- }
4104
+ class CesiumParabola {
4105
+ get Disposed() {
4106
+ return this.disposed;
3899
4107
  }
3900
- return newPosses;
3901
- }
3902
- /**
3903
- * Returns if the given positions are equal.
3904
- * @param a
3905
- * @param b
3906
- */
3907
- function CompareCPosses(a, b) {
3908
- // Same reference.
3909
- if (a == b) {
3910
- return true;
4108
+ set Hidden(value) {
4109
+ this.hidden = value;
3911
4110
  }
3912
- // Different lengths or one is null.
3913
- if ((!a || !b) || (a.length != b.length)) {
3914
- return false;
4111
+ get curPos1() {
4112
+ return this.pos1 instanceof Function ? this.pos1() : this.pos1;
3915
4113
  }
3916
- for (let i = 0; i < a.length; i++) {
3917
- const posA = a[i];
3918
- const posB = b[i];
3919
- // Null detected.
3920
- if (!posA || !posB) {
3921
- return false;
4114
+ get curPos2() {
4115
+ return this.pos2 instanceof Function ? this.pos2() : this.pos2;
4116
+ }
4117
+ constructor(params) {
4118
+ this.disposed = false;
4119
+ this.color = "white";
4120
+ this.width = 2;
4121
+ this.duration = 10;
4122
+ this.heightDistanceRatio = 0.25;
4123
+ this.curPoints = [];
4124
+ this.animateInterval = null;
4125
+ this.retryTimeout = null;
4126
+ this.hidden = false;
4127
+ this.viewer = params.viewer;
4128
+ this.pos1 = params.pos1;
4129
+ this.pos2 = params.pos2;
4130
+ if (params.color) {
4131
+ this.color = params.color;
3922
4132
  }
3923
- // Position values don't match.
3924
- if (!BModels.Cartes.IsEqualCartes3(posA, posB)) {
3925
- return false;
4133
+ if (!isNaN(params.width)) {
4134
+ this.width = params.width;
3926
4135
  }
3927
- }
3928
- return true;
3929
- }
3930
- /**
3931
- * Returns if the given polygon hierarchies are equal.
3932
- * @param a
3933
- * @param b
3934
- */
3935
- function CompareCPolygonHierarchies(a, b) {
3936
- // Same reference.
3937
- if (a == b) {
3938
- return true;
3939
- }
3940
- // Different lengths or one is null.
3941
- if ((!a || !b) || (a.positions.length != b.positions.length)) {
3942
- return false;
3943
- }
3944
- // Positions don't match.
3945
- if (!CompareCPosses(a.positions, b.positions)) {
3946
- return false;
3947
- }
3948
- const holes = a.holes;
3949
- const bHoles = b.holes;
3950
- // Number of holes don't match.
3951
- if (holes.length != bHoles.length) {
3952
- return false;
3953
- }
3954
- for (let i = 0; i < holes.length; i++) {
3955
- // Hole positions don't match.
3956
- if (!CompareCPosses(holes[i].positions, bHoles[i].positions)) {
3957
- return false;
4136
+ if (!isNaN(params.duration)) {
4137
+ this.duration = params.duration;
4138
+ }
4139
+ if (!isNaN(params.heightDistanceRatio)) {
4140
+ this.heightDistanceRatio = params.heightDistanceRatio;
3958
4141
  }
4142
+ this.prepareEntities();
3959
4143
  }
3960
- return true;
3961
- }
3962
-
3963
- const CESIUM_INSPECTOR_KEY = "_nextspace_inspector";
3964
- const CESIUM_TIMELINE_KEY = "_nextspace_timeline";
3965
- const CESIUM_TIMELINE_LIVE_KEY = "_nextspace_timeline_live";
3966
- const CESIUM_TIMELINE_LIVE_PADDING_KEY = "_nextspace_timeline_live_padding";
3967
- const CESIUM_TIMELINE_INTERVAL_KEY = "_nextspace_timeline_interval";
3968
- const CESIUM_MODEL_SPACE_KEY = "_nextspace_model_space";
3969
- const DEFAULT_LIVE_PADDING_SECONDS = 30 * 60;
3970
- (function (ViewUtils) {
3971
- function GatherLegacyMapTiles(params) {
3972
- const viewer = params.viewer;
3973
- const collection = viewer.imageryLayers;
3974
- const tiles = [];
3975
- for (let i = 0; i < collection.length; i++) {
3976
- const layer = collection.get(i);
3977
- if (layer._bName) {
3978
- tiles.push({
3979
- alpha: layer.alpha,
3980
- brightness: layer.brightness,
3981
- contrast: layer.contrast,
3982
- hue: layer.hue,
3983
- saturation: layer.saturation,
3984
- gamma: layer.gamma,
3985
- title: layer._bName,
3986
- });
4144
+ prepareEntities() {
4145
+ const parabola = new Cesium.Entity({
4146
+ polyline: {
4147
+ positions: new Cesium.CallbackProperty(() => {
4148
+ return this.curPoints;
4149
+ }, false),
4150
+ width: this.width,
4151
+ material: Cesium.Color.fromCssColorString(this.color),
4152
+ show: new Cesium.CallbackProperty(() => {
4153
+ return !this.hidden;
4154
+ }, false)
3987
4155
  }
3988
- }
3989
- return {
3990
- imagery: tiles.reverse()
3991
- };
4156
+ });
4157
+ const p1Entity = new Cesium.Entity({
4158
+ position: new Cesium.CallbackProperty(() => {
4159
+ return this.curPoints.length ? this.curPoints[0] : new Cesium.Cartesian3();
4160
+ }, false),
4161
+ point: {
4162
+ heightReference: Cesium.HeightReference.NONE,
4163
+ pixelSize: this.width * 1.3,
4164
+ color: Cesium.Color.fromCssColorString(this.color),
4165
+ outlineColor: Cesium.Color.WHITE,
4166
+ outlineWidth: 2,
4167
+ show: new Cesium.CallbackProperty(() => {
4168
+ return !this.hidden;
4169
+ }, false)
4170
+ }
4171
+ });
4172
+ const p2Entity = new Cesium.Entity({
4173
+ position: new Cesium.CallbackProperty(() => {
4174
+ return this.curPoints.length ? this.curPoints[this.curPoints.length - 1] : new Cesium.Cartesian3();
4175
+ }, false),
4176
+ point: {
4177
+ heightReference: Cesium.HeightReference.NONE,
4178
+ pixelSize: this.width * 1.8,
4179
+ color: Cesium.Color.fromCssColorString(this.color),
4180
+ outlineColor: Cesium.Color.WHITE,
4181
+ outlineWidth: 2,
4182
+ show: new Cesium.CallbackProperty(() => {
4183
+ return !this.hidden;
4184
+ }, false)
4185
+ }
4186
+ });
4187
+ p1Entity.parent = parabola;
4188
+ p2Entity.parent = parabola;
4189
+ const siblings = [p1Entity, p2Entity];
4190
+ this.parabola = parabola;
4191
+ this.siblings = siblings;
4192
+ // The parabola is hidden while this entity is not added.
4193
+ // If we avoid adding it now, then the parent can control if the parabola is visible at first or not.
4194
+ // this.viewer.entities.add(this.parabola);
4195
+ this.viewer.entities.add(p1Entity);
4196
+ this.viewer.entities.add(p2Entity);
3992
4197
  }
3993
- ViewUtils.GatherLegacyMapTiles = GatherLegacyMapTiles;
3994
- function GatherLegacyTerrainTile(params) {
3995
- const viewer = params.viewer;
3996
- const enabled = viewer.terrainProvider;
3997
- if (enabled === null || enabled === void 0 ? void 0 : enabled._bName) {
3998
- return {
3999
- terrain: enabled._bName
4000
- };
4198
+ Animate() {
4199
+ if (this.disposed) {
4200
+ return null;
4001
4201
  }
4002
- return {
4003
- terrain: "flatterrain"
4004
- };
4005
- }
4006
- ViewUtils.GatherLegacyTerrainTile = GatherLegacyTerrainTile;
4007
- function GatherMapTiles(params) {
4008
- const viewer = params.viewer;
4009
- const imagery = viewer.imageryLayers;
4010
- const tiles = [];
4011
- for (let i = 0; i < imagery.length; i++) {
4012
- const provider = imagery.get(i);
4013
- if (provider._bMeta) {
4014
- const idCombo = provider._bMeta.accountId + provider._bMeta.tilesetId;
4015
- if (!tiles.find(x => x.accountId + x.tilesetId === idCombo)) {
4016
- tiles.push({
4017
- accountId: provider._bMeta.accountId,
4018
- tilesetId: provider._bMeta.tilesetId,
4019
- alpha: provider.alpha,
4020
- brightness: provider.brightness,
4021
- contrast: provider.contrast,
4022
- hue: provider.hue,
4023
- saturation: provider.saturation,
4024
- gamma: provider.gamma
4025
- });
4026
- }
4027
- }
4202
+ let retry = false;
4203
+ if (!this.curPos1 || !this.curPos2 || !BModels.Cartes.ValidateCartes3(this.curPos1) || !BModels.Cartes.ValidateCartes3(this.curPos2)) {
4204
+ retry = true;
4028
4205
  }
4029
- return {
4030
- imagery: tiles
4031
- };
4032
- }
4033
- ViewUtils.GatherMapTiles = GatherMapTiles;
4034
- function GatherTerrainTile(params) {
4035
- const viewer = params.viewer;
4036
- const provider = viewer.terrainProvider;
4037
- if (provider === null || provider === void 0 ? void 0 : provider._bMeta) {
4038
- return {
4039
- terrain: {
4040
- accountId: provider._bMeta.accountId,
4041
- tilesetId: provider._bMeta.tilesetId,
4042
- }
4043
- };
4206
+ let TOTAL_LENGTH = retry ? 0 : Cesium.Cartesian3.distance(this.curPos1, this.curPos2);
4207
+ if (TOTAL_LENGTH <= 0) {
4208
+ retry = true;
4044
4209
  }
4045
- else if (provider instanceof Cesium.EllipsoidTerrainProvider) {
4210
+ if (retry) {
4211
+ this.retryTimeout = setTimeout(() => {
4212
+ this.Animate();
4213
+ }, 2000);
4046
4214
  return {
4047
- terrain: {
4048
- tilesetId: BModels.ProjectViewTile.EDefaultTerrain.FlatTerrain,
4049
- accountId: null
4050
- }
4215
+ parabola: this.parabola,
4216
+ siblings: this.siblings
4051
4217
  };
4052
4218
  }
4053
- return null;
4054
- }
4055
- ViewUtils.GatherTerrainTile = GatherTerrainTile;
4056
- function SetTerrainWireframeStatus(params) {
4057
- if (!params.viewer[CESIUM_INSPECTOR_KEY]) {
4058
- const InspectorClass = Cesium.CesiumInspector;
4059
- if (InspectorClass) {
4060
- const inspector = new InspectorClass(document.createElement("div"), params.viewer.scene);
4061
- inspector.container.style.display = "none";
4062
- params.viewer[CESIUM_INSPECTOR_KEY] = inspector;
4063
- params.viewer.scene.requestRender();
4219
+ const RATE_PER_SECOND = 1000 / 40;
4220
+ const SEC_DURATION = this.duration;
4221
+ const HEIGHT_DISTANCE_RATIO = this.heightDistanceRatio;
4222
+ let TOTAL_POINTS = null;
4223
+ let POINT_LENGTH = null;
4224
+ let TICK_LENGTH_INC = null;
4225
+ // Updates TOTAL_POINTS, POINT_LENGTH, and TICK_LENGTH_INC based on current TOTAL_LENGTH and camera position.
4226
+ // We want less points the further away the camera is.
4227
+ const updateParams = () => {
4228
+ var _a, _b;
4229
+ // TODO: Do distance to parabola line instead.
4230
+ const MIN_POINTS = 30;
4231
+ let totalPoints = 80;
4232
+ let cameraHeight = (_b = (_a = this.viewer.camera) === null || _a === void 0 ? void 0 : _a.positionCartographic) === null || _b === void 0 ? void 0 : _b.height;
4233
+ if (isNaN(cameraHeight) || cameraHeight >= 100000) {
4234
+ totalPoints = MIN_POINTS;
4064
4235
  }
4065
- }
4066
- if (params.viewer[CESIUM_INSPECTOR_KEY]) {
4067
- params.viewer[CESIUM_INSPECTOR_KEY].viewModel.wireframe = params.status;
4068
- }
4069
- }
4070
- ViewUtils.SetTerrainWireframeStatus = SetTerrainWireframeStatus;
4071
- function GetTerrainWireframeStatus(params) {
4072
- var _a, _b;
4073
- if (!params.viewer[CESIUM_INSPECTOR_KEY]) {
4074
- return false;
4075
- }
4076
- return (_b = (_a = params.viewer[CESIUM_INSPECTOR_KEY]) === null || _a === void 0 ? void 0 : _a.viewModel) === null || _b === void 0 ? void 0 : _b.wireframe;
4077
- }
4078
- ViewUtils.GetTerrainWireframeStatus = GetTerrainWireframeStatus;
4079
- /**
4080
- * Changes between perspective and orthographic view.
4081
- * When Cesium stops being bad at picking positions in 2d mode we'll use the flat earth mode instead.
4082
- * @param params
4083
- */
4084
- function Set2dStatus(params) {
4085
- const { viewer, status: is2d, moveCamera } = params;
4086
- const curLens2d = viewer.camera.frustum instanceof Cesium.OrthographicFrustum;
4087
- if (curLens2d && !is2d) {
4088
- OnNextCRender(viewer, () => {
4089
- viewer.camera.switchToPerspectiveFrustum();
4090
- viewer.scene.screenSpaceCameraController.enableTilt = true;
4091
- });
4092
- viewer.scene.requestRender();
4093
- }
4094
- else if (!curLens2d && is2d) {
4095
- OnNextCRender(viewer, () => {
4096
- viewer.camera.switchToOrthographicFrustum();
4097
- viewer.scene.screenSpaceCameraController.enableTilt = false;
4098
- });
4099
- if (moveCamera != false) {
4100
- try {
4101
- // Face camera downwards to make it look 2d.
4102
- // We want to try make it look at the center-point of the current view.
4103
- // If center cannot be calculated then we'll simply raise the camera and face it downwards.
4104
- const scene = viewer.scene;
4105
- const windowPosition = new Cesium.Cartesian2(scene.canvas.clientWidth / 2, scene.canvas.clientHeight / 2);
4106
- const ray = viewer.camera.getPickRay(windowPosition);
4107
- const intersection = scene.globe.pick(ray, scene);
4108
- let center;
4109
- if (Cesium.defined(intersection)) {
4110
- center = Cesium.Cartographic.fromCartesian(intersection);
4236
+ else if (cameraHeight >= 10000) {
4237
+ totalPoints = 50;
4238
+ }
4239
+ else if (cameraHeight >= 1000) {
4240
+ totalPoints = 80;
4241
+ }
4242
+ else if (cameraHeight >= 100) {
4243
+ totalPoints = 100;
4244
+ }
4245
+ TOTAL_POINTS = Math.max(MIN_POINTS, Math.min(totalPoints, TOTAL_LENGTH * 0.1));
4246
+ POINT_LENGTH = TOTAL_LENGTH / TOTAL_POINTS;
4247
+ TICK_LENGTH_INC = SEC_DURATION == 0 ? TOTAL_LENGTH : TOTAL_POINTS / (RATE_PER_SECOND * SEC_DURATION);
4248
+ };
4249
+ updateParams();
4250
+ let curPoint = 0;
4251
+ let quadraticKey = null;
4252
+ let quadratic = null;
4253
+ let quadraticPreparing = false;
4254
+ const prepareQuadratic = async () => {
4255
+ if (quadraticPreparing) {
4256
+ return;
4257
+ }
4258
+ quadraticPreparing = true;
4259
+ try {
4260
+ const p1 = this.curPos1;
4261
+ const p2 = this.curPos2;
4262
+ if (!p1 || !p2 || !BModels.Cartes.ValidateCartes3(p1) || !BModels.Cartes.ValidateCartes3(p2)) {
4263
+ return;
4264
+ }
4265
+ const height1 = Cesium.Cartographic.fromCartesian(p1).height;
4266
+ const height2 = Cesium.Cartographic.fromCartesian(p2).height;
4267
+ if (isNaN(height1) || isNaN(height2)) {
4268
+ return;
4269
+ }
4270
+ const totalHeight = height2 + height1;
4271
+ const curQuadraticKey = `${height1}-${height2}-${TOTAL_LENGTH}`;
4272
+ if (quadraticKey == curQuadraticKey) {
4273
+ return;
4274
+ }
4275
+ const points2d = [
4276
+ new Cesium.Cartesian2(0, height1),
4277
+ new Cesium.Cartesian2(TOTAL_LENGTH, height2)
4278
+ ];
4279
+ let vertexHeight = 0;
4280
+ // Flat line.
4281
+ if (HEIGHT_DISTANCE_RATIO == 0) {
4282
+ vertexHeight = totalHeight * 0.5;
4283
+ }
4284
+ else {
4285
+ const largestHeight = Math.max(height1, height2);
4286
+ vertexHeight = largestHeight + (TOTAL_LENGTH * HEIGHT_DISTANCE_RATIO);
4287
+ }
4288
+ points2d.push(new Cesium.Cartesian2(TOTAL_LENGTH * 0.5, vertexHeight));
4289
+ const calcQuadratic = (points) => {
4290
+ // Swaps position of two rows in matrix.
4291
+ function swapRows(matrix, rowAIndex, rowBIndex) {
4292
+ const rowAVal = matrix[rowAIndex];
4293
+ matrix[rowAIndex] = matrix[rowBIndex];
4294
+ matrix[rowBIndex] = rowAVal;
4295
+ return matrix;
4111
4296
  }
4112
- // Use current camera position if we can't calculate the center.
4113
- else {
4114
- center = Cesium.Cartographic.fromCartesian(viewer.camera.position);
4115
- center.height = 0;
4297
+ // Zeros rowA at colIndex by subtracting a multiplied rowB from it.
4298
+ function reduceMatrixRowByRow(matrix, zeroingIndex, parentIndex, colIndex) {
4299
+ const zeroRow = matrix[zeroingIndex];
4300
+ const parentRow = matrix[parentIndex];
4301
+ if (zeroRow[colIndex] == 0) {
4302
+ return matrix;
4303
+ }
4304
+ else if (parentRow[colIndex] == 0) {
4305
+ matrix = swapRows(matrix, parentIndex, zeroingIndex);
4306
+ return divideMatrixRow(matrix, parentIndex, colIndex);
4307
+ }
4308
+ // rowAIndex colIndex / rowBIndex colIndex = factor;
4309
+ let factor = zeroRow[colIndex] / parentRow[colIndex];
4310
+ for (let i = 0; i < zeroRow.length; i++) {
4311
+ if (i >= colIndex) {
4312
+ zeroRow[i] -= parentRow[i] * factor;
4313
+ }
4314
+ }
4315
+ return matrix;
4116
4316
  }
4117
- center.height = viewer.camera.positionCartographic.height + 100;
4118
- viewer.camera.setView({
4119
- destination: Cesium.Cartographic.toCartesian(center),
4120
- orientation: {
4121
- heading: 0.0,
4122
- pitch: Cesium.Math.toRadians(-90.0),
4123
- roll: 0.0
4317
+ // Makes a given row column equal 1 by diving while row by that column.
4318
+ function divideMatrixRow(matrix, rowIndex, colIndex) {
4319
+ const row = matrix[rowIndex];
4320
+ const colValue = row[colIndex];
4321
+ for (let i = 0; i < row.length; i++) {
4322
+ if (i >= colIndex) {
4323
+ row[i] /= colValue;
4324
+ }
4124
4325
  }
4125
- });
4126
- }
4127
- catch (e) {
4128
- console.error(e);
4129
- }
4326
+ return matrix;
4327
+ }
4328
+ // Returns initial matrix for calculating a, b and c for quadratic formula from given points.
4329
+ function matrixFromPoints(points) {
4330
+ const rows = [];
4331
+ const constructRow = (point) => {
4332
+ rows.push([
4333
+ -Math.pow(point.x, 2),
4334
+ point.x,
4335
+ 1,
4336
+ point.y
4337
+ ]);
4338
+ };
4339
+ for (let i = 0; i < points.length; i++) {
4340
+ constructRow(points[i]);
4341
+ }
4342
+ return rows;
4343
+ }
4344
+ const initialMatrix = matrixFromPoints(points);
4345
+ const step1Matrix = reduceMatrixRowByRow(initialMatrix, 1, 0, 0);
4346
+ const step2Matrix = reduceMatrixRowByRow(step1Matrix, 2, 0, 0);
4347
+ const step3Matrix = reduceMatrixRowByRow(step2Matrix, 2, 1, 1);
4348
+ const step4Matrix = reduceMatrixRowByRow(step3Matrix, 0, 1, 1);
4349
+ const step5Matrix = reduceMatrixRowByRow(step4Matrix, 0, 2, 2);
4350
+ const step6Matrix = reduceMatrixRowByRow(step5Matrix, 1, 2, 2);
4351
+ const a = step6Matrix[0][3];
4352
+ const b = step6Matrix[1][3];
4353
+ const c = step6Matrix[2][3];
4354
+ return { a: a, b: b, c: c };
4355
+ };
4356
+ quadratic = calcQuadratic(points2d);
4130
4357
  }
4131
- viewer.scene.requestRender();
4132
- }
4133
- }
4134
- ViewUtils.Set2dStatus = Set2dStatus;
4135
- function Get2dStatus(params) {
4136
- const { viewer } = params;
4137
- return viewer.camera.frustum instanceof Cesium.OrthographicFrustum;
4138
- }
4139
- ViewUtils.Get2dStatus = Get2dStatus;
4140
- function SetLockedCameraStatus(params) {
4141
- const { viewer, status } = params;
4142
- const scene = viewer === null || viewer === void 0 ? void 0 : viewer.scene;
4143
- if (!scene) {
4144
- return;
4145
- }
4146
- if (status) {
4147
- scene.screenSpaceCameraController.enableInputs = false;
4148
- scene.screenSpaceCameraController.enableTranslate = false;
4149
- scene.screenSpaceCameraController.enableZoom = false;
4150
- scene.screenSpaceCameraController.enableRotate = false;
4151
- scene.screenSpaceCameraController.enableTilt = false;
4152
- }
4153
- else {
4154
- scene.screenSpaceCameraController.enableInputs = true;
4155
- scene.screenSpaceCameraController.enableTranslate = true;
4156
- scene.screenSpaceCameraController.enableZoom = true;
4157
- scene.screenSpaceCameraController.enableRotate = true;
4158
- if (!ViewUtils.Get2dStatus({ viewer })) {
4159
- scene.screenSpaceCameraController.enableTilt = true;
4358
+ catch (e) {
4359
+ console.error(e);
4160
4360
  }
4161
- }
4162
- viewer.scene.requestRender();
4163
- }
4164
- ViewUtils.SetLockedCameraStatus = SetLockedCameraStatus;
4165
- function GetLockedCameraStatus(params) {
4166
- var _a;
4167
- const scene = (_a = params.viewer) === null || _a === void 0 ? void 0 : _a.scene;
4168
- if (!scene) {
4169
- return false;
4170
- }
4171
- return !scene.screenSpaceCameraController.enableTranslate;
4172
- }
4173
- ViewUtils.GetLockedCameraStatus = GetLockedCameraStatus;
4174
- /**
4175
- * Returns the current camera time and related settings.
4176
- * @param params
4177
- * @returns
4178
- */
4179
- function GetTimeDetails(params) {
4180
- const { viewer } = params;
4181
- const clock = viewer.clock;
4361
+ finally {
4362
+ quadraticPreparing = false;
4363
+ }
4364
+ };
4365
+ const getPosition = (increment) => {
4366
+ if (!quadratic) {
4367
+ return null;
4368
+ }
4369
+ let lengthAcross = POINT_LENGTH * increment;
4370
+ if (lengthAcross > TOTAL_LENGTH) {
4371
+ lengthAcross = TOTAL_LENGTH;
4372
+ }
4373
+ const getParabolaYFromX = (x, quadLetters) => {
4374
+ let a = quadLetters.a;
4375
+ let b = quadLetters.b;
4376
+ let c = quadLetters.c;
4377
+ return (-a * Math.pow(x, 2)) + (b * x) + c;
4378
+ };
4379
+ const { point: pos3d } = exports.DrawingUtils.PointAcrossPolyline({
4380
+ viewer: this.viewer,
4381
+ distance: lengthAcross,
4382
+ posses: [this.curPos1, this.curPos2]
4383
+ });
4384
+ const point = Cesium.Cartographic.fromCartesian(pos3d);
4385
+ const posHeight = getParabolaYFromX(lengthAcross, quadratic);
4386
+ return Cesium.Cartesian3.fromRadians(point.longitude, point.latitude, posHeight);
4387
+ };
4388
+ const updatePoints = () => {
4389
+ if (!quadratic) {
4390
+ return;
4391
+ }
4392
+ const increment = Math.floor(curPoint);
4393
+ const chips = curPoint - Math.floor(curPoint);
4394
+ const posses = [];
4395
+ posses.push(getPosition(0));
4396
+ const addLast = increment >= TOTAL_POINTS;
4397
+ const totalCycles = addLast ? increment + 1 : increment;
4398
+ for (let i = 0; i < totalCycles; i++) {
4399
+ posses.push(getPosition(i));
4400
+ }
4401
+ if (chips) {
4402
+ posses.push(getPosition(increment + chips));
4403
+ }
4404
+ if (posses.find(x => !x || !BModels.Cartes.ValidateCartes3(x))) {
4405
+ return;
4406
+ }
4407
+ this.curPoints = posses;
4408
+ };
4409
+ let lastTickDate = new Date();
4410
+ let finished = false;
4411
+ const doTick = () => {
4412
+ const curDate = new Date();
4413
+ const seconds = (curDate.getTime() - lastTickDate.getTime()) / 1000;
4414
+ const ticks = seconds * RATE_PER_SECOND;
4415
+ if (!isNaN(ticks) && ticks >= 1) {
4416
+ lastTickDate = curDate;
4417
+ const p1 = this.curPos1;
4418
+ const p2 = this.curPos2;
4419
+ const newLength = p1 && p2 ? Cesium.Cartesian3.distance(p1, p2) : -1;
4420
+ if (newLength > 0 && newLength != TOTAL_LENGTH) {
4421
+ TOTAL_LENGTH = newLength;
4422
+ updateParams();
4423
+ }
4424
+ prepareQuadratic();
4425
+ if (quadratic) {
4426
+ if (curPoint < TOTAL_POINTS) {
4427
+ curPoint += (TICK_LENGTH_INC * ticks);
4428
+ }
4429
+ updatePoints();
4430
+ }
4431
+ this.viewer.scene.requestRender();
4432
+ if (curPoint >= TOTAL_POINTS && !finished) {
4433
+ finished = true;
4434
+ // We can make the interval update super slow now.
4435
+ // We keep it updating in case the positions move.
4436
+ clearInterval(this.animateInterval);
4437
+ this.animateInterval = setInterval(doTick, 3000);
4438
+ }
4439
+ }
4440
+ };
4441
+ this.animateInterval = setInterval(doTick, RATE_PER_SECOND);
4182
4442
  return {
4183
- animationSpeed: clock.multiplier,
4184
- isAnimating: clock.shouldAnimate,
4185
- startTime: clock.startTime,
4186
- startTimeIso: clock.startTime.toString(),
4187
- currentTime: clock.currentTime,
4188
- currentTimeIso: clock.currentTime.toString(),
4189
- stopTime: clock.stopTime,
4190
- stopTimeIso: clock.stopTime.toString(),
4191
- areCesiumValues: clock[CESIUM_TIMELINE_KEY] != true,
4192
- isLive: clock[CESIUM_TIMELINE_LIVE_KEY] == true,
4193
- livePaddingSeconds: clock[CESIUM_TIMELINE_LIVE_PADDING_KEY] || DEFAULT_LIVE_PADDING_SECONDS
4443
+ parabola: this.parabola,
4444
+ siblings: this.siblings
4194
4445
  };
4195
4446
  }
4196
- ViewUtils.GetTimeDetails = GetTimeDetails;
4197
- /**
4198
- * Sets the Cesium clock values.
4199
- * If a value is not provided, then 'areCesiumValues' checked to see if the values are Cesium values.
4200
- * If they're currently Cesium set values then our defaults are used.
4201
- * @param params
4202
- */
4203
- function SetTimeDetails(params) {
4204
- let { viewer, animationSpeed, isAnimating, startTime, currentTime, stopTime, startTimeIso, stopTimeIso, currentTimeIso, isLive, livePaddingSeconds } = params;
4205
- const clock = viewer.clock;
4206
- if (startTime) {
4207
- clock.startTime = startTime;
4208
- }
4209
- else if (startTimeIso) {
4210
- const startDate = Cesium.JulianDate.fromIso8601(startTimeIso);
4211
- if (startDate) {
4212
- clock.startTime = startDate;
4447
+ Dispose() {
4448
+ this.disposed = true;
4449
+ clearTimeout(this.retryTimeout);
4450
+ clearInterval(this.animateInterval);
4451
+ const cEntities = [
4452
+ this.parabola
4453
+ ].concat(this.siblings);
4454
+ cEntities.forEach(e => {
4455
+ if (e && this.viewer.entities.contains(e)) {
4456
+ this.viewer.entities.remove(e);
4213
4457
  }
4458
+ });
4459
+ }
4460
+ }
4461
+
4462
+ function colorToCColor(color) {
4463
+ return new Cesium.Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
4464
+ }
4465
+ async function getStyle(api, typeId, styleId) {
4466
+ let style = null;
4467
+ if (styleId && styleId != -1) {
4468
+ try {
4469
+ style = (await BModels.Style.Get({
4470
+ api,
4471
+ styleId
4472
+ })).style;
4214
4473
  }
4215
- if (currentTime) {
4216
- clock.currentTime = currentTime;
4474
+ // Probably deleted.
4475
+ catch (e) {
4476
+ console.error(e);
4217
4477
  }
4218
- else if (currentTimeIso) {
4219
- const currentDate = Cesium.JulianDate.fromIso8601(currentTimeIso);
4220
- if (currentDate) {
4221
- clock.currentTime = currentDate;
4478
+ }
4479
+ if (!style && typeId) {
4480
+ const { entityType: type } = await BModels.EntityType.Get({
4481
+ api,
4482
+ entityTypeId: typeId
4483
+ });
4484
+ if (type["DisplaySetting.ID"]) {
4485
+ try {
4486
+ style = (await BModels.Style.Get({
4487
+ api,
4488
+ styleId: type["DisplaySetting.ID"]
4489
+ })).style;
4222
4490
  }
4223
- }
4224
- if (stopTime) {
4225
- clock.stopTime = stopTime;
4226
- }
4227
- else if (stopTimeIso) {
4228
- const stopDate = Cesium.JulianDate.fromIso8601(stopTimeIso);
4229
- if (stopDate) {
4230
- clock.stopTime = stopDate;
4491
+ catch (e) {
4492
+ let hideError = false;
4493
+ // TODO: we need a util for extracting code + message rather than writing all this every time.
4494
+ if (e && typeof e == "object" && e.ERROR) {
4495
+ const error = e.ERROR;
4496
+ const code = error && typeof error == "object" ? error.Code : "";
4497
+ // Avoiding logging a common error.
4498
+ // This happens when rendering entities that don't have records.
4499
+ hideError = String(code).toLowerCase() == "notfound";
4500
+ }
4501
+ if (!hideError) {
4502
+ console.error(e);
4503
+ }
4231
4504
  }
4232
4505
  }
4233
- clock.clockRange = Cesium.ClockRange.LOOP_STOP;
4234
- const areCesiumValues = clock[CESIUM_TIMELINE_KEY] != true;
4235
- if (areCesiumValues) {
4236
- if (isNaN(animationSpeed) || animationSpeed == null) {
4237
- animationSpeed = 1;
4238
- }
4239
- if (isAnimating == null) {
4240
- isAnimating = false;
4506
+ }
4507
+ return style;
4508
+ }
4509
+ var RelationRenderEngine;
4510
+ (function (RelationRenderEngine) {
4511
+ function GetRenderGroupId(relation) {
4512
+ return `${relation["Related.Entity.ID"]}-${relation["Principal.Entity.ID"]}-${relation["Relation.Type.ID"]}`;
4513
+ }
4514
+ RelationRenderEngine.GetRenderGroupId = GetRenderGroupId;
4515
+ async function Render(params) {
4516
+ const { apiGetter, viewer, visualRegister, menuItemId, relations } = params;
4517
+ const api = apiGetter.getApi(apiGetter.accountId);
4518
+ const rendered = {};
4519
+ let neededEntityIdsIds = [];
4520
+ for (let i = 0; i < relations.length; i++) {
4521
+ const relation = relations[i];
4522
+ if (relation["Principal.Entity.ID"]) {
4523
+ neededEntityIdsIds.push(relation["Principal.Entity.ID"]);
4241
4524
  }
4242
- if (isLive == null) {
4243
- isLive = false;
4525
+ if (relation["Related.Entity.ID"]) {
4526
+ neededEntityIdsIds.push(relation["Related.Entity.ID"]);
4244
4527
  }
4245
- if (livePaddingSeconds == null) {
4246
- livePaddingSeconds = DEFAULT_LIVE_PADDING_SECONDS;
4528
+ if (relation["Data.Entity.ID"]) {
4529
+ neededEntityIdsIds.push(relation["Data.Entity.ID"]);
4247
4530
  }
4248
4531
  }
4249
- if (!isNaN(animationSpeed) && animationSpeed != null) {
4250
- clock.multiplier = animationSpeed;
4251
- }
4252
- if (isAnimating != null) {
4253
- clock.shouldAnimate = isAnimating;
4254
- }
4255
- viewer.scene.requestRender();
4256
- clock[CESIUM_TIMELINE_KEY] = true;
4257
- if (livePaddingSeconds != null) {
4258
- clock[CESIUM_TIMELINE_LIVE_PADDING_KEY] = livePaddingSeconds || DEFAULT_LIVE_PADDING_SECONDS;
4259
- }
4260
- if (isLive != null) {
4261
- clock[CESIUM_TIMELINE_LIVE_KEY] = params.isLive == true;
4262
- }
4263
- if (clock[CESIUM_TIMELINE_LIVE_KEY]) {
4264
- startLive(viewer);
4532
+ // Turn the set unique.
4533
+ neededEntityIdsIds = neededEntityIdsIds.filter((v, i, a) => a.indexOf(v) === i);
4534
+ // Get all entities in one go.
4535
+ let entities = (await BModels.Entity.GetListByIds({
4536
+ entityIds: neededEntityIdsIds,
4537
+ api: apiGetter.getApi(),
4538
+ migrated: true,
4539
+ maxSearchTimeSec: 60 * 2
4540
+ })).entities;
4541
+ // Create a map for quick reference.
4542
+ const entitiesMap = {};
4543
+ for (let i = 0; i < entities.length; i++) {
4544
+ const entity = entities[i];
4545
+ entitiesMap[entity.Bruce.ID] = entity;
4265
4546
  }
4266
- else {
4267
- stopLive(viewer);
4547
+ entities = null;
4548
+ // Gather needed relationship types.
4549
+ // Right now this means just getting the full list.
4550
+ const relationTypes = (await BModels.EntityRelationType.GetList({
4551
+ api
4552
+ })).relationTypes;
4553
+ const relationTypesMap = {};
4554
+ for (let i = 0; i < relationTypes.length; i++) {
4555
+ const relationType = relationTypes[i];
4556
+ relationTypesMap[relationType.ID] = relationType;
4268
4557
  }
4269
- }
4270
- ViewUtils.SetTimeDetails = SetTimeDetails;
4271
- function startLive(viewer) {
4272
- const doUpdate = () => {
4273
- if (!viewer || viewer.isDestroyed() || !viewer.scene) {
4274
- stopLive(viewer);
4275
- return;
4558
+ for (let i = 0; i < relations.length; i++) {
4559
+ try {
4560
+ const relation = relations[i];
4561
+ const fromEntity = entitiesMap[relation["Principal.Entity.ID"]];
4562
+ const toEntity = entitiesMap[relation["Related.Entity.ID"]];
4563
+ const dataEntity = relation["Data.Entity.ID"] ? entitiesMap[relation["Data.Entity.ID"]] : null;
4564
+ const relationType = relationTypesMap[relation["Relation.Type.ID"]];
4565
+ 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));
4566
+ const cEntity = await Parabola.Render({
4567
+ dataEntity,
4568
+ fromEntity,
4569
+ relation,
4570
+ style,
4571
+ toEntity,
4572
+ viewer,
4573
+ visualRegister,
4574
+ apiGetter
4575
+ });
4576
+ cEntity._renderGroup = GetRenderGroupId(relation);
4577
+ rendered[GetRenderGroupId(relation)] = cEntity;
4276
4578
  }
4277
- // Get the current settings.
4278
- const tDetails = GetTimeDetails({ viewer });
4279
- const clock = viewer.clock;
4280
- if (clock) {
4281
- clock.shouldAnimate = true;
4282
- clock.multiplier = 1;
4283
- clock.currentTime = Cesium.JulianDate.now();
4284
- clock.startTime = Cesium.JulianDate.addSeconds(clock.currentTime, -tDetails.livePaddingSeconds, new Cesium.JulianDate());
4285
- clock.stopTime = Cesium.JulianDate.addSeconds(clock.currentTime, tDetails.livePaddingSeconds, new Cesium.JulianDate());
4286
- clock.clockRange = Cesium.ClockRange.UNBOUNDED;
4579
+ catch (e) {
4580
+ console.error(e);
4287
4581
  }
4288
- };
4289
- if (viewer[CESIUM_TIMELINE_INTERVAL_KEY]) {
4290
- doUpdate();
4291
- return;
4292
- }
4293
- // We'll start an interval that occasionally updates the Cesium clock to stay in the desired settings.
4294
- // Since it moves live (1 second per second), we don't have to worry about the ranges being out of date quickly.
4295
- viewer[CESIUM_TIMELINE_INTERVAL_KEY] = setInterval(() => {
4296
- doUpdate();
4297
- }, 800);
4298
- viewer[CESIUM_TIMELINE_LIVE_KEY] = true;
4299
- // Initial update.
4300
- doUpdate();
4301
- }
4302
- function stopLive(viewer) {
4303
- if (!viewer) {
4304
- return;
4305
- }
4306
- let interval = viewer[CESIUM_TIMELINE_INTERVAL_KEY];
4307
- if (interval) {
4308
- clearInterval(interval);
4309
- viewer[CESIUM_TIMELINE_INTERVAL_KEY] = null;
4310
- }
4311
- viewer[CESIUM_TIMELINE_LIVE_KEY] = false;
4312
- }
4313
- function SetGlobeDetails(params) {
4314
- let { viewer, hidden, baseColor } = params;
4315
- const scene = viewer === null || viewer === void 0 ? void 0 : viewer.scene;
4316
- if (!(scene === null || scene === void 0 ? void 0 : scene.globe)) {
4317
- return;
4318
- }
4319
- if (hidden == null) {
4320
- hidden = !scene.globe.show;
4321
- }
4322
- else {
4323
- scene.globe.show = !hidden;
4324
- }
4325
- if (baseColor == null) {
4326
- baseColor = scene.globe.baseColor;
4327
- }
4328
- // When globe is off, we'll also hide the stars/moon.
4329
- // We also grab the globe color and apply it to the sky.
4330
- if (hidden && GetModelSpace(viewer)) {
4331
- scene.skyBox.show = false;
4332
- scene.skyAtmosphere.show = false;
4333
- scene.sun.show = false;
4334
- scene.moon.show = false;
4335
- scene.backgroundColor = baseColor.clone();
4336
- }
4337
- else {
4338
- scene.skyBox.show = true;
4339
- scene.skyAtmosphere.show = true;
4340
- scene.sun.show = true;
4341
- scene.moon.show = true;
4342
- scene.backgroundColor = Cesium.Color.BLACK;
4343
- }
4344
- scene.globe.baseColor = baseColor;
4345
- }
4346
- ViewUtils.SetGlobeDetails = SetGlobeDetails;
4347
- function SetModelSpace(viewer, modelSpace) {
4348
- if (!viewer) {
4349
- return;
4350
4582
  }
4351
- if (viewer[CESIUM_MODEL_SPACE_KEY] === modelSpace) {
4352
- return;
4353
- }
4354
- viewer[CESIUM_MODEL_SPACE_KEY] = modelSpace;
4355
- // Reload globe since we display it differently between the two modes.
4356
- SetGlobeDetails({ viewer });
4583
+ return rendered;
4357
4584
  }
4358
- ViewUtils.SetModelSpace = SetModelSpace;
4359
- function GetModelSpace(viewer) {
4360
- if (!viewer) {
4361
- return false;
4585
+ RelationRenderEngine.Render = Render;
4586
+ let Parabola;
4587
+ (function (Parabola) {
4588
+ async function Render(params) {
4589
+ var _a;
4590
+ const style = (_a = params.style) === null || _a === void 0 ? void 0 : _a.Settings;
4591
+ const entity = params.dataEntity;
4592
+ const bColor = (style === null || style === void 0 ? void 0 : style.lineColor) ? BModels.Calculator.GetColor(style === null || style === void 0 ? void 0 : style.lineColor, entity, []) : null;
4593
+ const cColor = bColor ? colorToCColor(bColor) : Cesium.Color.WHITE;
4594
+ let width = EnsureNumber((style === null || style === void 0 ? void 0 : style.lineWidth) ? BModels.Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.lineWidth, entity, []) : 4, 4);
4595
+ if (width < 1) {
4596
+ width = 1;
4597
+ }
4598
+ const duration = EnsureNumber((style === null || style === void 0 ? void 0 : style.duration) ? BModels.Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.duration, entity, []) : 2, 2);
4599
+ const hDistanceRatio = EnsureNumber((style === null || style === void 0 ? void 0 : style.heightDistanceRatio) ? BModels.Calculator.GetNumber(style === null || style === void 0 ? void 0 : style.heightDistanceRatio, entity, []) : 0.25, 0.25);
4600
+ let fromPos = null;
4601
+ let toPos = null;
4602
+ let updatingPosses = false;
4603
+ const updatePosses = async () => {
4604
+ if (updatingPosses) {
4605
+ return;
4606
+ }
4607
+ updatingPosses = true;
4608
+ try {
4609
+ const fromData = await exports.EntityUtils.GetLocation({
4610
+ samples: [{
4611
+ entity: params.fromEntity,
4612
+ entityId: params.fromEntity.Bruce.ID,
4613
+ heightRef: Cesium.HeightReference.CLAMP_TO_GROUND,
4614
+ returnHeightRef: Cesium.HeightReference.NONE
4615
+ }],
4616
+ viewer: params.viewer,
4617
+ visualRegister: params.visualRegister,
4618
+ api: params.apiGetter.getApi()
4619
+ });
4620
+ fromPos = fromData.pos3d;
4621
+ const toData = await exports.EntityUtils.GetLocation({
4622
+ samples: [{
4623
+ entity: params.toEntity,
4624
+ entityId: params.toEntity.Bruce.ID,
4625
+ heightRef: Cesium.HeightReference.CLAMP_TO_GROUND,
4626
+ returnHeightRef: Cesium.HeightReference.NONE
4627
+ }],
4628
+ viewer: params.viewer,
4629
+ visualRegister: params.visualRegister,
4630
+ api: params.apiGetter.getApi()
4631
+ });
4632
+ toPos = toData.pos3d;
4633
+ }
4634
+ catch (e) {
4635
+ console.error(e);
4636
+ }
4637
+ updatingPosses = false;
4638
+ };
4639
+ updatePosses();
4640
+ const parabola = new CesiumParabola({
4641
+ viewer: params.viewer,
4642
+ pos1: () => fromPos,
4643
+ pos2: () => toPos,
4644
+ color: cColor.toCssColorString(),
4645
+ width: width,
4646
+ duration: duration,
4647
+ heightDistanceRatio: hDistanceRatio
4648
+ });
4649
+ parabola.Hidden = true;
4650
+ const cEntities = parabola.Animate();
4651
+ const cEntity = cEntities.parabola;
4652
+ cEntity._siblingGraphics = [];
4653
+ for (let i = 0; i < cEntities.siblings.length; i++) {
4654
+ const sibling = cEntities.siblings[i];
4655
+ cEntity._siblingGraphics.push(sibling);
4656
+ }
4657
+ let updateInterval = setInterval(() => {
4658
+ var _a;
4659
+ if (!((_a = params.viewer) === null || _a === void 0 ? void 0 : _a.scene) ||
4660
+ params.viewer.isDestroyed() ||
4661
+ (!parabola || parabola.Disposed)) {
4662
+ clearInterval(updateInterval);
4663
+ parabola.Dispose();
4664
+ return;
4665
+ }
4666
+ if (parabola) {
4667
+ const visible = cEntity && cEntity.show != false && params.viewer.entities.contains(cEntity);
4668
+ parabola.Hidden = !visible;
4669
+ }
4670
+ updatePosses();
4671
+ params.viewer.scene.requestRender();
4672
+ }, 1000);
4673
+ let disposed = false;
4674
+ cEntity._dispose = () => {
4675
+ if (disposed) {
4676
+ return;
4677
+ }
4678
+ disposed = true;
4679
+ clearInterval(updateInterval);
4680
+ if (parabola) {
4681
+ parabola.Dispose();
4682
+ }
4683
+ };
4684
+ return cEntity;
4362
4685
  }
4363
- return Boolean(viewer[CESIUM_MODEL_SPACE_KEY]);
4364
- }
4365
- ViewUtils.GetModelSpace = GetModelSpace;
4366
- })(exports.ViewUtils || (exports.ViewUtils = {}));
4686
+ Parabola.Render = Render;
4687
+ })(Parabola = RelationRenderEngine.Parabola || (RelationRenderEngine.Parabola = {}));
4688
+ })(RelationRenderEngine || (RelationRenderEngine = {}));
4367
4689
 
4368
4690
  const MODEL_MIN_RADIUS = 10;
4369
4691
  const POINT_MIN_RADIUS = 15;
@@ -7023,6 +7345,116 @@
7023
7345
  VisualsRegister.Register = Register;
7024
7346
  })(exports.VisualsRegister || (exports.VisualsRegister = {}));
7025
7347
 
7348
+ /**
7349
+ * Tracks per-entity rerender state for unsaved blob maintenance and stale API response suppression.
7350
+ */
7351
+ class EntityReRenderMaintainState {
7352
+ constructor() {
7353
+ this.maintainedEntitiesById = {};
7354
+ this.apiRevisionByEntityId = {};
7355
+ this.skipApiRunByEntityId = {};
7356
+ this.checkRunId = 0;
7357
+ }
7358
+ setMaintainedEntities(entities) {
7359
+ var _a;
7360
+ for (let i = 0; i < entities.length; i++) {
7361
+ const entity = entities[i];
7362
+ const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
7363
+ if (!id) {
7364
+ continue;
7365
+ }
7366
+ this.maintainedEntitiesById[id] = entity;
7367
+ }
7368
+ }
7369
+ clearMaintainedEntities(entityIds) {
7370
+ for (let i = 0; i < entityIds.length; i++) {
7371
+ const id = entityIds[i];
7372
+ if (!id) {
7373
+ continue;
7374
+ }
7375
+ delete this.maintainedEntitiesById[id];
7376
+ }
7377
+ }
7378
+ getMaintainedEntities(entityIds) {
7379
+ const entities = [];
7380
+ for (let i = 0; i < entityIds.length; i++) {
7381
+ const id = entityIds[i];
7382
+ if (!id) {
7383
+ continue;
7384
+ }
7385
+ const entity = this.maintainedEntitiesById[id];
7386
+ if (entity) {
7387
+ entities.push(entity);
7388
+ }
7389
+ }
7390
+ return entities;
7391
+ }
7392
+ bumpApiRevisions(entityIds) {
7393
+ var _a;
7394
+ for (let i = 0; i < entityIds.length; i++) {
7395
+ const id = entityIds[i];
7396
+ if (!id) {
7397
+ continue;
7398
+ }
7399
+ this.apiRevisionByEntityId[id] = ((_a = this.apiRevisionByEntityId[id]) !== null && _a !== void 0 ? _a : 0) + 1;
7400
+ }
7401
+ }
7402
+ captureApiRevisions(entityIds) {
7403
+ var _a;
7404
+ const revisions = {};
7405
+ for (let i = 0; i < entityIds.length; i++) {
7406
+ const id = entityIds[i];
7407
+ if (!id) {
7408
+ continue;
7409
+ }
7410
+ revisions[id] = (_a = this.apiRevisionByEntityId[id]) !== null && _a !== void 0 ? _a : 0;
7411
+ }
7412
+ return revisions;
7413
+ }
7414
+ startCheckRun() {
7415
+ this.checkRunId += 1;
7416
+ return this.checkRunId;
7417
+ }
7418
+ getCurrentCheckRun() {
7419
+ return this.checkRunId;
7420
+ }
7421
+ markSkipForCurrentRun(entityIds, isRunningCheck) {
7422
+ if (!isRunningCheck) {
7423
+ return;
7424
+ }
7425
+ const runId = this.checkRunId;
7426
+ for (let i = 0; i < entityIds.length; i++) {
7427
+ const id = entityIds[i];
7428
+ if (!id) {
7429
+ continue;
7430
+ }
7431
+ this.skipApiRunByEntityId[id] = runId;
7432
+ }
7433
+ }
7434
+ shouldSkipInRun(entityId, runId) {
7435
+ return this.skipApiRunByEntityId[entityId] === runId;
7436
+ }
7437
+ filterNonSkippedIds(entityIds, runId) {
7438
+ return entityIds.filter((id) => {
7439
+ return id && !this.shouldSkipInRun(id, runId);
7440
+ });
7441
+ }
7442
+ filterCurrentApiEntities(params) {
7443
+ const { entities, revisions, runId } = params;
7444
+ return entities.filter((entity) => {
7445
+ var _a, _b, _c;
7446
+ const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
7447
+ if (!id) {
7448
+ return false;
7449
+ }
7450
+ if (runId != null && this.shouldSkipInRun(id, runId)) {
7451
+ return false;
7452
+ }
7453
+ return ((_b = this.apiRevisionByEntityId[id]) !== null && _b !== void 0 ? _b : 0) === ((_c = revisions[id]) !== null && _c !== void 0 ? _c : 0);
7454
+ });
7455
+ }
7456
+ }
7457
+
7026
7458
  function GetValue(viewer, obj) {
7027
7459
  if (obj === null || obj === void 0 ? void 0 : obj.getValue) {
7028
7460
  let date = viewer.scene.lastRenderTime;
@@ -7842,438 +8274,6 @@
7842
8274
  }
7843
8275
  }
7844
8276
 
7845
- /**
7846
- * Tracks per-entity rerender state for unsaved blob maintenance and stale API response suppression.
7847
- */
7848
- class EntityReRenderMaintainState {
7849
- constructor() {
7850
- this.maintainedEntitiesById = {};
7851
- this.apiRevisionByEntityId = {};
7852
- this.skipApiRunByEntityId = {};
7853
- this.checkRunId = 0;
7854
- }
7855
- setMaintainedEntities(entities) {
7856
- var _a;
7857
- for (let i = 0; i < entities.length; i++) {
7858
- const entity = entities[i];
7859
- const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
7860
- if (!id) {
7861
- continue;
7862
- }
7863
- this.maintainedEntitiesById[id] = entity;
7864
- }
7865
- }
7866
- clearMaintainedEntities(entityIds) {
7867
- for (let i = 0; i < entityIds.length; i++) {
7868
- const id = entityIds[i];
7869
- if (!id) {
7870
- continue;
7871
- }
7872
- delete this.maintainedEntitiesById[id];
7873
- }
7874
- }
7875
- getMaintainedEntities(entityIds) {
7876
- const entities = [];
7877
- for (let i = 0; i < entityIds.length; i++) {
7878
- const id = entityIds[i];
7879
- if (!id) {
7880
- continue;
7881
- }
7882
- const entity = this.maintainedEntitiesById[id];
7883
- if (entity) {
7884
- entities.push(entity);
7885
- }
7886
- }
7887
- return entities;
7888
- }
7889
- bumpApiRevisions(entityIds) {
7890
- var _a;
7891
- for (let i = 0; i < entityIds.length; i++) {
7892
- const id = entityIds[i];
7893
- if (!id) {
7894
- continue;
7895
- }
7896
- this.apiRevisionByEntityId[id] = ((_a = this.apiRevisionByEntityId[id]) !== null && _a !== void 0 ? _a : 0) + 1;
7897
- }
7898
- }
7899
- captureApiRevisions(entityIds) {
7900
- var _a;
7901
- const revisions = {};
7902
- for (let i = 0; i < entityIds.length; i++) {
7903
- const id = entityIds[i];
7904
- if (!id) {
7905
- continue;
7906
- }
7907
- revisions[id] = (_a = this.apiRevisionByEntityId[id]) !== null && _a !== void 0 ? _a : 0;
7908
- }
7909
- return revisions;
7910
- }
7911
- startCheckRun() {
7912
- this.checkRunId += 1;
7913
- return this.checkRunId;
7914
- }
7915
- getCurrentCheckRun() {
7916
- return this.checkRunId;
7917
- }
7918
- markSkipForCurrentRun(entityIds, isRunningCheck) {
7919
- if (!isRunningCheck) {
7920
- return;
7921
- }
7922
- const runId = this.checkRunId;
7923
- for (let i = 0; i < entityIds.length; i++) {
7924
- const id = entityIds[i];
7925
- if (!id) {
7926
- continue;
7927
- }
7928
- this.skipApiRunByEntityId[id] = runId;
7929
- }
7930
- }
7931
- shouldSkipInRun(entityId, runId) {
7932
- return this.skipApiRunByEntityId[entityId] === runId;
7933
- }
7934
- filterNonSkippedIds(entityIds, runId) {
7935
- return entityIds.filter((id) => {
7936
- return id && !this.shouldSkipInRun(id, runId);
7937
- });
7938
- }
7939
- filterCurrentApiEntities(params) {
7940
- const { entities, revisions, runId } = params;
7941
- return entities.filter((entity) => {
7942
- var _a, _b, _c;
7943
- const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
7944
- if (!id) {
7945
- return false;
7946
- }
7947
- if (runId != null && this.shouldSkipInRun(id, runId)) {
7948
- return false;
7949
- }
7950
- return ((_b = this.apiRevisionByEntityId[id]) !== null && _b !== void 0 ? _b : 0) === ((_c = revisions[id]) !== null && _c !== void 0 ? _c : 0);
7951
- });
7952
- }
7953
- }
7954
-
7955
- function isTurfAvailable() {
7956
- return window && window.turf != null;
7957
- }
7958
- /**
7959
- * Util for simplifying geometry on the fly.
7960
- */
7961
- var SimplifyGeometry;
7962
- (function (SimplifyGeometry) {
7963
- /**
7964
- * Returns the total number of points in the geometry.
7965
- * @param geometry
7966
- * @param limit number to count up to before returning.
7967
- * @returns
7968
- */
7969
- function CountPoints(geometry, limit) {
7970
- let count = 0;
7971
- const traverse = (geometry) => {
7972
- if (geometry.MultiGeometry) {
7973
- for (let i = 0; i < geometry.MultiGeometry.length; i++) {
7974
- traverse(geometry.MultiGeometry[i]);
7975
- // Reached the limit, return.
7976
- if (limit && count >= limit) {
7977
- return;
7978
- }
7979
- }
7980
- }
7981
- else if (geometry.Polygon) {
7982
- for (let i = 0; i < geometry.Polygon.length; i++) {
7983
- const polygon = geometry.Polygon[i];
7984
- count += BModels.Geometry.ParsePoints(polygon.LinearRing).length;
7985
- }
7986
- }
7987
- else if (geometry.LineString) {
7988
- count += BModels.Geometry.ParsePoints(geometry.LineString).length;
7989
- }
7990
- else if (geometry.Point) {
7991
- count += 1;
7992
- }
7993
- };
7994
- traverse(geometry);
7995
- return count;
7996
- }
7997
- SimplifyGeometry.CountPoints = CountPoints;
7998
- /**
7999
- * Simplifies input geometry.
8000
- * This will turn it into GeoJSON, run it through turf, then back to Bruce geometry.
8001
- * @param geometry
8002
- */
8003
- function Simplify(entityId, geometry, tolerance) {
8004
- var _a;
8005
- if (!geometry || !isTurfAvailable() || !turf.simplify) {
8006
- return geometry;
8007
- }
8008
- // Convert to geojson so that we can interact with turf.
8009
- const gFeature = BModels.Geometry.ToGeoJsonFeature({
8010
- geometry: geometry
8011
- });
8012
- // Unkink the geometry.
8013
- // This removes overlapping polygons before we start merging and simplifying.
8014
- // Commented out because it has crashes and doesn't handle holes.
8015
- untangleFeature(gFeature);
8016
- // Union the geometry.
8017
- // This merges overlapping polygons.
8018
- unionFeature(gFeature);
8019
- // Simplify the geometry.
8020
- if (tolerance > 0) {
8021
- gFeature.geometry = turf.simplify(gFeature.geometry, {
8022
- tolerance: tolerance,
8023
- highQuality: true,
8024
- mutate: true
8025
- });
8026
- }
8027
- // Converting back to Bruce geometry.
8028
- geometry = (_a = BModels.Geometry.FromGeoJson({
8029
- geoJson: gFeature
8030
- })) === null || _a === void 0 ? void 0 : _a.geometry;
8031
- return geometry;
8032
- }
8033
- SimplifyGeometry.Simplify = Simplify;
8034
- })(SimplifyGeometry || (SimplifyGeometry = {}));
8035
- /**
8036
- * Runs through all found polygons and runs unkink through turf on them.
8037
- * @param feature
8038
- */
8039
- function untangleFeature(feature) {
8040
- // Collection to add to because the result might be multiple from an unkink.
8041
- const collection = {
8042
- geometries: [],
8043
- type: "GeometryCollection"
8044
- };
8045
- // Runs a dedupe and unkink on the coordinates.
8046
- // Returns if the coordinates were added to the collection.
8047
- const processCoordinates = (coords) => {
8048
- try {
8049
- // Dedupe the coordinates to avoid issues with unkink.
8050
- coords = dedupeCoordinates(coords);
8051
- const outer = [];
8052
- let inner = [];
8053
- // We'll unkink each ring separately as this is killing the holes when it is done as a whole.
8054
- // So we'll do it separate then recombine.
8055
- for (let i = 0; i < coords.length; i++) {
8056
- const ring = coords[i];
8057
- const unkink = turf.unkinkPolygon({
8058
- type: "Polygon",
8059
- coordinates: [ring]
8060
- });
8061
- if (unkink.type == "FeatureCollection") {
8062
- let target = i == 0 ? outer : inner;
8063
- for (let j = 0; j < unkink.features.length; j++) {
8064
- const unkinked = unkink.features[j].geometry.coordinates;
8065
- if (unkinked.length > 0) {
8066
- target.push(unkinked[0]);
8067
- }
8068
- }
8069
- }
8070
- else {
8071
- console.error("Unexpected unkink result.", unkink);
8072
- }
8073
- }
8074
- // Recreate the rings and reapply to the collection.
8075
- if (outer.length > 0) {
8076
- const combinedCoords = [outer[0]];
8077
- for (let i = 0; i < inner.length; i++) {
8078
- combinedCoords.push(inner[i]);
8079
- }
8080
- // Add the combined coordinates to the collection
8081
- const polygon = {
8082
- type: "Polygon",
8083
- coordinates: combinedCoords
8084
- };
8085
- // Ensure right-hand rule is followed.
8086
- ensureRightHandRule(polygon);
8087
- // Add to the collection.
8088
- collection.geometries.push(polygon);
8089
- return true;
8090
- }
8091
- }
8092
- catch (e) {
8093
- // console.error("Failed to unkink polygon.", e);
8094
- }
8095
- return false;
8096
- };
8097
- const processGeometry = (geometry) => {
8098
- let added = false;
8099
- if (geometry.type == "Polygon") {
8100
- added = processCoordinates(geometry.coordinates);
8101
- }
8102
- else if (geometry.type == "MultiPolygon") {
8103
- for (let i = 0; i < geometry.coordinates.length; i++) {
8104
- added = processCoordinates(geometry.coordinates[i]) || added;
8105
- }
8106
- }
8107
- if (!added) {
8108
- // Adding original since we can't unkink it.
8109
- collection.geometries.push(geometry);
8110
- }
8111
- };
8112
- if (feature.geometry.type == "GeometryCollection") {
8113
- feature.geometry.geometries.forEach((geometry) => {
8114
- processGeometry(geometry);
8115
- });
8116
- }
8117
- else {
8118
- processGeometry(feature.geometry);
8119
- }
8120
- // Re-assign the geometry.
8121
- if (collection.geometries.length == 1) {
8122
- feature.geometry = collection.geometries[0];
8123
- }
8124
- else {
8125
- feature.geometry = collection;
8126
- }
8127
- }
8128
- /**
8129
- * Runs through all found polygons and unions them using turf.
8130
- * Failed unions are ignored and the original is kept.
8131
- * @param feature
8132
- */
8133
- function unionFeature(feature) {
8134
- // Collection to add to because the result might be multiple from an unkink.
8135
- const collection = {
8136
- geometries: [],
8137
- type: "GeometryCollection"
8138
- };
8139
- // We'll turn each geometry into a feature and union them.
8140
- const tmpCollection = {
8141
- features: [],
8142
- type: "FeatureCollection"
8143
- };
8144
- if (feature.geometry.type == "GeometryCollection") {
8145
- feature.geometry.geometries.forEach((geometry) => {
8146
- if (geometry.type == "Polygon") {
8147
- tmpCollection.features.push({
8148
- type: "Feature",
8149
- geometry: geometry,
8150
- properties: {}
8151
- });
8152
- }
8153
- else if (geometry.type == "MultiPolygon") {
8154
- for (let i = 0; i < geometry.coordinates.length; i++) {
8155
- tmpCollection.features.push({
8156
- type: "Feature",
8157
- geometry: {
8158
- type: "Polygon",
8159
- coordinates: geometry.coordinates[i]
8160
- },
8161
- properties: {}
8162
- });
8163
- }
8164
- }
8165
- // Only focusing on polygons.
8166
- else {
8167
- collection.geometries.push(geometry);
8168
- }
8169
- });
8170
- }
8171
- else if (feature.geometry.type == "Polygon") {
8172
- tmpCollection.features.push({
8173
- type: "Feature",
8174
- geometry: feature.geometry,
8175
- properties: {}
8176
- });
8177
- }
8178
- else if (feature.geometry.type == "MultiPolygon") {
8179
- for (let i = 0; i < feature.geometry.coordinates.length; i++) {
8180
- tmpCollection.features.push({
8181
- type: "Feature",
8182
- geometry: {
8183
- type: "Polygon",
8184
- coordinates: feature.geometry.coordinates[i]
8185
- },
8186
- properties: {}
8187
- });
8188
- }
8189
- }
8190
- // No polygons to union.
8191
- // Need at least 2 to union.
8192
- if (tmpCollection.features.length < 2) {
8193
- return;
8194
- }
8195
- // Now we'll union them.
8196
- try {
8197
- const union = turf.union(tmpCollection);
8198
- if (union.geometry.type == "Polygon") {
8199
- collection.geometries.push(union.geometry);
8200
- }
8201
- else if (union.geometry.type == "MultiPolygon") {
8202
- for (let i = 0; i < union.geometry.coordinates.length; i++) {
8203
- collection.geometries.push({
8204
- type: "Polygon",
8205
- coordinates: union.geometry.coordinates[i]
8206
- });
8207
- }
8208
- }
8209
- else {
8210
- // Returning early because the result is unexpected.
8211
- return;
8212
- }
8213
- }
8214
- catch (e) {
8215
- // console.error("Failed to union polygons.", e);
8216
- return;
8217
- }
8218
- // Re-assign the geometry.
8219
- if (collection.geometries.length == 1) {
8220
- feature.geometry = collection.geometries[0];
8221
- }
8222
- else {
8223
- feature.geometry = collection;
8224
- }
8225
- }
8226
- function dedupeCoordinates(inputCoords) {
8227
- return inputCoords.map(ring => {
8228
- if (ring.length < 2) {
8229
- return ring;
8230
- }
8231
- const dedupeCoords = [];
8232
- const uniqueCoords = new Set();
8233
- // Dedupe the points.
8234
- ring.forEach(coord => {
8235
- const key = coord.join(',');
8236
- if (!uniqueCoords.has(key)) {
8237
- uniqueCoords.add(key);
8238
- dedupeCoords.push(coord);
8239
- }
8240
- });
8241
- // Make sure the last point matches the first.
8242
- if (dedupeCoords.length > 1) {
8243
- if (dedupeCoords[0][0] != dedupeCoords[dedupeCoords.length - 1][0] ||
8244
- dedupeCoords[0][1] != dedupeCoords[dedupeCoords.length - 1][1]) {
8245
- dedupeCoords.push(dedupeCoords[0]);
8246
- }
8247
- }
8248
- return dedupeCoords;
8249
- });
8250
- }
8251
- function ensureRightHandRule(polygon) {
8252
- // Ensure the outer ring follows the right-hand rule
8253
- if (polygon.coordinates.length > 0) {
8254
- const outerRing = polygon.coordinates[0];
8255
- if (isClockwise(outerRing)) {
8256
- polygon.coordinates[0] = outerRing.reverse();
8257
- }
8258
- }
8259
- // Ensure any inner rings (holes) follow the right-hand rule
8260
- for (let i = 1; i < polygon.coordinates.length; i++) {
8261
- const innerRing = polygon.coordinates[i];
8262
- if (!isClockwise(innerRing)) {
8263
- polygon.coordinates[i] = innerRing.reverse();
8264
- }
8265
- }
8266
- }
8267
- function isClockwise(ring) {
8268
- let sum = 0;
8269
- for (let i = 0; i < ring.length - 1; i++) {
8270
- const p1 = ring[i];
8271
- const p2 = ring[i + 1];
8272
- sum += (p2[0] - p1[0]) * (p2[1] + p1[1]);
8273
- }
8274
- return sum > 0;
8275
- }
8276
-
8277
8277
  const BATCH_SIZE = 500;
8278
8278
  const CHECK_BATCH_SIZE = 250;
8279
8279
  function getValue$2(viewer, obj) {
@@ -8313,6 +8313,16 @@
8313
8313
  this.getterSub = null;
8314
8314
  this.disposed = false;
8315
8315
  this.renderedEntities = {};
8316
+ // InternalID to public Entity ID, populated when Entity blob is available.
8317
+ // Used to match WS entity-change events (which carry internal ID ranges) to rendered Entities.
8318
+ this.renderedByInternalId = new Map();
8319
+ // Entity ID to internal ID, reverse lookup for cleanup.
8320
+ this.internalByEntityId = new Map();
8321
+ // Cleanup function for the RecordChangeFeed subscription.
8322
+ this.feedSub = null;
8323
+ // Entity IDs waiting for a throttled re-render pass (1s rate limit).
8324
+ this.feedPendingUpdateIds = new Set();
8325
+ this.feedUpdateThrottleTimer = null;
8316
8326
  this.entityCheckQueue = null;
8317
8327
  this.entityCheckQueueIds = [];
8318
8328
  this.entityCheckRemoval = null;
@@ -8477,7 +8487,7 @@
8477
8487
  }
8478
8488
  }
8479
8489
  setGetter() {
8480
- var _a, _b, _c, _d;
8490
+ var _a, _b, _c, _d, _e;
8481
8491
  this.unsetGetter();
8482
8492
  const isTagItem = Boolean(this.item.BruceEntity.ExpandLayers);
8483
8493
  let tagsToRender = isTagItem ? this.item.BruceEntity.SelectedExpandLayers : null;
@@ -8535,15 +8545,90 @@
8535
8545
  this.entityCheckQueue = new BModels.DelayQueue(() => {
8536
8546
  this.doEntityCheck(Object.keys(this.renderedEntities));
8537
8547
  }, shouldCheck ? 3000 : 30000);
8548
+ const feed = (_e = this.apiGetter.getApi()) === null || _e === void 0 ? void 0 : _e.RecordChangeFeed;
8549
+ if (feed) {
8550
+ this.feedSub = feed.Subscribe({
8551
+ concepts: [BModels.AccountConcept.EConcept.ENTITY],
8552
+ actions: ["U", "D"]
8553
+ }, (event) => {
8554
+ var _a;
8555
+ if (!this.renderedByInternalId.size) {
8556
+ return;
8557
+ }
8558
+ const rangeStr = typeof event.data === "string" ? event.data : "";
8559
+ if (!rangeStr) {
8560
+ return;
8561
+ }
8562
+ const affectedIds = [];
8563
+ for (const [internalId, entityId] of this.renderedByInternalId) {
8564
+ if (BModels.RecordChangeFeed.isEntityInternalIdInRangeString(rangeStr, internalId)) {
8565
+ affectedIds.push(entityId);
8566
+ }
8567
+ }
8568
+ if (!affectedIds.length) {
8569
+ return;
8570
+ }
8571
+ // Remove regos directly.
8572
+ if (event.action === "D") {
8573
+ for (const entityId of affectedIds) {
8574
+ this.visualsManager.RemoveRegos({
8575
+ entityId,
8576
+ menuItemId: this.item.id,
8577
+ requestRender: false
8578
+ });
8579
+ delete this.renderedEntities[entityId];
8580
+ (_a = this.clustering) === null || _a === void 0 ? void 0 : _a.RemoveEntity(entityId, false);
8581
+ const knownId = this.internalByEntityId.get(entityId);
8582
+ if (knownId != null) {
8583
+ this.renderedByInternalId.delete(knownId);
8584
+ this.internalByEntityId.delete(entityId);
8585
+ }
8586
+ }
8587
+ if (this.clustering) {
8588
+ this.clustering.Update();
8589
+ }
8590
+ this.viewer.scene.requestRender();
8591
+ }
8592
+ // Accumulate IDs and flush at most once per second.
8593
+ else {
8594
+ for (const entityId of affectedIds) {
8595
+ this.feedPendingUpdateIds.add(entityId);
8596
+ }
8597
+ if (!this.feedUpdateThrottleTimer) {
8598
+ this.feedUpdateThrottleTimer = setTimeout(() => {
8599
+ this.feedUpdateThrottleTimer = null;
8600
+ if (this.disposed || !this.feedPendingUpdateIds.size) {
8601
+ return;
8602
+ }
8603
+ const ids = [...this.feedPendingUpdateIds];
8604
+ this.feedPendingUpdateIds.clear();
8605
+ this.ReRender({
8606
+ entityIds: ids,
8607
+ force: true
8608
+ });
8609
+ }, 1000);
8610
+ }
8611
+ }
8612
+ });
8613
+ }
8538
8614
  }
8539
8615
  unsetGetter() {
8540
- var _a, _b, _c;
8616
+ var _a, _b, _c, _d;
8541
8617
  (_a = this.getter) === null || _a === void 0 ? void 0 : _a.ExcludeMenuItem(this.item.id);
8542
8618
  this.getter = null;
8543
8619
  (_b = this.getterSub) === null || _b === void 0 ? void 0 : _b.call(this);
8544
8620
  this.getterSub = null;
8545
8621
  (_c = this.entityCheckQueue) === null || _c === void 0 ? void 0 : _c.Dispose();
8546
8622
  this.entityCheckQueue = null;
8623
+ (_d = this.feedSub) === null || _d === void 0 ? void 0 : _d.call(this);
8624
+ this.feedSub = null;
8625
+ if (this.feedUpdateThrottleTimer) {
8626
+ clearTimeout(this.feedUpdateThrottleTimer);
8627
+ this.feedUpdateThrottleTimer = null;
8628
+ }
8629
+ this.feedPendingUpdateIds.clear();
8630
+ this.renderedByInternalId.clear();
8631
+ this.internalByEntityId.clear();
8547
8632
  }
8548
8633
  preventCurrentCheckApiRefresh(entityIds) {
8549
8634
  var _a;
@@ -9096,7 +9181,7 @@
9096
9181
  * @returns
9097
9182
  */
9098
9183
  const register = (thing) => {
9099
- var _a, _b, _c, _d, _e, _f;
9184
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
9100
9185
  // See if the cesium entity already exists in a group.
9101
9186
  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); });
9102
9187
  if (group) {
@@ -9140,8 +9225,14 @@
9140
9225
  cdn: this.item.cdnEnabled,
9141
9226
  collection: source.entities,
9142
9227
  outline: (_f = (_e = group.data) === null || _e === void 0 ? void 0 : _e.Bruce) === null || _f === void 0 ? void 0 : _f.Outline,
9228
+ 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,
9143
9229
  };
9144
9230
  group.rego = rego;
9231
+ const groupInternalId = (_l = (_k = group.data) === null || _k === void 0 ? void 0 : _k.Bruce) === null || _l === void 0 ? void 0 : _l.InternalID;
9232
+ if (groupInternalId != null) {
9233
+ this.renderedByInternalId.set(groupInternalId, entityId);
9234
+ this.internalByEntityId.set(entityId, groupInternalId);
9235
+ }
9145
9236
  this.visualsManager.AddRego({
9146
9237
  rego,
9147
9238
  requestRender: false
@@ -9185,7 +9276,7 @@
9185
9276
  * @returns
9186
9277
  */
9187
9278
  async renderAsIndividuals(entities, force = false) {
9188
- var _a, _b, _c, _d, _e, _f;
9279
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
9189
9280
  // When live we just want to show the latest pos.
9190
9281
  // When not live, the user might scroll the timeline and want to see it a fluid animation between points in time.
9191
9282
  const isLive = exports.ViewUtils.GetTimeDetails({
@@ -9239,13 +9330,25 @@
9239
9330
  const id = entity.Bruce.ID;
9240
9331
  const cEntity = cEntities.get(id);
9241
9332
  this.renderedEntities[id] = !!cEntity;
9333
+ const internalId = (_c = entity.Bruce) === null || _c === void 0 ? void 0 : _c.InternalID;
9334
+ if (cEntity && internalId != null) {
9335
+ this.renderedByInternalId.set(internalId, id);
9336
+ this.internalByEntityId.set(id, internalId);
9337
+ }
9338
+ else if (!cEntity) {
9339
+ const knownInternalId = this.internalByEntityId.get(id);
9340
+ if (knownInternalId != null) {
9341
+ this.renderedByInternalId.delete(knownInternalId);
9342
+ this.internalByEntityId.delete(id);
9343
+ }
9344
+ }
9242
9345
  if (cEntity) {
9243
9346
  const rego = this.visualsManager.GetRego({
9244
9347
  entityId: id,
9245
9348
  menuItemId: this.item.id
9246
9349
  });
9247
9350
  // The baseline data source must be editable.
9248
- const canEdit = !((_c = entity.Bruce.Outline) === null || _c === void 0 ? void 0 : _c.find(x => x.Baseline && !x.Editable));
9351
+ const canEdit = !((_d = entity.Bruce.Outline) === null || _d === void 0 ? void 0 : _d.find(x => x.Baseline && !x.Editable));
9249
9352
  const visual = rego === null || rego === void 0 ? void 0 : rego.visual;
9250
9353
  if (!visual || visual != cEntity) {
9251
9354
  const wasClustered = this.clustering ? this.clustering.AddEntity(id, cEntity, false) : false;
@@ -9264,7 +9367,8 @@
9264
9367
  overrideShow: wasClustered ? false : null,
9265
9368
  name: cEntity.name,
9266
9369
  cdn: this.item.cdnEnabled,
9267
- outline: entity.Bruce.Outline
9370
+ outline: entity.Bruce.Outline,
9371
+ internalId: (_f = (_e = entity.Bruce) === null || _e === void 0 ? void 0 : _e.InternalID) !== null && _f !== void 0 ? _f : undefined,
9268
9372
  };
9269
9373
  this.visualsManager.AddRego({
9270
9374
  rego,
@@ -9276,10 +9380,11 @@
9276
9380
  rego.visual = cEntity;
9277
9381
  rego.entityTypeId = entity.Bruce["EntityType.ID"];
9278
9382
  rego.tagIds = entity.Bruce["Layer.ID"] ? [].concat(entity.Bruce["Layer.ID"]) : [];
9279
- rego.outline = (_d = entity.Bruce) === null || _d === void 0 ? void 0 : _d.Outline;
9383
+ rego.outline = (_g = entity.Bruce) === null || _g === void 0 ? void 0 : _g.Outline;
9280
9384
  rego.cdn = this.item.cdnEnabled;
9281
- rego.schema = (_e = entity.Bruce) === null || _e === void 0 ? void 0 : _e.Schema;
9385
+ rego.schema = (_h = entity.Bruce) === null || _h === void 0 ? void 0 : _h.Schema;
9282
9386
  rego.canEdit = canEdit;
9387
+ rego.internalId = (_k = (_j = entity.Bruce) === null || _j === void 0 ? void 0 : _j.InternalID) !== null && _k !== void 0 ? _k : rego.internalId;
9283
9388
  // Marked as stale meaning some change was performed that requires a refresh.
9284
9389
  // This usually means a new sibling was added that we need to update.
9285
9390
  if (rego.stale) {
@@ -9309,7 +9414,7 @@
9309
9414
  menuItemId: this.item.id,
9310
9415
  requestRender: false
9311
9416
  });
9312
- (_f = this.clustering) === null || _f === void 0 ? void 0 : _f.RemoveEntity(id, false);
9417
+ (_l = this.clustering) === null || _l === void 0 ? void 0 : _l.RemoveEntity(id, false);
9313
9418
  }
9314
9419
  }
9315
9420
  this.viewer.scene.requestRender();
@@ -11347,6 +11452,14 @@
11347
11452
  // Entity ID -> styled status.
11348
11453
  // Helps us emit progress events.
11349
11454
  this.styledEntityIds = new Map();
11455
+ // InternalID to Entity ID for Styled Tileset Entities.
11456
+ // Populated when Entity data is available in styleTilesetFeatureFullData.
11457
+ this.styledByInternalId = new Map();
11458
+ // Cleanup function for the RecordChangeFeed subscription.
11459
+ this.feedSub = null;
11460
+ // Entity IDs waiting for a throttled re-style pass (1s rate limit).
11461
+ this.feedPendingRestyleIds = new Set();
11462
+ this.feedRestyleThrottleTimer = null;
11350
11463
  // % progress for how many Entities have been styled so far.
11351
11464
  // This can change as Tiles load in and more queue.
11352
11465
  this._styleProgress = 0;
@@ -11366,7 +11479,7 @@
11366
11479
  return this._styleProgress;
11367
11480
  }
11368
11481
  Init(params) {
11369
- var _a;
11482
+ var _a, _b;
11370
11483
  let { viewer, api, cTileset, fallbackStyleId, styleMapping, expandSources, menuItemId, register, scenario, historic } = params;
11371
11484
  this.viewer = viewer;
11372
11485
  this.api = api;
@@ -11422,6 +11535,37 @@
11422
11535
  });
11423
11536
  this.loaded = true;
11424
11537
  this.loadStyles();
11538
+ const feed = (_b = this.api) === null || _b === void 0 ? void 0 : _b.RecordChangeFeed;
11539
+ if (feed) {
11540
+ this.feedSub = feed.Subscribe({
11541
+ concepts: [BModels.AccountConcept.EConcept.ENTITY],
11542
+ actions: ["U"]
11543
+ }, (event) => {
11544
+ if (!this.styledByInternalId.size || !this.entityGatherer) {
11545
+ return;
11546
+ }
11547
+ const rangeStr = typeof event.data === "string" ? event.data : "";
11548
+ if (!rangeStr) {
11549
+ return;
11550
+ }
11551
+ for (const [internalId, entityId] of this.styledByInternalId) {
11552
+ if (BModels.RecordChangeFeed.isEntityInternalIdInRangeString(rangeStr, internalId)) {
11553
+ this.feedPendingRestyleIds.add(entityId);
11554
+ }
11555
+ }
11556
+ if (this.feedPendingRestyleIds.size && !this.feedRestyleThrottleTimer) {
11557
+ this.feedRestyleThrottleTimer = setTimeout(() => {
11558
+ this.feedRestyleThrottleTimer = null;
11559
+ if (this.disposed || !this.feedPendingRestyleIds.size || !this.entityGatherer) {
11560
+ return;
11561
+ }
11562
+ const ids = [...this.feedPendingRestyleIds];
11563
+ this.feedPendingRestyleIds.clear();
11564
+ this.entityGatherer.Queue(ids, true);
11565
+ }, 1000);
11566
+ }
11567
+ });
11568
+ }
11425
11569
  }
11426
11570
  /**
11427
11571
  * Updates style mapping and fallback style.
@@ -11574,11 +11718,19 @@
11574
11718
  });
11575
11719
  }
11576
11720
  Dispose() {
11721
+ var _a;
11577
11722
  if (this.disposed) {
11578
11723
  return;
11579
11724
  }
11580
11725
  this.disposed = true;
11581
11726
  this._styleProgressQueue.Dispose();
11727
+ (_a = this.feedSub) === null || _a === void 0 ? void 0 : _a.call(this);
11728
+ this.feedSub = null;
11729
+ if (this.feedRestyleThrottleTimer) {
11730
+ clearTimeout(this.feedRestyleThrottleTimer);
11731
+ this.feedRestyleThrottleTimer = null;
11732
+ }
11733
+ this.feedPendingRestyleIds.clear();
11582
11734
  this.disposeGatherer();
11583
11735
  }
11584
11736
  async loadStyles() {
@@ -11754,6 +11906,12 @@
11754
11906
  }
11755
11907
  }
11756
11908
  disposeGatherer() {
11909
+ if (this.feedRestyleThrottleTimer) {
11910
+ clearTimeout(this.feedRestyleThrottleTimer);
11911
+ this.feedRestyleThrottleTimer = null;
11912
+ }
11913
+ this.feedPendingRestyleIds.clear();
11914
+ this.styledByInternalId.clear();
11757
11915
  if (this.entityGatherer) {
11758
11916
  this.entityGatherer.Dispose();
11759
11917
  this.entityGatherer = null;
@@ -11816,7 +11974,7 @@
11816
11974
  this.styleTilesetFeatureFullData(rego, null, []);
11817
11975
  }
11818
11976
  styleTilesetFeatureFullData(rego, data, tags) {
11819
- var _a, _b;
11977
+ var _a, _b, _c;
11820
11978
  const visual = rego.visual;
11821
11979
  if (!visual || !(visual instanceof Cesium.Cesium3DTileFeature)) {
11822
11980
  return;
@@ -11838,6 +11996,10 @@
11838
11996
  override: override
11839
11997
  });
11840
11998
  this.overrideFeatureColor.set(rego.entityId, true);
11999
+ if (((_b = data === null || data === void 0 ? void 0 : data.Bruce) === null || _b === void 0 ? void 0 : _b.InternalID) != null) {
12000
+ rego.internalId = data.Bruce.InternalID;
12001
+ this.styledByInternalId.set(data.Bruce.InternalID, rego.entityId);
12002
+ }
11841
12003
  this.styledEntityIds.set(rego.entityId, true);
11842
12004
  this._styleProgressQueue.Call();
11843
12005
  // Since we only need to update it for scenarios right now.
@@ -11846,7 +12008,7 @@
11846
12008
  // Update the Entity's rego state.
11847
12009
  let changed = false;
11848
12010
  if (isOutlineChanged(rego, data)) {
11849
- rego.outline = (_b = data === null || data === void 0 ? void 0 : data.Bruce) === null || _b === void 0 ? void 0 : _b.Outline;
12011
+ rego.outline = (_c = data === null || data === void 0 ? void 0 : data.Bruce) === null || _c === void 0 ? void 0 : _c.Outline;
11850
12012
  changed = true;
11851
12013
  }
11852
12014
  // Something changed, trigger a rego update.
@@ -12877,6 +13039,10 @@
12877
13039
  viaCdn: false
12878
13040
  });
12879
13041
  }
13042
+ // Should not occur.
13043
+ if (!tileset.loadUrl && loadUrl) {
13044
+ tileset.loadUrl = loadUrl;
13045
+ }
12880
13046
  // TODO: we shouldn't just assume we'll need it, huge assemblies are 100+ MB.
12881
13047
  // TODO: this is a problem as we need to know what nodes are collapsed...
12882
13048
  // In >v1 the model-tree sits in its own file.
@@ -13155,6 +13321,9 @@
13155
13321
  else if (lowered === "brucepath") {
13156
13322
  this.featurePropCache.set("brucePath", prop);
13157
13323
  }
13324
+ else if (lowered === "internalid") {
13325
+ this.featurePropCache.set("internalId", prop);
13326
+ }
13158
13327
  }
13159
13328
  }
13160
13329
  /**
@@ -13283,6 +13452,14 @@
13283
13452
  }
13284
13453
  }
13285
13454
  }
13455
+ const internalIdProp = this.featurePropCache.get("internalId");
13456
+ if (internalIdProp) {
13457
+ const raw = feature.getProperty(internalIdProp);
13458
+ const parsed = raw != null ? +raw : NaN;
13459
+ if (Number.isInteger(parsed)) {
13460
+ rego.internalId = parsed;
13461
+ }
13462
+ }
13286
13463
  this.loadedCesiumEntities[rego.entityId] = rego;
13287
13464
  this.visualsManager.AddRego({
13288
13465
  rego,
@@ -16485,6 +16662,9 @@
16485
16662
  else if (lowered === "building_id" || lowered === "buildingid") {
16486
16663
  this.featurePropCache.set("BuildingID", prop);
16487
16664
  }
16665
+ else if (lowered === "internalid") {
16666
+ this.featurePropCache.set("internalId", prop);
16667
+ }
16488
16668
  }
16489
16669
  }
16490
16670
  Dispose() {
@@ -16595,6 +16775,14 @@
16595
16775
  }
16596
16776
  }
16597
16777
  }
16778
+ const internalIdProp = this.featurePropCache.get("internalId");
16779
+ if (internalIdProp) {
16780
+ const raw = feature.getProperty(internalIdProp);
16781
+ const parsed = raw != null ? +raw : NaN;
16782
+ if (Number.isInteger(parsed)) {
16783
+ rego.internalId = parsed;
16784
+ }
16785
+ }
16598
16786
  this.loadedCesiumEntities[rego.entityId] = rego;
16599
16787
  this.visualsManager.AddRego({
16600
16788
  rego,
@@ -36071,7 +36259,7 @@
36071
36259
  }
36072
36260
  }
36073
36261
 
36074
- const VERSION = "6.6.4";
36262
+ const VERSION = "6.6.6";
36075
36263
  /**
36076
36264
  * Updates the environment instance used by bruce-cesium to one specified.
36077
36265
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.