bruce-cesium 7.6.1 → 7.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bruce-cesium.es5.js +2535 -385
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +2524 -382
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +3 -1
- package/dist/lib/bruce-cesium.js.map +1 -1
- package/dist/lib/rendering/cesium-animated-property.js +63 -107
- package/dist/lib/rendering/cesium-animated-property.js.map +1 -1
- package/dist/lib/rendering/entity-gatherer.js +11 -3
- package/dist/lib/rendering/entity-gatherer.js.map +1 -1
- package/dist/lib/rendering/menu-item-creator.js +44 -23
- package/dist/lib/rendering/menu-item-creator.js.map +1 -1
- package/dist/lib/rendering/menu-item-manager.js +199 -17
- package/dist/lib/rendering/menu-item-manager.js.map +1 -1
- package/dist/lib/rendering/menu-item-styles.js +151 -0
- package/dist/lib/rendering/menu-item-styles.js.map +1 -0
- package/dist/lib/rendering/relation-render-engine.js +24 -5
- package/dist/lib/rendering/relation-render-engine.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-label-group.js +13 -9
- package/dist/lib/rendering/render-managers/common/entity-label-group.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-label.js +68 -7
- package/dist/lib/rendering/render-managers/common/entity-label.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-rerender-maintain-state.js +44 -5
- package/dist/lib/rendering/render-managers/common/entity-rerender-maintain-state.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/entity-simulation.js +483 -0
- package/dist/lib/rendering/render-managers/common/entity-simulation.js.map +1 -0
- package/dist/lib/rendering/render-managers/common/historic-trail.js +123 -0
- package/dist/lib/rendering/render-managers/common/historic-trail.js.map +1 -0
- package/dist/lib/rendering/render-managers/common/historic-utils.js +17 -6
- package/dist/lib/rendering/render-managers/common/historic-utils.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-datalab-render-manager.js +13 -2
- package/dist/lib/rendering/render-managers/entities/entities-datalab-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js +20 -2
- package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-loaded-render-manager.js +13 -2
- package/dist/lib/rendering/render-managers/entities/entities-loaded-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-render-manager.js +66 -5
- package/dist/lib/rendering/render-managers/entities/entities-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entity-render-manager.js +11 -1
- package/dist/lib/rendering/render-managers/entities/entity-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/other/assembly-render-manager.js +745 -106
- package/dist/lib/rendering/render-managers/other/assembly-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/other/legacy-relations-render-manager.js +23 -1
- package/dist/lib/rendering/render-managers/other/legacy-relations-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/other/relations-render-manager.js +23 -1
- package/dist/lib/rendering/render-managers/other/relations-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-arb-render-manager.js +19 -0
- package/dist/lib/rendering/render-managers/tilesets/tileset-arb-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js +145 -40
- package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-entities-render-manager.js +18 -0
- package/dist/lib/rendering/render-managers/tilesets/tileset-entities-render-manager.js.map +1 -1
- package/dist/lib/rendering/tileset-styler.js +1 -1
- package/dist/lib/rendering/tileset-styler.js.map +1 -1
- package/dist/lib/rendering/visual-register-culler.js +2 -0
- package/dist/lib/rendering/visual-register-culler.js.map +1 -1
- package/dist/lib/rendering/visuals-register.js +89 -20
- package/dist/lib/rendering/visuals-register.js.map +1 -1
- package/dist/lib/utils/entity-utils.js +43 -2
- package/dist/lib/utils/entity-utils.js.map +1 -1
- package/dist/lib/widgets/tabs-left-panel/widget-left-panel-tab-menu-items.js +64 -12
- package/dist/lib/widgets/tabs-left-panel/widget-left-panel-tab-menu-items.js.map +1 -1
- package/dist/lib/widgets/widget-info-view.js +20 -7
- package/dist/lib/widgets/widget-info-view.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +3 -1
- package/dist/types/rendering/cesium-animated-property.d.ts +8 -6
- package/dist/types/rendering/entity-gatherer.d.ts +6 -1
- package/dist/types/rendering/menu-item-manager.d.ts +58 -1
- package/dist/types/rendering/menu-item-styles.d.ts +30 -0
- package/dist/types/rendering/relation-render-engine.d.ts +10 -0
- package/dist/types/rendering/render-managers/common/entity-label-group.d.ts +3 -2
- package/dist/types/rendering/render-managers/common/entity-label.d.ts +4 -0
- package/dist/types/rendering/render-managers/common/entity-rerender-maintain-state.d.ts +20 -0
- package/dist/types/rendering/render-managers/common/entity-simulation.d.ts +126 -0
- package/dist/types/rendering/render-managers/common/historic-trail.d.ts +30 -0
- package/dist/types/rendering/render-managers/common/historic-utils.d.ts +4 -0
- package/dist/types/rendering/render-managers/entities/entities-datalab-render-manager.d.ts +7 -1
- package/dist/types/rendering/render-managers/entities/entities-ids-render-manager.d.ts +7 -1
- package/dist/types/rendering/render-managers/entities/entities-loaded-render-manager.d.ts +7 -1
- package/dist/types/rendering/render-managers/entities/entities-render-manager.d.ts +10 -1
- package/dist/types/rendering/render-managers/entities/entity-render-manager.d.ts +7 -1
- package/dist/types/rendering/render-managers/other/assembly-render-manager.d.ts +79 -2
- package/dist/types/rendering/render-managers/other/legacy-relations-render-manager.d.ts +5 -0
- package/dist/types/rendering/render-managers/other/relations-render-manager.d.ts +5 -0
- package/dist/types/rendering/render-managers/render-manager.d.ts +14 -1
- package/dist/types/rendering/render-managers/tilesets/tileset-arb-render-manager.d.ts +8 -1
- package/dist/types/rendering/render-managers/tilesets/tileset-cad-render-manager.d.ts +16 -2
- package/dist/types/rendering/render-managers/tilesets/tileset-entities-render-manager.d.ts +8 -1
- package/dist/types/rendering/tileset-styler.d.ts +2 -0
- package/dist/types/rendering/visuals-register.d.ts +13 -0
- package/dist/types/utils/entity-utils.d.ts +6 -0
- package/dist/types/widgets/tabs-left-panel/widget-left-panel-tab-menu-items.d.ts +1 -0
- package/dist/types/widgets/widget-info-view.d.ts +1 -0
- package/package.json +2 -2
package/dist/bruce-cesium.umd.js
CHANGED
|
@@ -2621,13 +2621,13 @@
|
|
|
2621
2621
|
class AnimateTPositionSeries {
|
|
2622
2622
|
constructor(params) {
|
|
2623
2623
|
this.lastCalcAttitude = null;
|
|
2624
|
-
// Cache for calculated values.
|
|
2624
|
+
// Cache for calculated values: the scene time and set of positions they were worked out for.
|
|
2625
2625
|
this.lastCalcTime = null;
|
|
2626
|
+
this.lastCalcRevision = -1;
|
|
2626
2627
|
this.lastCalcPos3d = null;
|
|
2627
|
-
this.lastCalcPosApplyOverTime = false;
|
|
2628
|
-
this.lastCalcPos3dApplyOverTimeTarget = null;
|
|
2629
|
-
this.lastCalcPos3dApplyOverTimeTimeStart = null;
|
|
2630
2628
|
this.lastCalcHeading = null;
|
|
2629
|
+
// Bumped whenever the positions change, so a still clock re-applies a changed series.
|
|
2630
|
+
this.revision = 0;
|
|
2631
2631
|
this.removal = null;
|
|
2632
2632
|
// Track the timeline range for which we have data.
|
|
2633
2633
|
this.minDate = null;
|
|
@@ -2657,6 +2657,7 @@
|
|
|
2657
2657
|
if (!newPositions || newPositions.length === 0) {
|
|
2658
2658
|
return;
|
|
2659
2659
|
}
|
|
2660
|
+
this.revision++;
|
|
2660
2661
|
// Add new positions to our map, overwriting any existing positions with the same timestamp
|
|
2661
2662
|
for (const pos of newPositions) {
|
|
2662
2663
|
const key = pos.dateTime.toISOString();
|
|
@@ -2680,6 +2681,17 @@
|
|
|
2680
2681
|
}
|
|
2681
2682
|
}
|
|
2682
2683
|
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Replaces every position with these, eg. once some that were simulated have been cleared.
|
|
2686
|
+
* @param positions Positions to animate through from now on.
|
|
2687
|
+
*/
|
|
2688
|
+
replacePositions(positions) {
|
|
2689
|
+
this.positionsMap.clear();
|
|
2690
|
+
this.positions = [];
|
|
2691
|
+
this.minDate = null;
|
|
2692
|
+
this.maxDate = null;
|
|
2693
|
+
this.addPositions(positions);
|
|
2694
|
+
}
|
|
2683
2695
|
/**
|
|
2684
2696
|
* Get the current date range covered by our positions.
|
|
2685
2697
|
*/
|
|
@@ -2727,106 +2739,47 @@
|
|
|
2727
2739
|
/*
|
|
2728
2740
|
* Returns the attitude of the record at an index, or nothing recorded when it names none.
|
|
2729
2741
|
*/
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2742
|
+
/*
|
|
2743
|
+
* Pitch and roll between two positions the short way round; an angle only one names is held.
|
|
2744
|
+
*/
|
|
2745
|
+
attitudeBetween(indexLast, indexNext, timeMs) {
|
|
2746
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2747
|
+
const a = indexLast >= 0 ? (_a = this.positions) === null || _a === void 0 ? void 0 : _a[indexLast] : null;
|
|
2748
|
+
const b = indexNext >= 0 ? (_b = this.positions) === null || _b === void 0 ? void 0 : _b[indexNext] : null;
|
|
2749
|
+
const span = a && b ? b.dateTime.getTime() - a.dateTime.getTime() : 0;
|
|
2750
|
+
const t = span > 0 ? (timeMs - a.dateTime.getTime()) / span : 0;
|
|
2751
|
+
const turn = (x, y) => {
|
|
2752
|
+
if (x == null || y == null) {
|
|
2753
|
+
return x !== null && x !== void 0 ? x : null;
|
|
2754
|
+
}
|
|
2755
|
+
return x + (Cesium.Math.negativePiToPi(Cesium.Math.toRadians(y - x)) * 180 / Math.PI) * t;
|
|
2756
|
+
};
|
|
2757
|
+
return { pitch: turn((_c = a === null || a === void 0 ? void 0 : a.pitch) !== null && _c !== void 0 ? _c : null, (_d = b === null || b === void 0 ? void 0 : b.pitch) !== null && _d !== void 0 ? _d : null), roll: turn((_e = a === null || a === void 0 ? void 0 : a.roll) !== null && _e !== void 0 ? _e : null, (_f = b === null || b === void 0 ? void 0 : b.roll) !== null && _f !== void 0 ? _f : null) };
|
|
2734
2758
|
}
|
|
2759
|
+
/*
|
|
2760
|
+
* Places the series at the scene's time, exactly rather than eased, so what moves with it never lags the clock.
|
|
2761
|
+
*/
|
|
2735
2762
|
update() {
|
|
2763
|
+
var _a;
|
|
2736
2764
|
if (!this.positions || this.positions.length === 0) {
|
|
2737
2765
|
return;
|
|
2738
2766
|
}
|
|
2739
|
-
//
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
const currentRealTimeMs = Date.now();
|
|
2744
|
-
// Calculate the ideal position based on current time.
|
|
2745
|
-
const targetPosition = this.calculatePosition(nowTimeMs);
|
|
2746
|
-
// Initialize if this is the first update.
|
|
2747
|
-
if (!this.lastCalcPos3d) {
|
|
2748
|
-
this.lastCalcPos3d = targetPosition.pos3d;
|
|
2749
|
-
this.lastCalcAttitude = this.attitudeAt(targetPosition.indexLast);
|
|
2750
|
-
this.onUpdate(targetPosition.pos3d, this.lastCalcHeading, this.lastCalcAttitude);
|
|
2751
|
-
return;
|
|
2752
|
-
}
|
|
2753
|
-
// Check if target has changed.
|
|
2754
|
-
if (!this.lastCalcPos3dApplyOverTimeTarget ||
|
|
2755
|
-
!Cesium.Cartesian3.equals(this.lastCalcPos3dApplyOverTimeTarget, targetPosition.pos3d)) {
|
|
2756
|
-
// If we were already interpolating, get the current interpolated position as our new starting point.
|
|
2757
|
-
if (this.lastCalcPosApplyOverTime && this.lastCalcPos3dApplyOverTimeTimeStart) {
|
|
2758
|
-
// Calculate where we are in the current interpolation.
|
|
2759
|
-
const currentInterpolatedPos = this.interpolatePos3dOverTime(this.lastCalcPos3dApplyOverTimeTimeStart, currentRealTimeMs);
|
|
2760
|
-
// Use this as our new starting position.
|
|
2761
|
-
this.lastCalcPos3d = currentInterpolatedPos;
|
|
2762
|
-
}
|
|
2763
|
-
// Set new target and start time.
|
|
2764
|
-
this.lastCalcPos3dApplyOverTimeTarget = targetPosition.pos3d;
|
|
2765
|
-
this.lastCalcPos3dApplyOverTimeTimeStart = currentRealTimeMs;
|
|
2766
|
-
this.lastCalcPosApplyOverTime = true;
|
|
2767
|
-
}
|
|
2768
|
-
// Calculate the interpolated position.
|
|
2769
|
-
let pos3d;
|
|
2770
|
-
if (this.lastCalcPosApplyOverTime) {
|
|
2771
|
-
pos3d = this.interpolatePos3dOverTime(this.lastCalcPos3dApplyOverTimeTimeStart, currentRealTimeMs);
|
|
2772
|
-
// If we've reached the target, update our base position.
|
|
2773
|
-
if (Cesium.Cartesian3.distance(pos3d, this.lastCalcPos3dApplyOverTimeTarget) < 0.01) {
|
|
2774
|
-
this.lastCalcPos3d = this.lastCalcPos3dApplyOverTimeTarget;
|
|
2775
|
-
this.lastCalcPosApplyOverTime = false;
|
|
2776
|
-
}
|
|
2767
|
+
// The clock's time is the frame being drawn; the last render time is the frame before it.
|
|
2768
|
+
const nowTimeMs = Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime();
|
|
2769
|
+
if (nowTimeMs === this.lastCalcTime && this.revision === this.lastCalcRevision) {
|
|
2770
|
+
return;
|
|
2777
2771
|
}
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
const currentToTargetDistance = Cesium.Cartesian3.distance(this.lastCalcPos3d, this.lastCalcPos3dApplyOverTimeTarget);
|
|
2786
|
-
if (currentToTargetDistance >= minDistanceThreshold) {
|
|
2787
|
-
const lastPos = {
|
|
2788
|
-
pos3d: this.lastCalcPos3d,
|
|
2789
|
-
dateTime: this.lastCalcPos3dApplyOverTimeTimeStart ? new Date(this.lastCalcPos3dApplyOverTimeTimeStart) : null,
|
|
2790
|
-
heading: null
|
|
2791
|
-
};
|
|
2792
|
-
const nextPos = {
|
|
2793
|
-
pos3d: this.lastCalcPos3dApplyOverTimeTarget,
|
|
2794
|
-
dateTime: null,
|
|
2795
|
-
heading: null
|
|
2796
|
-
};
|
|
2797
|
-
if (lastPos && nextPos) {
|
|
2798
|
-
this.lastCalcHeading = this.calculateHeading(nowTimeMs, lastPos, nextPos);
|
|
2799
|
-
}
|
|
2800
|
-
}
|
|
2801
|
-
}
|
|
2772
|
+
this.lastCalcTime = nowTimeMs;
|
|
2773
|
+
this.lastCalcRevision = this.revision;
|
|
2774
|
+
const target = this.calculatePosition(nowTimeMs);
|
|
2775
|
+
const lastPos = this.positions[target.indexLast];
|
|
2776
|
+
const nextPos = this.positions[target.indexNext];
|
|
2777
|
+
if (lastPos && nextPos) {
|
|
2778
|
+
this.lastCalcHeading = (_a = this.calculateHeading(nowTimeMs, lastPos, nextPos)) !== null && _a !== void 0 ? _a : this.lastCalcHeading;
|
|
2802
2779
|
}
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
const nextPos = posses[targetPosition.indexNext];
|
|
2807
|
-
if (lastPos && nextPos) {
|
|
2808
|
-
this.lastCalcHeading = this.calculateHeading(nowTimeMs, lastPos, nextPos);
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
|
-
// Provide the calculated values to the caller.
|
|
2812
|
-
this.lastCalcAttitude = this.attitudeAt(targetPosition.indexLast);
|
|
2813
|
-
this.onUpdate(pos3d, this.lastCalcHeading, this.lastCalcAttitude);
|
|
2814
|
-
}
|
|
2815
|
-
interpolatePos3dOverTime(startTimeMs, currentTimeMs) {
|
|
2816
|
-
const lastPos = this.lastCalcPos3d;
|
|
2817
|
-
const targetPos = this.lastCalcPos3dApplyOverTimeTarget;
|
|
2818
|
-
if (!lastPos || !targetPos) {
|
|
2819
|
-
return lastPos ? lastPos : targetPos;
|
|
2820
|
-
}
|
|
2821
|
-
const interpolationDuration = 200;
|
|
2822
|
-
const elapsedTime = currentTimeMs - startTimeMs;
|
|
2823
|
-
let progress = Math.min(elapsedTime / interpolationDuration, 1.0);
|
|
2824
|
-
// Optional step to make it smoother.
|
|
2825
|
-
progress = this.easeInOutQuad(progress);
|
|
2826
|
-
return Cesium.Cartesian3.lerp(lastPos, targetPos, progress, new Cesium.Cartesian3());
|
|
2827
|
-
}
|
|
2828
|
-
easeInOutQuad(t) {
|
|
2829
|
-
return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
|
|
2780
|
+
this.lastCalcPos3d = target.pos3d;
|
|
2781
|
+
this.lastCalcAttitude = this.attitudeBetween(target.indexLast, target.indexNext, nowTimeMs);
|
|
2782
|
+
this.onUpdate(target.pos3d, this.lastCalcHeading, this.lastCalcAttitude);
|
|
2830
2783
|
}
|
|
2831
2784
|
/**
|
|
2832
2785
|
* Pre-process headings in the series.
|
|
@@ -2852,14 +2805,14 @@
|
|
|
2852
2805
|
* Calculate the position at the given time.
|
|
2853
2806
|
*/
|
|
2854
2807
|
calculatePosition(currentTimeMs) {
|
|
2808
|
+
var _a, _b;
|
|
2855
2809
|
const posses = this.positions;
|
|
2856
2810
|
// No positions to interpolate
|
|
2857
2811
|
if (!posses || posses.length === 0) {
|
|
2858
2812
|
return {
|
|
2859
2813
|
pos3d: new Cesium.Cartesian3(),
|
|
2860
2814
|
indexLast: -1,
|
|
2861
|
-
indexNext: -1
|
|
2862
|
-
applyOverTime: false
|
|
2815
|
+
indexNext: -1
|
|
2863
2816
|
};
|
|
2864
2817
|
}
|
|
2865
2818
|
// See if we're before the first position.
|
|
@@ -2867,8 +2820,7 @@
|
|
|
2867
2820
|
return {
|
|
2868
2821
|
pos3d: posses[0].pos3d,
|
|
2869
2822
|
indexLast: 0,
|
|
2870
|
-
indexNext: 0
|
|
2871
|
-
applyOverTime: true
|
|
2823
|
+
indexNext: 0
|
|
2872
2824
|
};
|
|
2873
2825
|
}
|
|
2874
2826
|
// See if we're after the last position.
|
|
@@ -2877,8 +2829,7 @@
|
|
|
2877
2829
|
return {
|
|
2878
2830
|
pos3d: posses[lastIndex].pos3d,
|
|
2879
2831
|
indexLast: lastIndex,
|
|
2880
|
-
indexNext: lastIndex
|
|
2881
|
-
applyOverTime: true
|
|
2832
|
+
indexNext: lastIndex
|
|
2882
2833
|
};
|
|
2883
2834
|
}
|
|
2884
2835
|
// Binary search to find the closest position.
|
|
@@ -2904,20 +2855,25 @@
|
|
|
2904
2855
|
return {
|
|
2905
2856
|
pos3d: last.pos3d,
|
|
2906
2857
|
indexLast: lastIndex,
|
|
2907
|
-
indexNext: lastIndex
|
|
2908
|
-
applyOverTime: true
|
|
2858
|
+
indexNext: lastIndex
|
|
2909
2859
|
};
|
|
2910
2860
|
}
|
|
2911
2861
|
// Interpolate between the two closest positions.
|
|
2912
2862
|
const lastTime = last.dateTime.getTime();
|
|
2913
2863
|
const nextTime = next.dateTime.getTime();
|
|
2914
2864
|
const progress = (currentTimeMs - lastTime) / (nextTime - lastTime);
|
|
2915
|
-
|
|
2865
|
+
// A straight line between two points on a curved path cuts inside it, so it is lifted back out.
|
|
2866
|
+
const chord = Cesium.Cartesian3.lerp(last.pos3d, next.pos3d, progress, new Cesium.Cartesian3());
|
|
2867
|
+
const chordCarto = Cesium.Cartographic.fromCartesian(chord);
|
|
2868
|
+
const lastHeight = (_a = Cesium.Cartographic.fromCartesian(last.pos3d)) === null || _a === void 0 ? void 0 : _a.height;
|
|
2869
|
+
const nextHeight = (_b = Cesium.Cartographic.fromCartesian(next.pos3d)) === null || _b === void 0 ? void 0 : _b.height;
|
|
2870
|
+
const interpolatedPos = chordCarto && lastHeight != null && nextHeight != null
|
|
2871
|
+
? Cesium.Cartesian3.fromRadians(chordCarto.longitude, chordCarto.latitude, Cesium.Math.lerp(lastHeight, nextHeight, progress))
|
|
2872
|
+
: chord;
|
|
2916
2873
|
return {
|
|
2917
2874
|
pos3d: interpolatedPos,
|
|
2918
2875
|
indexLast: lastIndex,
|
|
2919
|
-
indexNext: nextIndex
|
|
2920
|
-
applyOverTime: false
|
|
2876
|
+
indexNext: nextIndex
|
|
2921
2877
|
};
|
|
2922
2878
|
}
|
|
2923
2879
|
/**
|
|
@@ -5481,6 +5437,481 @@
|
|
|
5481
5437
|
return result;
|
|
5482
5438
|
}
|
|
5483
5439
|
|
|
5440
|
+
(function (EntitySimulation) {
|
|
5441
|
+
const VIEWER_KEY = "_nextspaceSimulation";
|
|
5442
|
+
/**
|
|
5443
|
+
* The set used when a caller does not name one.
|
|
5444
|
+
*/
|
|
5445
|
+
EntitySimulation.DEFAULT_SET = "default";
|
|
5446
|
+
// Record parts replaced whole rather than merged field by field, eg. a matrix or a geometry.
|
|
5447
|
+
const WHOLE_RECORD_PARTS = new Set(["geometry", "boundaries", "assemblyPosition"]);
|
|
5448
|
+
// Record parts that carry Entity data, in the order they are laid over an Entity.
|
|
5449
|
+
const RECORD_PARTS = ["location", "transform", "geometry", "boundaries", "assemblyPosition", "data"];
|
|
5450
|
+
/**
|
|
5451
|
+
* The store for a viewer, made on first use and shared by everything drawing into that scene.
|
|
5452
|
+
*/
|
|
5453
|
+
function Get(viewer) {
|
|
5454
|
+
if (!viewer) {
|
|
5455
|
+
return null;
|
|
5456
|
+
}
|
|
5457
|
+
if (!viewer[VIEWER_KEY]) {
|
|
5458
|
+
viewer[VIEWER_KEY] = new Store();
|
|
5459
|
+
}
|
|
5460
|
+
return viewer[VIEWER_KEY];
|
|
5461
|
+
}
|
|
5462
|
+
EntitySimulation.Get = Get;
|
|
5463
|
+
function isPlainObject(value) {
|
|
5464
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
5465
|
+
}
|
|
5466
|
+
// Entity values replaced whole by a patch, since half of one geometry over another describes neither.
|
|
5467
|
+
const WHOLE_ENTITY_PARTS = new Set(["VectorGeometry", "Boundaries", "AssemblyPosition"]);
|
|
5468
|
+
/**
|
|
5469
|
+
* Returns base with patch laid over it: objects merge key by key, anything else replaces.
|
|
5470
|
+
* @param whole names keys at the top level, or under Bruce, whose value is replaced rather than merged.
|
|
5471
|
+
*/
|
|
5472
|
+
function Overlay(base, patch, whole = WHOLE_ENTITY_PARTS) {
|
|
5473
|
+
const lay = (into, over, depth, underBruce) => {
|
|
5474
|
+
if (over === undefined) {
|
|
5475
|
+
return into;
|
|
5476
|
+
}
|
|
5477
|
+
if (!isPlainObject(over) || !isPlainObject(into)) {
|
|
5478
|
+
return over;
|
|
5479
|
+
}
|
|
5480
|
+
const merged = { ...into };
|
|
5481
|
+
for (const key of Object.keys(over)) {
|
|
5482
|
+
const replace = (depth === 0 || underBruce) && whole.has(key);
|
|
5483
|
+
merged[key] = replace ? over[key] : lay(merged[key], over[key], depth + 1, depth === 0 && key === "Bruce");
|
|
5484
|
+
}
|
|
5485
|
+
return merged;
|
|
5486
|
+
};
|
|
5487
|
+
return lay(base, patch, 0, false);
|
|
5488
|
+
}
|
|
5489
|
+
EntitySimulation.Overlay = Overlay;
|
|
5490
|
+
/*
|
|
5491
|
+
* Lays one record's parts over another's, each part replaced whole where a part is one value.
|
|
5492
|
+
*/
|
|
5493
|
+
function overlayRecord(base, over) {
|
|
5494
|
+
return Overlay(base, over, WHOLE_RECORD_PARTS);
|
|
5495
|
+
}
|
|
5496
|
+
/**
|
|
5497
|
+
* Each value a record names, as a path into the record. A part replaced whole is one value.
|
|
5498
|
+
*/
|
|
5499
|
+
function recordPaths(record) {
|
|
5500
|
+
const paths = [];
|
|
5501
|
+
const walk = (value, path) => {
|
|
5502
|
+
if (isPlainObject(value) && !(path.length === 1 && WHOLE_RECORD_PARTS.has(path[0]))) {
|
|
5503
|
+
for (const key of Object.keys(value)) {
|
|
5504
|
+
walk(value[key], [...path, key]);
|
|
5505
|
+
}
|
|
5506
|
+
return;
|
|
5507
|
+
}
|
|
5508
|
+
if (value !== undefined) {
|
|
5509
|
+
paths.push(path);
|
|
5510
|
+
}
|
|
5511
|
+
};
|
|
5512
|
+
for (const part of RECORD_PARTS) {
|
|
5513
|
+
if ((record === null || record === void 0 ? void 0 : record[part]) != null) {
|
|
5514
|
+
walk(record[part], [part]);
|
|
5515
|
+
}
|
|
5516
|
+
}
|
|
5517
|
+
return paths;
|
|
5518
|
+
}
|
|
5519
|
+
/*
|
|
5520
|
+
* A copy of the record without the values at these paths, dropping objects left empty.
|
|
5521
|
+
*/
|
|
5522
|
+
function withoutPaths(record, paths) {
|
|
5523
|
+
const strip = (value, path) => {
|
|
5524
|
+
if (!isPlainObject(value) || !(path[0] in value)) {
|
|
5525
|
+
return value;
|
|
5526
|
+
}
|
|
5527
|
+
const copy = { ...value };
|
|
5528
|
+
if (path.length === 1) {
|
|
5529
|
+
delete copy[path[0]];
|
|
5530
|
+
}
|
|
5531
|
+
else {
|
|
5532
|
+
const inner = strip(copy[path[0]], path.slice(1));
|
|
5533
|
+
if (isPlainObject(inner) && !Object.keys(inner).length) {
|
|
5534
|
+
delete copy[path[0]];
|
|
5535
|
+
}
|
|
5536
|
+
else {
|
|
5537
|
+
copy[path[0]] = inner;
|
|
5538
|
+
}
|
|
5539
|
+
}
|
|
5540
|
+
return copy;
|
|
5541
|
+
};
|
|
5542
|
+
let stripped = record;
|
|
5543
|
+
for (const path of paths) {
|
|
5544
|
+
stripped = strip(stripped, path);
|
|
5545
|
+
}
|
|
5546
|
+
return stripped;
|
|
5547
|
+
}
|
|
5548
|
+
/*
|
|
5549
|
+
* Whether a record still says anything about its Entity.
|
|
5550
|
+
*/
|
|
5551
|
+
function hasContent(record) {
|
|
5552
|
+
return RECORD_PARTS.some(part => {
|
|
5553
|
+
const value = record === null || record === void 0 ? void 0 : record[part];
|
|
5554
|
+
return value != null && !(isPlainObject(value) && !Object.keys(value).length);
|
|
5555
|
+
});
|
|
5556
|
+
}
|
|
5557
|
+
function timeOf(record) {
|
|
5558
|
+
return (record === null || record === void 0 ? void 0 : record.dateTime) ? new Date(record.dateTime).getTime() : NaN;
|
|
5559
|
+
}
|
|
5560
|
+
class Store {
|
|
5561
|
+
constructor() {
|
|
5562
|
+
// Insertion order is precedence: a later set wins.
|
|
5563
|
+
this.sets = new Map();
|
|
5564
|
+
this.onChanged = new BModels.BruceEvent();
|
|
5565
|
+
}
|
|
5566
|
+
/**
|
|
5567
|
+
* Triggered after anything is simulated or cleared, naming the Entities affected.
|
|
5568
|
+
*/
|
|
5569
|
+
get OnChanged() {
|
|
5570
|
+
return this.onChanged;
|
|
5571
|
+
}
|
|
5572
|
+
/**
|
|
5573
|
+
* Whether anything at all is simulated, so a caller can skip the work when nothing is.
|
|
5574
|
+
*/
|
|
5575
|
+
get IsEmpty() {
|
|
5576
|
+
for (const set of this.sets.values()) {
|
|
5577
|
+
if (set.entities.size || set.patches.size || set.records.size) {
|
|
5578
|
+
return false;
|
|
5579
|
+
}
|
|
5580
|
+
}
|
|
5581
|
+
return true;
|
|
5582
|
+
}
|
|
5583
|
+
/**
|
|
5584
|
+
* The names of the sets holding anything, oldest first.
|
|
5585
|
+
*/
|
|
5586
|
+
GetSets() {
|
|
5587
|
+
return Array.from(this.sets.keys());
|
|
5588
|
+
}
|
|
5589
|
+
/**
|
|
5590
|
+
* The time each set's records span, oldest set first, for sets holding any records.
|
|
5591
|
+
*/
|
|
5592
|
+
GetSetRanges() {
|
|
5593
|
+
const ranges = [];
|
|
5594
|
+
for (const [name, set] of this.sets) {
|
|
5595
|
+
let startMs = Infinity;
|
|
5596
|
+
let endMs = -Infinity;
|
|
5597
|
+
for (const byTime of set.records.values()) {
|
|
5598
|
+
for (const ms of byTime.keys()) {
|
|
5599
|
+
startMs = Math.min(startMs, ms);
|
|
5600
|
+
endMs = Math.max(endMs, ms);
|
|
5601
|
+
}
|
|
5602
|
+
}
|
|
5603
|
+
if (set.records.size) {
|
|
5604
|
+
ranges.push({ set: name, startMs, endMs, entityIds: Array.from(set.records.keys()) });
|
|
5605
|
+
}
|
|
5606
|
+
}
|
|
5607
|
+
return ranges;
|
|
5608
|
+
}
|
|
5609
|
+
setFor(name) {
|
|
5610
|
+
const key = name || EntitySimulation.DEFAULT_SET;
|
|
5611
|
+
let set = this.sets.get(key);
|
|
5612
|
+
if (!set) {
|
|
5613
|
+
set = { entities: new Map(), patches: new Map(), records: new Map() };
|
|
5614
|
+
this.sets.set(key, set);
|
|
5615
|
+
}
|
|
5616
|
+
return set;
|
|
5617
|
+
}
|
|
5618
|
+
/**
|
|
5619
|
+
* Replaces the stand-in for each Entity given, within a set.
|
|
5620
|
+
*/
|
|
5621
|
+
SetEntities(entities, set) {
|
|
5622
|
+
this.setBlobs(entities, set, false);
|
|
5623
|
+
}
|
|
5624
|
+
/**
|
|
5625
|
+
* Replaces the patch for each Entity given, within a set. A patch names only the data it changes.
|
|
5626
|
+
*/
|
|
5627
|
+
SetPatches(patches, set) {
|
|
5628
|
+
this.setBlobs(patches, set, true);
|
|
5629
|
+
}
|
|
5630
|
+
setBlobs(blobs, set, patch) {
|
|
5631
|
+
var _a;
|
|
5632
|
+
const ids = [];
|
|
5633
|
+
for (const blob of blobs || []) {
|
|
5634
|
+
const id = (_a = blob === null || blob === void 0 ? void 0 : blob.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
5635
|
+
if (!id) {
|
|
5636
|
+
continue;
|
|
5637
|
+
}
|
|
5638
|
+
const held = this.setFor(set);
|
|
5639
|
+
(patch ? held.patches : held.entities).set(id, blob);
|
|
5640
|
+
ids.push(id);
|
|
5641
|
+
}
|
|
5642
|
+
if (ids.length) {
|
|
5643
|
+
this.onChanged.Trigger({ entityIds: ids, entities: true, records: false, set: set || EntitySimulation.DEFAULT_SET });
|
|
5644
|
+
}
|
|
5645
|
+
}
|
|
5646
|
+
/**
|
|
5647
|
+
* Adds records to each Entity's simulated history within a set, replacing any at the same instant.
|
|
5648
|
+
*/
|
|
5649
|
+
SetRecords(records, set) {
|
|
5650
|
+
const ids = new Set();
|
|
5651
|
+
for (const record of records || []) {
|
|
5652
|
+
const id = record === null || record === void 0 ? void 0 : record.entityId;
|
|
5653
|
+
const timeMs = timeOf(record);
|
|
5654
|
+
if (!id || isNaN(timeMs)) {
|
|
5655
|
+
continue;
|
|
5656
|
+
}
|
|
5657
|
+
const held = this.setFor(set);
|
|
5658
|
+
let byTime = held.records.get(id);
|
|
5659
|
+
if (!byTime) {
|
|
5660
|
+
byTime = new Map();
|
|
5661
|
+
held.records.set(id, byTime);
|
|
5662
|
+
}
|
|
5663
|
+
byTime.set(timeMs, record);
|
|
5664
|
+
ids.add(id);
|
|
5665
|
+
}
|
|
5666
|
+
if (ids.size) {
|
|
5667
|
+
this.onChanged.Trigger({ entityIds: Array.from(ids), entities: false, records: true, set: set || EntitySimulation.DEFAULT_SET });
|
|
5668
|
+
}
|
|
5669
|
+
}
|
|
5670
|
+
/**
|
|
5671
|
+
* Forgets what is simulated for these Entities, or for every Entity when none are named.
|
|
5672
|
+
* @param params.set the set to clear. By default every set.
|
|
5673
|
+
* @param params.entities clear the stand-ins and patches. Default true.
|
|
5674
|
+
* @param params.records clear the historic records. Default true.
|
|
5675
|
+
*/
|
|
5676
|
+
Clear(params) {
|
|
5677
|
+
var _a, _b;
|
|
5678
|
+
const entities = (params === null || params === void 0 ? void 0 : params.entities) !== false;
|
|
5679
|
+
const records = (params === null || params === void 0 ? void 0 : params.records) !== false;
|
|
5680
|
+
const names = (params === null || params === void 0 ? void 0 : params.set) ? [params.set] : Array.from(this.sets.keys());
|
|
5681
|
+
const cleared = new Set();
|
|
5682
|
+
for (const name of names) {
|
|
5683
|
+
const set = this.sets.get(name);
|
|
5684
|
+
if (!set) {
|
|
5685
|
+
continue;
|
|
5686
|
+
}
|
|
5687
|
+
const ids = (_a = params === null || params === void 0 ? void 0 : params.entityIds) !== null && _a !== void 0 ? _a : [...set.entities.keys(), ...set.patches.keys(), ...set.records.keys()];
|
|
5688
|
+
for (const id of ids) {
|
|
5689
|
+
const hadEntity = entities && set.entities.delete(id);
|
|
5690
|
+
const hadPatch = entities && set.patches.delete(id);
|
|
5691
|
+
const hadRecords = records && set.records.delete(id);
|
|
5692
|
+
if (hadEntity || hadPatch || hadRecords) {
|
|
5693
|
+
cleared.add(id);
|
|
5694
|
+
}
|
|
5695
|
+
}
|
|
5696
|
+
if (!set.entities.size && !set.patches.size && !set.records.size) {
|
|
5697
|
+
this.sets.delete(name);
|
|
5698
|
+
}
|
|
5699
|
+
}
|
|
5700
|
+
if (cleared.size) {
|
|
5701
|
+
this.onChanged.Trigger({ entityIds: Array.from(cleared), entities, records, set: (_b = params === null || params === void 0 ? void 0 : params.set) !== null && _b !== void 0 ? _b : null });
|
|
5702
|
+
}
|
|
5703
|
+
}
|
|
5704
|
+
/**
|
|
5705
|
+
* The Entity's stand-in, with any patches laid over it, or null when nothing stands in for it.
|
|
5706
|
+
*/
|
|
5707
|
+
GetEntity(entityId) {
|
|
5708
|
+
var _a;
|
|
5709
|
+
let standIn = null;
|
|
5710
|
+
for (const set of this.sets.values()) {
|
|
5711
|
+
standIn = (_a = set.entities.get(entityId)) !== null && _a !== void 0 ? _a : standIn;
|
|
5712
|
+
}
|
|
5713
|
+
return standIn ? this.Overlay(standIn) : null;
|
|
5714
|
+
}
|
|
5715
|
+
/**
|
|
5716
|
+
* Whether a stand-in replaces this Entity, so the API need not be asked for it.
|
|
5717
|
+
*/
|
|
5718
|
+
HasEntity(entityId) {
|
|
5719
|
+
for (const set of this.sets.values()) {
|
|
5720
|
+
if (set.entities.has(entityId)) {
|
|
5721
|
+
return true;
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
return false;
|
|
5725
|
+
}
|
|
5726
|
+
/**
|
|
5727
|
+
* Whether a stand-in or a patch changes this Entity.
|
|
5728
|
+
*/
|
|
5729
|
+
HasBlob(entityId) {
|
|
5730
|
+
for (const set of this.sets.values()) {
|
|
5731
|
+
if (set.entities.has(entityId) || set.patches.has(entityId)) {
|
|
5732
|
+
return true;
|
|
5733
|
+
}
|
|
5734
|
+
}
|
|
5735
|
+
return false;
|
|
5736
|
+
}
|
|
5737
|
+
/**
|
|
5738
|
+
* Returns an Entity with its simulated patches laid over it. The input is never changed.
|
|
5739
|
+
*/
|
|
5740
|
+
Overlay(entity) {
|
|
5741
|
+
var _a;
|
|
5742
|
+
const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
5743
|
+
if (!id) {
|
|
5744
|
+
return entity;
|
|
5745
|
+
}
|
|
5746
|
+
let result = entity;
|
|
5747
|
+
for (const set of this.sets.values()) {
|
|
5748
|
+
const patch = set.patches.get(id);
|
|
5749
|
+
if (patch) {
|
|
5750
|
+
result = Overlay(result, patch);
|
|
5751
|
+
}
|
|
5752
|
+
}
|
|
5753
|
+
return result;
|
|
5754
|
+
}
|
|
5755
|
+
/**
|
|
5756
|
+
* The Entity as simulated: its stand-in if there is one, otherwise what was read with patches laid over it.
|
|
5757
|
+
* @param entityId the Entity.
|
|
5758
|
+
* @param read what the API gave for it, if it was asked.
|
|
5759
|
+
*/
|
|
5760
|
+
Resolve(entityId, read) {
|
|
5761
|
+
var _a;
|
|
5762
|
+
return (_a = this.GetEntity(entityId)) !== null && _a !== void 0 ? _a : (read ? this.Overlay(read) : null);
|
|
5763
|
+
}
|
|
5764
|
+
/**
|
|
5765
|
+
* Every Entity with a simulated stand-in or patch.
|
|
5766
|
+
*/
|
|
5767
|
+
GetEntityIds() {
|
|
5768
|
+
const ids = new Set();
|
|
5769
|
+
for (const set of this.sets.values()) {
|
|
5770
|
+
set.entities.forEach((_, id) => ids.add(id));
|
|
5771
|
+
set.patches.forEach((_, id) => ids.add(id));
|
|
5772
|
+
}
|
|
5773
|
+
return Array.from(ids);
|
|
5774
|
+
}
|
|
5775
|
+
/**
|
|
5776
|
+
* Every Entity with simulated history.
|
|
5777
|
+
*/
|
|
5778
|
+
GetRecordEntityIds() {
|
|
5779
|
+
const ids = new Set();
|
|
5780
|
+
for (const set of this.sets.values()) {
|
|
5781
|
+
set.records.forEach((_, id) => ids.add(id));
|
|
5782
|
+
}
|
|
5783
|
+
return Array.from(ids);
|
|
5784
|
+
}
|
|
5785
|
+
/**
|
|
5786
|
+
* An Entity's simulated history for a historic key, oldest first, every set's record at an instant merged.
|
|
5787
|
+
*/
|
|
5788
|
+
GetRecords(entityId, attrKey) {
|
|
5789
|
+
const byTime = new Map();
|
|
5790
|
+
for (const set of this.sets.values()) {
|
|
5791
|
+
for (const [ms, record] of set.records.get(entityId) || []) {
|
|
5792
|
+
if (attrKey && record.attrKey && record.attrKey !== attrKey) {
|
|
5793
|
+
continue;
|
|
5794
|
+
}
|
|
5795
|
+
const held = byTime.get(ms);
|
|
5796
|
+
byTime.set(ms, held ? overlayRecord(held, record) : record);
|
|
5797
|
+
}
|
|
5798
|
+
}
|
|
5799
|
+
return Array.from(byTime.entries()).sort(([a], [b]) => a - b).map(([, record]) => record);
|
|
5800
|
+
}
|
|
5801
|
+
/**
|
|
5802
|
+
* Each value an Entity's simulated history names, with the instant from which it is the simulation's.
|
|
5803
|
+
*/
|
|
5804
|
+
ownedFrom(records) {
|
|
5805
|
+
const owned = new Map();
|
|
5806
|
+
for (const record of records) {
|
|
5807
|
+
const ms = timeOf(record);
|
|
5808
|
+
for (const path of recordPaths(record)) {
|
|
5809
|
+
const key = path.join("\u0000");
|
|
5810
|
+
if (!owned.has(key)) {
|
|
5811
|
+
owned.set(key, { path, fromMs: ms });
|
|
5812
|
+
}
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5815
|
+
return Array.from(owned.values());
|
|
5816
|
+
}
|
|
5817
|
+
/**
|
|
5818
|
+
* An Entity as it stands at an instant, with each value its simulated records have named by then laid over it.
|
|
5819
|
+
* @param entity the Entity as read for that instant, from the API or a simulated stand-in.
|
|
5820
|
+
* @param timeMs the instant in milliseconds.
|
|
5821
|
+
* @param attrKey the historic attribute key being followed, or null for any.
|
|
5822
|
+
*/
|
|
5823
|
+
ApplyAt(entity, timeMs, attrKey) {
|
|
5824
|
+
var _a, _b, _c;
|
|
5825
|
+
const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
5826
|
+
if (!id || timeMs == null || isNaN(timeMs)) {
|
|
5827
|
+
return entity;
|
|
5828
|
+
}
|
|
5829
|
+
// Laid oldest first, each record replacing only what it names, which leaves every value at its newest.
|
|
5830
|
+
let state = null;
|
|
5831
|
+
let stateMs = -Infinity;
|
|
5832
|
+
for (const record of this.GetRecords(id, attrKey)) {
|
|
5833
|
+
const ms = timeOf(record);
|
|
5834
|
+
if (ms > timeMs) {
|
|
5835
|
+
break;
|
|
5836
|
+
}
|
|
5837
|
+
const parts = {};
|
|
5838
|
+
for (const part of RECORD_PARTS) {
|
|
5839
|
+
if (record[part] != null) {
|
|
5840
|
+
parts[part] = record[part];
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
state = state ? overlayRecord(state, parts) : parts;
|
|
5844
|
+
stateMs = ms;
|
|
5845
|
+
}
|
|
5846
|
+
if (!state) {
|
|
5847
|
+
return entity;
|
|
5848
|
+
}
|
|
5849
|
+
const bruce = { ...entity.Bruce };
|
|
5850
|
+
if (state.location) {
|
|
5851
|
+
bruce.Location = Overlay(bruce.Location, state.location);
|
|
5852
|
+
}
|
|
5853
|
+
if (state.transform) {
|
|
5854
|
+
bruce.Transform = Overlay(bruce.Transform, state.transform);
|
|
5855
|
+
}
|
|
5856
|
+
if (state.geometry) {
|
|
5857
|
+
bruce.VectorGeometry = state.geometry;
|
|
5858
|
+
}
|
|
5859
|
+
if (state.boundaries) {
|
|
5860
|
+
bruce.Boundaries = state.boundaries;
|
|
5861
|
+
}
|
|
5862
|
+
if (state.assemblyPosition) {
|
|
5863
|
+
bruce.AssemblyPosition = state.assemblyPosition;
|
|
5864
|
+
}
|
|
5865
|
+
// Says the newest record the Entity now reflects, the way a read at a point does.
|
|
5866
|
+
const outline = entity.Bruce.Outline || [];
|
|
5867
|
+
const readAt = outline.find(x => !!x.DateTime);
|
|
5868
|
+
const readMs = readAt ? new Date(readAt.DateTime).getTime() : -Infinity;
|
|
5869
|
+
const dated = {
|
|
5870
|
+
...(readAt || { "Source.Name": "Simulation", Editable: false, Kind: BModels.Entity.EOutlineKind.Attribute }),
|
|
5871
|
+
DateTime: new Date(Math.max(readMs, stateMs)).toISOString(),
|
|
5872
|
+
ForeignKey: (_b = readAt === null || readAt === void 0 ? void 0 : readAt.ForeignKey) !== null && _b !== void 0 ? _b : attrKey
|
|
5873
|
+
};
|
|
5874
|
+
bruce.Outline = [dated, ...outline.filter(x => x !== readAt)];
|
|
5875
|
+
const data = state.data ? Overlay({ ...entity, Bruce: undefined }, state.data) : entity;
|
|
5876
|
+
return { ...data, Bruce: Overlay(bruce, (_c = state.data) === null || _c === void 0 ? void 0 : _c.Bruce) };
|
|
5877
|
+
}
|
|
5878
|
+
/**
|
|
5879
|
+
* API records with the simulated ones joined in, for the named Entities or every simulated one.
|
|
5880
|
+
*/
|
|
5881
|
+
MergeRecords(recordsByIds, attrKey, entityIds) {
|
|
5882
|
+
if (this.IsEmpty) {
|
|
5883
|
+
return recordsByIds;
|
|
5884
|
+
}
|
|
5885
|
+
const ids = entityIds !== null && entityIds !== void 0 ? entityIds : this.GetRecordEntityIds();
|
|
5886
|
+
let merged = null;
|
|
5887
|
+
for (const id of ids) {
|
|
5888
|
+
const simulated = this.GetRecords(id, attrKey);
|
|
5889
|
+
if (!simulated.length) {
|
|
5890
|
+
continue;
|
|
5891
|
+
}
|
|
5892
|
+
const owned = this.ownedFrom(simulated);
|
|
5893
|
+
const byTime = new Map();
|
|
5894
|
+
for (const record of (recordsByIds === null || recordsByIds === void 0 ? void 0 : recordsByIds[id]) || []) {
|
|
5895
|
+
const ms = timeOf(record);
|
|
5896
|
+
const kept = withoutPaths(record, owned.filter(x => x.fromMs <= ms).map(x => x.path));
|
|
5897
|
+
if (hasContent(kept)) {
|
|
5898
|
+
byTime.set(ms, kept);
|
|
5899
|
+
}
|
|
5900
|
+
}
|
|
5901
|
+
for (const record of simulated) {
|
|
5902
|
+
const ms = timeOf(record);
|
|
5903
|
+
const held = byTime.get(ms);
|
|
5904
|
+
byTime.set(ms, held ? overlayRecord(held, record) : record);
|
|
5905
|
+
}
|
|
5906
|
+
merged = merged !== null && merged !== void 0 ? merged : { ...(recordsByIds || {}) };
|
|
5907
|
+
merged[id] = Array.from(byTime.entries()).sort(([a], [b]) => a - b).map(([, record]) => record);
|
|
5908
|
+
}
|
|
5909
|
+
return merged !== null && merged !== void 0 ? merged : recordsByIds;
|
|
5910
|
+
}
|
|
5911
|
+
}
|
|
5912
|
+
EntitySimulation.Store = Store;
|
|
5913
|
+
})(exports.EntitySimulation || (exports.EntitySimulation = {}));
|
|
5914
|
+
|
|
5484
5915
|
/**
|
|
5485
5916
|
* Returns cesium property's value.
|
|
5486
5917
|
* This will check if it's one that changes over time, or just a fixed value.
|
|
@@ -5532,6 +5963,8 @@
|
|
|
5532
5963
|
const PHOTO_CACHE_KEY = "_nextspaceLabelPhotos";
|
|
5533
5964
|
// Clearance around a model's box, as a share of its half-extent on each axis.
|
|
5534
5965
|
const MODEL_BOX_PADDING = 0.02;
|
|
5966
|
+
// How far a moving model's box may drift before it is moved, in metres.
|
|
5967
|
+
const MODEL_BOX_FOLLOW_TOLERANCE = 0.001;
|
|
5535
5968
|
// Share of each edge drawn out from its corners while the box is idle. Hovering draws the edges whole.
|
|
5536
5969
|
const MODEL_BOX_BRACKET = 0.2;
|
|
5537
5970
|
// Under this many pixels across, a box reads as a smudge and the ring takes over.
|
|
@@ -6748,6 +7181,7 @@
|
|
|
6748
7181
|
constructor() {
|
|
6749
7182
|
// Whether a box competes for space comes only from inputs (camera distance, hover, the pointer), never from
|
|
6750
7183
|
// how its label was laid out, so an animation moving a label cannot feed back into which boxes show.
|
|
7184
|
+
// corners is where the box is drawn this frame: stored, moved by the entry's motion.
|
|
6751
7185
|
this.entries = new Map();
|
|
6752
7186
|
this.groups = null;
|
|
6753
7187
|
// The hovered Entity. Its box is drawn on its own and whole, ahead of every other box.
|
|
@@ -6765,7 +7199,7 @@
|
|
|
6765
7199
|
Set(id, corners, entityId, inputs) {
|
|
6766
7200
|
const current = this.entries.get(id);
|
|
6767
7201
|
// A label rebuilt over the same box keeps its place and how far it has animated.
|
|
6768
|
-
if (corners && (current === null || current === void 0 ? void 0 : current.
|
|
7202
|
+
if (corners && (current === null || current === void 0 ? void 0 : current.stored) === corners && current.entityId === entityId) {
|
|
6769
7203
|
Object.assign(current, inputs);
|
|
6770
7204
|
return;
|
|
6771
7205
|
}
|
|
@@ -6773,17 +7207,41 @@
|
|
|
6773
7207
|
return;
|
|
6774
7208
|
}
|
|
6775
7209
|
if (corners) {
|
|
6776
|
-
this.entries.set(id, { ...inputs, corners, entityId, active: false, wanted: false });
|
|
7210
|
+
this.entries.set(id, { ...inputs, corners, stored: corners, entityId, active: false, wanted: false });
|
|
6777
7211
|
}
|
|
6778
7212
|
else
|
|
6779
7213
|
this.entries.delete(id);
|
|
6780
7214
|
this.since.delete(id);
|
|
7215
|
+
this.forget(id);
|
|
7216
|
+
}
|
|
7217
|
+
/*
|
|
7218
|
+
* Drops the groups and outlines a box was in, so they are worked out again from where it is now.
|
|
7219
|
+
*/
|
|
7220
|
+
forget(id) {
|
|
6781
7221
|
this.groups = null;
|
|
6782
7222
|
for (const [key, group] of this.outlines) {
|
|
6783
7223
|
if (group.members.includes(id))
|
|
6784
7224
|
this.outlines.delete(key);
|
|
6785
7225
|
}
|
|
6786
7226
|
}
|
|
7227
|
+
/*
|
|
7228
|
+
* Moves each box whose model moved since the last frame, keeping where it has got to in showing.
|
|
7229
|
+
*/
|
|
7230
|
+
follow() {
|
|
7231
|
+
var _a;
|
|
7232
|
+
for (const [id, entry] of this.entries) {
|
|
7233
|
+
const motion = (_a = entry.motion) === null || _a === void 0 ? void 0 : _a.call(entry);
|
|
7234
|
+
if (!motion) {
|
|
7235
|
+
continue;
|
|
7236
|
+
}
|
|
7237
|
+
const moved = entry.stored.map(corner => Cesium.Matrix4.multiplyByPoint(motion, corner, new Cesium.Cartesian3()));
|
|
7238
|
+
if (moved.every((corner, i) => Cesium.Cartesian3.equalsEpsilon(corner, entry.corners[i], 0, MODEL_BOX_FOLLOW_TOLERANCE))) {
|
|
7239
|
+
continue;
|
|
7240
|
+
}
|
|
7241
|
+
entry.corners = moved;
|
|
7242
|
+
this.forget(id);
|
|
7243
|
+
}
|
|
7244
|
+
}
|
|
6787
7245
|
/*
|
|
6788
7246
|
* The box drawn for a label this frame, or undefined when it has none or lost its place.
|
|
6789
7247
|
*/
|
|
@@ -6851,6 +7309,7 @@
|
|
|
6851
7309
|
*/
|
|
6852
7310
|
Resolve(viewer, pointer) {
|
|
6853
7311
|
var _a, _b, _c, _d;
|
|
7312
|
+
this.follow();
|
|
6854
7313
|
this.frames.clear();
|
|
6855
7314
|
this.hulls.clear();
|
|
6856
7315
|
this.drawn = [];
|
|
@@ -7273,9 +7732,16 @@
|
|
|
7273
7732
|
}
|
|
7274
7733
|
if (this.api) {
|
|
7275
7734
|
const rego = this.rego;
|
|
7735
|
+
const simulation = exports.EntitySimulation.Get(this.viewer);
|
|
7736
|
+
let simulated = null;
|
|
7737
|
+
if (simulation === null || simulation === void 0 ? void 0 : simulation.HasBlob(rego.entityId)) {
|
|
7738
|
+
// A stand-in is named as is; a patch is laid over the API's record first.
|
|
7739
|
+
const read = simulation.HasEntity(rego.entityId) ? null : (await BModels.Entity.Get({ api: this.api, entityId: rego.entityId, migrated: true })).entity;
|
|
7740
|
+
simulated = simulation.Resolve(rego.entityId, read);
|
|
7741
|
+
}
|
|
7276
7742
|
this.rego.name = await BModels.Entity.CalculateNameAsync({
|
|
7277
7743
|
api: this.api,
|
|
7278
|
-
entity:
|
|
7744
|
+
entity: simulated,
|
|
7279
7745
|
entityId: rego.entityId,
|
|
7280
7746
|
defaultToId: false
|
|
7281
7747
|
});
|
|
@@ -7304,6 +7770,21 @@
|
|
|
7304
7770
|
clearTimeout(this.loadTimeout);
|
|
7305
7771
|
this.loadTimeout = null;
|
|
7306
7772
|
}
|
|
7773
|
+
/*
|
|
7774
|
+
* Reads the label's Entity again and redraws it, eg. after what is simulated for it changed.
|
|
7775
|
+
*/
|
|
7776
|
+
Reload() {
|
|
7777
|
+
if (this.disposed) {
|
|
7778
|
+
return;
|
|
7779
|
+
}
|
|
7780
|
+
this.additionalTexts = this.options.text != null ? [] : null;
|
|
7781
|
+
this.loadedName = false;
|
|
7782
|
+
// The name came from whatever record the visual was drawn from, so it is worked out again too.
|
|
7783
|
+
if (this.rego) {
|
|
7784
|
+
this.rego.name = null;
|
|
7785
|
+
}
|
|
7786
|
+
this.createLabel();
|
|
7787
|
+
}
|
|
7307
7788
|
/*
|
|
7308
7789
|
* Rebuilds only when configuration changes; state refreshes must not recreate DOM every frame.
|
|
7309
7790
|
*/
|
|
@@ -7534,7 +8015,7 @@
|
|
|
7534
8015
|
}
|
|
7535
8016
|
clearTimeout(this.loadTimeout);
|
|
7536
8017
|
this.loadTimeout = setTimeout(async () => {
|
|
7537
|
-
var _a, _b, _c, _d, _e;
|
|
8018
|
+
var _a, _b, _c, _d, _e, _f;
|
|
7538
8019
|
if (this.disposed || this.counter != counter) {
|
|
7539
8020
|
return;
|
|
7540
8021
|
}
|
|
@@ -7561,16 +8042,19 @@
|
|
|
7561
8042
|
const attributes = (_a = this.options.attributes) !== null && _a !== void 0 ? _a : (_c = (_b = entityType === null || entityType === void 0 ? void 0 : entityType.VisualSettings) === null || _b === void 0 ? void 0 : _b.label) === null || _c === void 0 ? void 0 : _c.attributes;
|
|
7562
8043
|
// Read for its attributes, and for a photo when the label has no icon of its own.
|
|
7563
8044
|
if (attributes || !HasIcon(this.options)) {
|
|
7564
|
-
|
|
8045
|
+
// A simulated stand-in is labelled as is, and a patch is laid over the API's.
|
|
8046
|
+
const simulation = exports.EntitySimulation.Get(this.viewer);
|
|
8047
|
+
let entity = (_d = simulation === null || simulation === void 0 ? void 0 : simulation.GetEntity(this.rego.entityId)) !== null && _d !== void 0 ? _d : null;
|
|
7565
8048
|
try {
|
|
7566
|
-
entity = (await BModels.Entity.Get({
|
|
8049
|
+
entity = entity !== null && entity !== void 0 ? entity : (await BModels.Entity.Get({
|
|
7567
8050
|
api: this.api,
|
|
7568
8051
|
entityId: this.rego.entityId,
|
|
7569
|
-
scenario: ((
|
|
8052
|
+
scenario: ((_e = this.rego.outline) === null || _e === void 0 ? void 0 : _e.length) ? (_f = this.rego.outline.find(x => !!x.Scenario)) === null || _f === void 0 ? void 0 : _f.Scenario : null,
|
|
7570
8053
|
schemaId: this.rego.schema,
|
|
7571
8054
|
migrated: true,
|
|
7572
8055
|
expandAttachments: !HasIcon(this.options)
|
|
7573
8056
|
})).entity;
|
|
8057
|
+
entity = entity && simulation ? simulation.Resolve(this.rego.entityId, entity) : entity;
|
|
7574
8058
|
}
|
|
7575
8059
|
// Entity doesn't exist.
|
|
7576
8060
|
// Likely a graphic with an ID that points to no record.
|
|
@@ -7954,11 +8438,17 @@
|
|
|
7954
8438
|
// Past the wait a slow record no longer holds the label back; a box that comes later eases in.
|
|
7955
8439
|
setTimeout(settle, MODEL_BOX_WAIT);
|
|
7956
8440
|
this.modelBox.load.then(corners => {
|
|
8441
|
+
var _a, _b;
|
|
7957
8442
|
if (!corners || this.disposed || this.counter !== counter) {
|
|
7958
8443
|
return;
|
|
7959
8444
|
}
|
|
7960
8445
|
// A record that disagrees with where the model was found describes another placement, such as a moved tileset.
|
|
8446
|
+
// A part known to have moved from its record, eg. a joint turning, is judged where it has moved to.
|
|
8447
|
+
const motion = (_b = (_a = this.rego) === null || _a === void 0 ? void 0 : _a.motion) === null || _b === void 0 ? void 0 : _b.call(_a, this.viewer.clock.currentTime);
|
|
7961
8448
|
const centre = Cesium.Cartesian3.midpoint(corners[0], corners[7], new Cesium.Cartesian3());
|
|
8449
|
+
if (motion) {
|
|
8450
|
+
Cesium.Matrix4.multiplyByPoint(motion, centre, centre);
|
|
8451
|
+
}
|
|
7962
8452
|
if (Cesium.Cartesian3.distance(centre, found) > Cesium.Cartesian3.distance(corners[0], corners[7]) * 0.75 + 2) {
|
|
7963
8453
|
return;
|
|
7964
8454
|
}
|
|
@@ -7966,6 +8456,7 @@
|
|
|
7966
8456
|
// Let go a little further out than it is taken, so a camera resting at the limit does not flip it.
|
|
7967
8457
|
let near = false;
|
|
7968
8458
|
layer.modelBoxes.Set(this.id, corners, rego.entityId, {
|
|
8459
|
+
motion: rego.motion ? () => rego.motion(this.viewer.clock.currentTime) : undefined,
|
|
7969
8460
|
selected: () => { var _a, _b; return Boolean((_b = (_a = this.visualRegister) === null || _a === void 0 ? void 0 : _a.GetState({ entityId: rego.entityId, menuItemId: rego.menuItemId })) === null || _b === void 0 ? void 0 : _b.selected); },
|
|
7970
8461
|
hovered: () => { var _a, _b; return Boolean((_b = (_a = this.visualRegister) === null || _a === void 0 ? void 0 : _a.IsLabelHovered) === null || _b === void 0 ? void 0 : _b.call(_a, rego.entityId, rego.menuItemId)); },
|
|
7971
8462
|
near: () => {
|
|
@@ -8946,9 +9437,9 @@
|
|
|
8946
9437
|
* Reads the entities behind items that name one without carrying it, attachments included,
|
|
8947
9438
|
* so a label's default image needs no second request.
|
|
8948
9439
|
*/
|
|
8949
|
-
async function Hydrate(items, api, signal) {
|
|
9440
|
+
async function Hydrate(items, api, signal, simulation) {
|
|
8950
9441
|
var _a, _b;
|
|
8951
|
-
if (!api) {
|
|
9442
|
+
if (!api && !simulation) {
|
|
8952
9443
|
return items;
|
|
8953
9444
|
}
|
|
8954
9445
|
const hydrated = items.slice();
|
|
@@ -8959,12 +9450,15 @@
|
|
|
8959
9450
|
}
|
|
8960
9451
|
const chunk = missing.slice(start, start + HYDRATE_AT_ONCE);
|
|
8961
9452
|
try {
|
|
8962
|
-
|
|
8963
|
-
|
|
8964
|
-
}
|
|
9453
|
+
// A simulated stand-in is labelled as is, never from the API, and a patch is laid over the API's.
|
|
9454
|
+
const asked = chunk.filter(at => !(simulation === null || simulation === void 0 ? void 0 : simulation.HasEntity(hydrated[at].entityId)));
|
|
9455
|
+
const { entities } = api && asked.length ? await BModels.Entity.GetListByIds({
|
|
9456
|
+
api, entityIds: asked.map(at => hydrated[at].entityId), expandAttachments: true, migrated: true
|
|
9457
|
+
}) : { entities: [] };
|
|
8965
9458
|
const found = new Map((entities !== null && entities !== void 0 ? entities : []).map(entity => { var _a; return [(_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID, entity]; }));
|
|
8966
9459
|
for (const at of chunk) {
|
|
8967
|
-
const
|
|
9460
|
+
const id = hydrated[at].entityId;
|
|
9461
|
+
const entity = simulation ? simulation.Resolve(id, found.get(id)) : found.get(id);
|
|
8968
9462
|
if (entity) {
|
|
8969
9463
|
// The API leaves Attachment out when there are none; an empty list records that they were read.
|
|
8970
9464
|
hydrated[at] = { ...hydrated[at], entity: { ...entity, Bruce: { ...entity.Bruce, Attachment: (_b = (_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.Attachment) !== null && _b !== void 0 ? _b : [] } } };
|
|
@@ -8981,7 +9475,7 @@
|
|
|
8981
9475
|
/*
|
|
8982
9476
|
* Uses the existing DataLab grammar, discarding actions and projections that cannot return Entities.
|
|
8983
9477
|
*/
|
|
8984
|
-
async function Loader(source, api, signal, hydrate) {
|
|
9478
|
+
async function Loader(source, api, signal, hydrate, simulation) {
|
|
8985
9479
|
var _a;
|
|
8986
9480
|
var _b;
|
|
8987
9481
|
if (source.type === "provider") {
|
|
@@ -8996,7 +9490,7 @@
|
|
|
8996
9490
|
return async (offset, limit, signal) => {
|
|
8997
9491
|
const page = items.slice(offset, offset + limit);
|
|
8998
9492
|
return {
|
|
8999
|
-
items: hydrate ? await Hydrate(page, api, signal) : page,
|
|
9493
|
+
items: hydrate ? await Hydrate(page, api, signal, simulation) : page,
|
|
9000
9494
|
hasMore: offset + limit < items.length
|
|
9001
9495
|
};
|
|
9002
9496
|
};
|
|
@@ -9138,7 +9632,7 @@
|
|
|
9138
9632
|
const items = new Map();
|
|
9139
9633
|
let truncated = false;
|
|
9140
9634
|
try {
|
|
9141
|
-
const load = await Loader(definition.source, (_g = this.register.ApiGetters) === null || _g === void 0 ? void 0 : _g.GetBruceApi(), controller.signal, NeedsEntityData(definition.options));
|
|
9635
|
+
const load = await Loader(definition.source, (_g = this.register.ApiGetters) === null || _g === void 0 ? void 0 : _g.GetBruceApi(), controller.signal, NeedsEntityData(definition.options), exports.EntitySimulation.Get(this.register.Viewer));
|
|
9142
9636
|
let offset = 0;
|
|
9143
9637
|
for (let pageNumber = 0;; pageNumber++) {
|
|
9144
9638
|
if (controller.signal.aborted || this.register.Disposed) {
|
|
@@ -9960,8 +10454,25 @@
|
|
|
9960
10454
|
return `${relation["Related.Entity.ID"]}-${relation["Principal.Entity.ID"]}-${relation["Relation.Type.ID"]}`;
|
|
9961
10455
|
}
|
|
9962
10456
|
RelationRenderEngine.GetRenderGroupId = GetRenderGroupId;
|
|
10457
|
+
/**
|
|
10458
|
+
* Removes and returns a menu item's drawn relations that end at, or carry data from, any of these Entities.
|
|
10459
|
+
*/
|
|
10460
|
+
function TakeRelationsTouching(params) {
|
|
10461
|
+
const { visualRegister, menuItemId } = params;
|
|
10462
|
+
const ids = new Set(params.entityIds);
|
|
10463
|
+
const touched = visualRegister.GetRegos({ menuItemId }).filter((rego) => {
|
|
10464
|
+
const relation = rego.relation;
|
|
10465
|
+
return relation && [relation["Principal.Entity.ID"], relation["Related.Entity.ID"], relation["Data.Entity.ID"]]
|
|
10466
|
+
.some(id => id && ids.has(id));
|
|
10467
|
+
});
|
|
10468
|
+
for (const rego of touched) {
|
|
10469
|
+
visualRegister.RemoveRegos({ relation: rego.relation, entityId: rego.entityId, menuItemId, requestRender: false });
|
|
10470
|
+
}
|
|
10471
|
+
return touched.map(rego => rego.relation);
|
|
10472
|
+
}
|
|
10473
|
+
RelationRenderEngine.TakeRelationsTouching = TakeRelationsTouching;
|
|
9963
10474
|
async function Render(params) {
|
|
9964
|
-
const { apiGetter, viewer, visualRegister, menuItemId, relations } = params;
|
|
10475
|
+
const { apiGetter, viewer, visualRegister, menuItemId, relations, simulation } = params;
|
|
9965
10476
|
const api = apiGetter.getApi(apiGetter.accountId);
|
|
9966
10477
|
const rendered = {};
|
|
9967
10478
|
let neededEntityIdsIds = [];
|
|
@@ -9979,13 +10490,15 @@
|
|
|
9979
10490
|
}
|
|
9980
10491
|
// Turn the set unique.
|
|
9981
10492
|
neededEntityIdsIds = neededEntityIdsIds.filter((v, i, a) => a.indexOf(v) === i);
|
|
9982
|
-
// Get all entities in one go.
|
|
9983
|
-
|
|
9984
|
-
|
|
10493
|
+
// Get all entities in one go, other than the simulated ones.
|
|
10494
|
+
const simulated = neededEntityIdsIds.map(id => simulation === null || simulation === void 0 ? void 0 : simulation.GetEntity(id)).filter(x => !!x);
|
|
10495
|
+
const apiIds = neededEntityIdsIds.filter(id => !(simulation === null || simulation === void 0 ? void 0 : simulation.HasEntity(id)));
|
|
10496
|
+
let entities = (apiIds.length ? (await BModels.Entity.GetListByIds({
|
|
10497
|
+
entityIds: apiIds,
|
|
9985
10498
|
api: apiGetter.getApi(),
|
|
9986
10499
|
migrated: true,
|
|
9987
10500
|
maxSearchTimeSec: 60 * 2
|
|
9988
|
-
})).entities;
|
|
10501
|
+
})).entities.map(entity => simulation ? simulation.Overlay(entity) : entity) : []).concat(simulated);
|
|
9989
10502
|
// Create a map for quick reference.
|
|
9990
10503
|
const entitiesMap = {};
|
|
9991
10504
|
for (let i = 0; i < entities.length; i++) {
|
|
@@ -10479,6 +10992,8 @@
|
|
|
10479
10992
|
rego.overrideShow != null ||
|
|
10480
10993
|
// Being dragged around right now, so its extent is changing faster than we could measure it.
|
|
10481
10994
|
rego.editing == true ||
|
|
10995
|
+
// Placed by the clock every frame, so no measurement of where it is stays true.
|
|
10996
|
+
rego.moving == true ||
|
|
10482
10997
|
// Part of a collection we did not create, eg. a geojson data source, which may have its own rules for
|
|
10483
10998
|
// what is in the scene. Our own per-menu-item data sources are fair game.
|
|
10484
10999
|
exports.VisualsRegister.IsForeignCollection(rego) ||
|
|
@@ -11313,6 +11828,7 @@
|
|
|
11313
11828
|
}
|
|
11314
11829
|
get OnLabelGroupsChanged() { return this.labelGroupsChanged; }
|
|
11315
11830
|
constructor(params) {
|
|
11831
|
+
var _a, _b;
|
|
11316
11832
|
this.id = BModels.ObjectUtils.UId();
|
|
11317
11833
|
this.disposed = false;
|
|
11318
11834
|
this.rego = {};
|
|
@@ -11352,6 +11868,8 @@
|
|
|
11352
11868
|
this.menuItemSources = new Map();
|
|
11353
11869
|
// Set when the data source order no longer matches the zIndexes seen, so it is re-applied once.
|
|
11354
11870
|
this.sourceOrderDirty = false;
|
|
11871
|
+
// Stops following what is simulated, so labels can read it again when it changes.
|
|
11872
|
+
this.simulationRemoval = null;
|
|
11355
11873
|
this.labelGroupsChanged = new BModels.BruceEvent();
|
|
11356
11874
|
this.hoverRingState = {};
|
|
11357
11875
|
this.retiringHoverLabels = new Map();
|
|
@@ -11386,6 +11904,33 @@
|
|
|
11386
11904
|
this.cameraCullerDispose = exports.VisualRegisterCuller.Monitor({
|
|
11387
11905
|
register: this
|
|
11388
11906
|
});
|
|
11907
|
+
this.simulationRemoval = (_b = (_a = exports.EntitySimulation.Get(this.viewer)) === null || _a === void 0 ? void 0 : _a.OnChanged.Subscribe((change) => this.reloadLabels(change.entityIds))) !== null && _b !== void 0 ? _b : null;
|
|
11908
|
+
}
|
|
11909
|
+
/*
|
|
11910
|
+
* Tells labels to read their Entity again, since they keep what they read when drawn.
|
|
11911
|
+
*/
|
|
11912
|
+
reloadLabels(entityIds) {
|
|
11913
|
+
var _a, _b, _c, _d;
|
|
11914
|
+
if (this.disposed) {
|
|
11915
|
+
return;
|
|
11916
|
+
}
|
|
11917
|
+
const groupIds = new Set();
|
|
11918
|
+
for (const entityId of entityIds) {
|
|
11919
|
+
for (const rego of this.GetRegos({ entityId })) {
|
|
11920
|
+
(_a = exports.EntityLabel.GetLabel({ rego })) === null || _a === void 0 ? void 0 : _a.Reload();
|
|
11921
|
+
}
|
|
11922
|
+
if (((_b = this.labelHover) === null || _b === void 0 ? void 0 : _b.entityId) === entityId) {
|
|
11923
|
+
(_c = this.hoverLabel) === null || _c === void 0 ? void 0 : _c.Reload();
|
|
11924
|
+
}
|
|
11925
|
+
const groupId = (_d = this.GetLabelGroupFor(entityId)) === null || _d === void 0 ? void 0 : _d.groupId;
|
|
11926
|
+
if (groupId) {
|
|
11927
|
+
groupIds.add(groupId);
|
|
11928
|
+
}
|
|
11929
|
+
}
|
|
11930
|
+
// A group may have read the Entity in with its items, so the group is read again as a whole.
|
|
11931
|
+
for (const groupId of groupIds) {
|
|
11932
|
+
this.RefreshLabelGroup(groupId).catch((e) => console.error(e));
|
|
11933
|
+
}
|
|
11389
11934
|
}
|
|
11390
11935
|
/**
|
|
11391
11936
|
* Returns the collection a menu item's visuals belong in, creating its data source on first use.
|
|
@@ -12288,7 +12833,9 @@
|
|
|
12288
12833
|
(_b = this.viewer.scene) === null || _b === void 0 ? void 0 : _b.requestRender();
|
|
12289
12834
|
}
|
|
12290
12835
|
Dispose() {
|
|
12291
|
-
var _a, _b, _c, _d, _e;
|
|
12836
|
+
var _a, _b, _c, _d, _e, _f;
|
|
12837
|
+
(_a = this.simulationRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
12838
|
+
this.simulationRemoval = null;
|
|
12292
12839
|
exports.CesiumEntityStyler.SetDimming(this.viewer, this.id, false);
|
|
12293
12840
|
this.ClearLabelHover();
|
|
12294
12841
|
clearTimeout(this.hoverRingReset);
|
|
@@ -12298,14 +12845,14 @@
|
|
|
12298
12845
|
exports.EntityLabel.Detatch({ label });
|
|
12299
12846
|
}
|
|
12300
12847
|
this.retiringHoverLabels.clear();
|
|
12301
|
-
(
|
|
12848
|
+
(_b = this.labelGroups) === null || _b === void 0 ? void 0 : _b.Dispose();
|
|
12302
12849
|
this.labelGroupsChanged.Clear();
|
|
12303
12850
|
for (const regos of Object.values(this.rego)) {
|
|
12304
12851
|
for (const rego of regos)
|
|
12305
12852
|
exports.EntityLabel.Detatch({ rego, force: true });
|
|
12306
12853
|
}
|
|
12307
12854
|
exports.EntityLabel.SetContainer(this.viewer);
|
|
12308
|
-
(
|
|
12855
|
+
(_c = this.cameraCullerDispose) === null || _c === void 0 ? void 0 : _c.call(this, {
|
|
12309
12856
|
uncull: false
|
|
12310
12857
|
});
|
|
12311
12858
|
this.cameraCullerDispose = null;
|
|
@@ -12321,7 +12868,7 @@
|
|
|
12321
12868
|
this.disposed = true;
|
|
12322
12869
|
for (const record of Array.from(this.menuItemSources.values())) {
|
|
12323
12870
|
try {
|
|
12324
|
-
(
|
|
12871
|
+
(_e = (_d = this.viewer) === null || _d === void 0 ? void 0 : _d.dataSources) === null || _e === void 0 ? void 0 : _e.remove(record.source, true);
|
|
12325
12872
|
}
|
|
12326
12873
|
catch (e) {
|
|
12327
12874
|
console.error(e);
|
|
@@ -12330,7 +12877,7 @@
|
|
|
12330
12877
|
this.menuItemSources.clear();
|
|
12331
12878
|
// Hand every tileset's show flag back to its owner, holding whatever the owner last asked for.
|
|
12332
12879
|
for (const rego of Array.from(this.tilesets.values())) {
|
|
12333
|
-
(
|
|
12880
|
+
(_f = rego.gate) === null || _f === void 0 ? void 0 : _f.Release();
|
|
12334
12881
|
}
|
|
12335
12882
|
this.tilesets.clear();
|
|
12336
12883
|
}
|
|
@@ -12504,21 +13051,7 @@
|
|
|
12504
13051
|
changed = true;
|
|
12505
13052
|
}
|
|
12506
13053
|
if (editing) {
|
|
12507
|
-
|
|
12508
|
-
entity: rego.visual
|
|
12509
|
-
});
|
|
12510
|
-
for (let k = 0; k < parts.length; k++) {
|
|
12511
|
-
const part = parts[k];
|
|
12512
|
-
if (!(part instanceof Cesium.Entity)) {
|
|
12513
|
-
continue;
|
|
12514
|
-
}
|
|
12515
|
-
const removalPending = exports.VisualRegisterCuller.CancelQueuedSceneChange(part);
|
|
12516
|
-
const wasCulled = part[exports.VisualRegisterCuller.VISUAL_CULL_KEY] == true || removalPending;
|
|
12517
|
-
delete part[exports.VisualRegisterCuller.VISUAL_CULL_KEY];
|
|
12518
|
-
if (wasCulled && !IsCEntityInScene(this.viewer, part)) {
|
|
12519
|
-
AddCEntityToScene(this.viewer, part, rego.collection);
|
|
12520
|
-
}
|
|
12521
|
-
}
|
|
13054
|
+
this.restoreCulled(rego);
|
|
12522
13055
|
}
|
|
12523
13056
|
else {
|
|
12524
13057
|
exports.VisualRegisterCuller.InvalidateBounds(rego.visual);
|
|
@@ -12530,6 +13063,56 @@
|
|
|
12530
13063
|
(_b = (_a = this.viewer) === null || _a === void 0 ? void 0 : _a.scene) === null || _b === void 0 ? void 0 : _b.requestRender();
|
|
12531
13064
|
}
|
|
12532
13065
|
}
|
|
13066
|
+
/**
|
|
13067
|
+
* Marks visuals as placed by the clock, exempting them from culling until it is turned back off.
|
|
13068
|
+
*/
|
|
13069
|
+
SetMoving(params) {
|
|
13070
|
+
const { entityIds, moving, menuItemId } = params;
|
|
13071
|
+
if (!(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
|
|
13072
|
+
return;
|
|
13073
|
+
}
|
|
13074
|
+
for (let i = 0; i < entityIds.length; i++) {
|
|
13075
|
+
const regos = this.rego[entityIds[i]];
|
|
13076
|
+
if (!regos) {
|
|
13077
|
+
continue;
|
|
13078
|
+
}
|
|
13079
|
+
for (let j = 0; j < regos.length; j++) {
|
|
13080
|
+
const rego = regos[j];
|
|
13081
|
+
if ((menuItemId && rego.menuItemId !== menuItemId) || Boolean(rego.moving) == Boolean(moving)) {
|
|
13082
|
+
continue;
|
|
13083
|
+
}
|
|
13084
|
+
// Null rather than false, so the rego does not carry a key for every visual that ever moved.
|
|
13085
|
+
rego.moving = moving ? true : null;
|
|
13086
|
+
if (moving) {
|
|
13087
|
+
this.restoreCulled(rego);
|
|
13088
|
+
}
|
|
13089
|
+
else {
|
|
13090
|
+
exports.VisualRegisterCuller.InvalidateBounds(rego.visual);
|
|
13091
|
+
exports.VisualRegisterCuller.MarkShouldRecheck(this.viewer);
|
|
13092
|
+
}
|
|
13093
|
+
}
|
|
13094
|
+
}
|
|
13095
|
+
}
|
|
13096
|
+
/*
|
|
13097
|
+
* Puts back whatever the culler took out of a visual that is now exempt from it.
|
|
13098
|
+
*/
|
|
13099
|
+
restoreCulled(rego) {
|
|
13100
|
+
const parts = exports.EntityUtils.GatherEntity({
|
|
13101
|
+
entity: rego.visual
|
|
13102
|
+
});
|
|
13103
|
+
for (let k = 0; k < parts.length; k++) {
|
|
13104
|
+
const part = parts[k];
|
|
13105
|
+
if (!(part instanceof Cesium.Entity)) {
|
|
13106
|
+
continue;
|
|
13107
|
+
}
|
|
13108
|
+
const removalPending = exports.VisualRegisterCuller.CancelQueuedSceneChange(part);
|
|
13109
|
+
const wasCulled = part[exports.VisualRegisterCuller.VISUAL_CULL_KEY] == true || removalPending;
|
|
13110
|
+
delete part[exports.VisualRegisterCuller.VISUAL_CULL_KEY];
|
|
13111
|
+
if (wasCulled && !IsCEntityInScene(this.viewer, part)) {
|
|
13112
|
+
AddCEntityToScene(this.viewer, part, rego.collection);
|
|
13113
|
+
}
|
|
13114
|
+
}
|
|
13115
|
+
}
|
|
12533
13116
|
SetSelected(params) {
|
|
12534
13117
|
var _a;
|
|
12535
13118
|
let { entityIds, selected, refreshIfSelected, requestRender, menuItemId, source } = params;
|
|
@@ -14022,12 +14605,41 @@
|
|
|
14022
14605
|
* Tracks per-entity rerender state for unsaved blob maintenance and stale API response suppression.
|
|
14023
14606
|
*/
|
|
14024
14607
|
class EntityReRenderMaintainState {
|
|
14025
|
-
constructor() {
|
|
14608
|
+
constructor(simulation, pointInTime) {
|
|
14609
|
+
this.simulation = simulation;
|
|
14610
|
+
this.pointInTime = pointInTime;
|
|
14026
14611
|
this.maintainedEntitiesById = {};
|
|
14027
14612
|
this.apiRevisionByEntityId = {};
|
|
14028
14613
|
this.skipApiRunByEntityId = {};
|
|
14029
14614
|
this.checkRunId = 0;
|
|
14030
14615
|
}
|
|
14616
|
+
/*
|
|
14617
|
+
* Lays each Entity's simulated record for the current point over it, when the manager reads at one.
|
|
14618
|
+
*/
|
|
14619
|
+
atPoint(entities) {
|
|
14620
|
+
var _a;
|
|
14621
|
+
const point = (_a = this.pointInTime) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
14622
|
+
if (!point || !this.simulation || this.simulation.IsEmpty || !(entities === null || entities === void 0 ? void 0 : entities.length)) {
|
|
14623
|
+
return entities;
|
|
14624
|
+
}
|
|
14625
|
+
return entities.map((entity) => this.simulation.ApplyAt(entity, point.timeMs, point.attrKey));
|
|
14626
|
+
}
|
|
14627
|
+
/**
|
|
14628
|
+
* Whether a simulated stand-in replaces this Entity, so nothing from the API may replace what is drawn.
|
|
14629
|
+
*/
|
|
14630
|
+
isSimulated(entityId) {
|
|
14631
|
+
var _a;
|
|
14632
|
+
return Boolean(entityId && ((_a = this.simulation) === null || _a === void 0 ? void 0 : _a.HasEntity(entityId)));
|
|
14633
|
+
}
|
|
14634
|
+
/**
|
|
14635
|
+
* Swaps any simulated Entity in a set the API returned for its stand-in, or lays its patch over it.
|
|
14636
|
+
*/
|
|
14637
|
+
withSimulated(entities) {
|
|
14638
|
+
if (!this.simulation || this.simulation.IsEmpty || !(entities === null || entities === void 0 ? void 0 : entities.length)) {
|
|
14639
|
+
return entities;
|
|
14640
|
+
}
|
|
14641
|
+
return this.atPoint(entities.map((entity) => { var _a, _b; return (_b = this.simulation.Resolve((_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID, entity)) !== null && _b !== void 0 ? _b : entity; }));
|
|
14642
|
+
}
|
|
14031
14643
|
setMaintainedEntities(entities) {
|
|
14032
14644
|
var _a;
|
|
14033
14645
|
for (let i = 0; i < entities.length; i++) {
|
|
@@ -14049,15 +14661,21 @@
|
|
|
14049
14661
|
}
|
|
14050
14662
|
}
|
|
14051
14663
|
getMaintainedEntities(entityIds) {
|
|
14664
|
+
var _a;
|
|
14052
14665
|
const entities = [];
|
|
14053
14666
|
for (let i = 0; i < entityIds.length; i++) {
|
|
14054
14667
|
const id = entityIds[i];
|
|
14055
14668
|
if (!id) {
|
|
14056
14669
|
continue;
|
|
14057
14670
|
}
|
|
14058
|
-
|
|
14059
|
-
|
|
14060
|
-
|
|
14671
|
+
// A maintained blob is this manager's own unsaved edit, newer than a simulation, so it is drawn as is.
|
|
14672
|
+
const maintained = this.maintainedEntitiesById[id];
|
|
14673
|
+
const simulated = maintained ? null : (_a = this.simulation) === null || _a === void 0 ? void 0 : _a.GetEntity(id);
|
|
14674
|
+
if (maintained) {
|
|
14675
|
+
entities.push(maintained);
|
|
14676
|
+
}
|
|
14677
|
+
else if (simulated) {
|
|
14678
|
+
entities.push(this.atPoint([simulated])[0]);
|
|
14061
14679
|
}
|
|
14062
14680
|
}
|
|
14063
14681
|
return entities;
|
|
@@ -14114,7 +14732,7 @@
|
|
|
14114
14732
|
}
|
|
14115
14733
|
filterCurrentApiEntities(params) {
|
|
14116
14734
|
const { entities, revisions, runId } = params;
|
|
14117
|
-
|
|
14735
|
+
const current = entities.filter((entity) => {
|
|
14118
14736
|
var _a, _b, _c;
|
|
14119
14737
|
const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
14120
14738
|
if (!id) {
|
|
@@ -14123,8 +14741,12 @@
|
|
|
14123
14741
|
if (runId != null && this.shouldSkipInRun(id, runId)) {
|
|
14124
14742
|
return false;
|
|
14125
14743
|
}
|
|
14744
|
+
if (this.isSimulated(id)) {
|
|
14745
|
+
return false;
|
|
14746
|
+
}
|
|
14126
14747
|
return ((_b = this.apiRevisionByEntityId[id]) !== null && _b !== void 0 ? _b : 0) === ((_c = revisions[id]) !== null && _c !== void 0 ? _c : 0);
|
|
14127
14748
|
});
|
|
14749
|
+
return this.atPoint(this.simulation && !this.simulation.IsEmpty ? current.map((entity) => this.simulation.Overlay(entity)) : current);
|
|
14128
14750
|
}
|
|
14129
14751
|
}
|
|
14130
14752
|
|
|
@@ -15560,7 +16182,7 @@
|
|
|
15560
16182
|
this.cache = new HistoricRangeCache();
|
|
15561
16183
|
}
|
|
15562
16184
|
get Records() {
|
|
15563
|
-
return this.cache.GetRecords();
|
|
16185
|
+
return this.withSimulated(this.cache.GetRecords());
|
|
15564
16186
|
}
|
|
15565
16187
|
Clear() {
|
|
15566
16188
|
this.cache.Clear();
|
|
@@ -15584,8 +16206,9 @@
|
|
|
15584
16206
|
*/
|
|
15585
16207
|
async Gather(entities) {
|
|
15586
16208
|
var _a;
|
|
15587
|
-
|
|
15588
|
-
|
|
16209
|
+
const entityIds = entities === null || entities === void 0 ? void 0 : entities.map(x => { var _a; return (_a = x.Bruce) === null || _a === void 0 ? void 0 : _a.ID; }).filter(x => !!x);
|
|
16210
|
+
if (this.disposed || !(entities === null || entities === void 0 ? void 0 : entities.length) || this.params.simulatedOnly) {
|
|
16211
|
+
return { fetched: false, recordsByIds: this.withSimulated(this.cache.GetRecords(), entityIds) };
|
|
15589
16212
|
}
|
|
15590
16213
|
const { viewer } = this.params;
|
|
15591
16214
|
const windowStart = new Date(viewer.clock.startTime.toString()).getTime();
|
|
@@ -15605,7 +16228,7 @@
|
|
|
15605
16228
|
if (plan.coarse && !this.cache.CoversCoarse(plan.coarse.start, plan.coarse.stop)) {
|
|
15606
16229
|
const records = await this.request(plan.coarse.start, plan.coarse.stop, entities, plan.coarse.sample);
|
|
15607
16230
|
if (this.disposed) {
|
|
15608
|
-
return { fetched, recordsByIds: this.cache.GetRecords() };
|
|
16231
|
+
return { fetched, recordsByIds: this.withSimulated(this.cache.GetRecords(), entityIds) };
|
|
15609
16232
|
}
|
|
15610
16233
|
this.cache.Absorb(plan.coarse.start, this.holdTo(plan.coarse.stop, liveEdge, liveTail), records, true);
|
|
15611
16234
|
fetched = true;
|
|
@@ -15640,7 +16263,17 @@
|
|
|
15640
16263
|
}
|
|
15641
16264
|
}
|
|
15642
16265
|
}
|
|
15643
|
-
return { fetched, recordsByIds: this.cache.GetRecords() };
|
|
16266
|
+
return { fetched, recordsByIds: this.withSimulated(this.cache.GetRecords(), entityIds) };
|
|
16267
|
+
}
|
|
16268
|
+
/*
|
|
16269
|
+
* Joins the simulated records for these Entities, or every simulated Entity, into an answer.
|
|
16270
|
+
*/
|
|
16271
|
+
withSimulated(recordsByIds, entityIds) {
|
|
16272
|
+
const simulation = this.params.simulation;
|
|
16273
|
+
if (!simulation || simulation.IsEmpty) {
|
|
16274
|
+
return recordsByIds;
|
|
16275
|
+
}
|
|
16276
|
+
return simulation.MergeRecords(recordsByIds, this.params.getAttrKey(), entityIds);
|
|
15644
16277
|
}
|
|
15645
16278
|
/*
|
|
15646
16279
|
* Returns how much of a range that was just read may be marked as held.
|
|
@@ -15675,7 +16308,7 @@
|
|
|
15675
16308
|
}).then((res) => {
|
|
15676
16309
|
const records = res.recordsByIds || {};
|
|
15677
16310
|
if (!this.disposed && this.params.onRecords) {
|
|
15678
|
-
this.params.onRecords(records);
|
|
16311
|
+
this.params.onRecords(this.withSimulated(records, entityIds));
|
|
15679
16312
|
}
|
|
15680
16313
|
return records;
|
|
15681
16314
|
}).finally(() => {
|
|
@@ -15747,7 +16380,6 @@
|
|
|
15747
16380
|
this.renderQueue = [];
|
|
15748
16381
|
this.renderQueueInterval = null;
|
|
15749
16382
|
this.sources = [];
|
|
15750
|
-
this.reRenderState = new EntityReRenderMaintainState();
|
|
15751
16383
|
// Highly experimental flag to try improve rendering large sets of polygons and polylines.
|
|
15752
16384
|
// Many things are not supported when this is enabled.
|
|
15753
16385
|
this.useGeojson = false;
|
|
@@ -15755,6 +16387,10 @@
|
|
|
15755
16387
|
this.zoomControl = [];
|
|
15756
16388
|
// Scenario for retrieving Entities.
|
|
15757
16389
|
this.scenario = null;
|
|
16390
|
+
// Hand-off key of the data currently drawn, or null when it is unknown or nothing is drawn.
|
|
16391
|
+
this.drawnKey = null;
|
|
16392
|
+
// How the drawn entities were last told to look, see getDrawnSettingsSignature.
|
|
16393
|
+
this.drawnSettings = null;
|
|
15758
16394
|
// Type IDs that we'll allow to be rendered when receiving Entities.
|
|
15759
16395
|
// This might be exactly the Menu Item Type ID because of local data sources.
|
|
15760
16396
|
this.allowedTypeIDs = [];
|
|
@@ -15767,6 +16403,14 @@
|
|
|
15767
16403
|
*/
|
|
15768
16404
|
this.renderAsIndividualsChain = Promise.resolve();
|
|
15769
16405
|
const { viewer, apiGetter, monitor, item, register: visualsManager, sharedGetters, onSeriesDiscovered } = params;
|
|
16406
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation, () => {
|
|
16407
|
+
// Read at the scene's time only when the item follows history, the same choice its reads make.
|
|
16408
|
+
const bruceEntity = this.item.BruceEntity;
|
|
16409
|
+
if (!(bruceEntity === null || bruceEntity === void 0 ? void 0 : bruceEntity.historic) && !(bruceEntity === null || bruceEntity === void 0 ? void 0 : bruceEntity.historicAttrKey)) {
|
|
16410
|
+
return null;
|
|
16411
|
+
}
|
|
16412
|
+
return { timeMs: Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime(), attrKey: bruceEntity.historicAttrKey };
|
|
16413
|
+
});
|
|
15770
16414
|
this.viewer = viewer;
|
|
15771
16415
|
this.sharedGetters = sharedGetters;
|
|
15772
16416
|
this.monitor = monitor;
|
|
@@ -15780,7 +16424,8 @@
|
|
|
15780
16424
|
getApi: () => this.apiGetter.getApi(),
|
|
15781
16425
|
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
15782
16426
|
// A second either side, to take in records sitting exactly on the boundary.
|
|
15783
|
-
paddingMs: 1000
|
|
16427
|
+
paddingMs: 1000,
|
|
16428
|
+
simulation: params.simulation
|
|
15784
16429
|
});
|
|
15785
16430
|
this.useGeojson = item.renderAsGeojson == true;
|
|
15786
16431
|
if (item.enableClustering) {
|
|
@@ -15804,9 +16449,26 @@
|
|
|
15804
16449
|
if (this.disposed) {
|
|
15805
16450
|
return;
|
|
15806
16451
|
}
|
|
16452
|
+
// Landing on the data already drawn re-applies settings instead of removing and re-fetching it.
|
|
16453
|
+
const nextKey = shouldRender ? Manager.GetHandoffKey(this.item) : null;
|
|
16454
|
+
const keepDrawn = nextKey != null && nextKey === this.drawnKey;
|
|
16455
|
+
const restyle = keepDrawn && this.drawnSettings !== this.getDrawnSettingsSignature();
|
|
16456
|
+
this.drawnKey = nextKey;
|
|
16457
|
+
this.drawnSettings = this.getDrawnSettingsSignature();
|
|
15807
16458
|
this.unsetGetter();
|
|
15808
16459
|
(_a = this.viewMonitorRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
15809
16460
|
this.viewMonitorRemoval = null;
|
|
16461
|
+
if (keepDrawn) {
|
|
16462
|
+
this.setGetter();
|
|
16463
|
+
this.viewMonitorRemoval = this.monitor.Updated().Subscribe(() => {
|
|
16464
|
+
var _a;
|
|
16465
|
+
(_a = this.entityCheckQueue) === null || _a === void 0 ? void 0 : _a.Call();
|
|
16466
|
+
});
|
|
16467
|
+
if (restyle) {
|
|
16468
|
+
this.ReRender({ entityIds: Object.keys(this.renderedEntities), force: true });
|
|
16469
|
+
}
|
|
16470
|
+
return;
|
|
16471
|
+
}
|
|
15810
16472
|
clearInterval(this.renderQueueInterval);
|
|
15811
16473
|
this.renderQueueInterval = null;
|
|
15812
16474
|
this.renderQueue = [];
|
|
@@ -15840,6 +16502,18 @@
|
|
|
15840
16502
|
}
|
|
15841
16503
|
})();
|
|
15842
16504
|
}
|
|
16505
|
+
/*
|
|
16506
|
+
* Everything about how drawn entities look that applying the item's settings can change.
|
|
16507
|
+
*/
|
|
16508
|
+
getDrawnSettingsSignature() {
|
|
16509
|
+
var _a;
|
|
16510
|
+
return JSON.stringify({
|
|
16511
|
+
zoomControl: exports.RenderManager.GetZoomControlSignature(this.zoomControl),
|
|
16512
|
+
renderPriority: (_a = this.renderPriority) !== null && _a !== void 0 ? _a : null,
|
|
16513
|
+
historicDrawTrack: Boolean(this.item.historicDrawTrack),
|
|
16514
|
+
historicInterpolation: Boolean(this.item.historicInterpolation)
|
|
16515
|
+
});
|
|
16516
|
+
}
|
|
15843
16517
|
applyItemSettings() {
|
|
15844
16518
|
var _a, _b, _c, _d, _e, _f;
|
|
15845
16519
|
// Reset allowed list if there's change.
|
|
@@ -15961,8 +16635,9 @@
|
|
|
15961
16635
|
return;
|
|
15962
16636
|
}
|
|
15963
16637
|
this.updateAllowedTypeIDs(data.entityTypeSources, data.entities);
|
|
16638
|
+
// The getter answers from the API, so a simulated Entity in its answer is swapped for its blob.
|
|
15964
16639
|
if (isTagItem) {
|
|
15965
|
-
this.distributeForRender(data.entities.filter((entity) => {
|
|
16640
|
+
this.distributeForRender(this.reRenderState.withSimulated(data.entities.filter((entity) => {
|
|
15966
16641
|
let entityTags = entity.Bruce["Layer.ID"];
|
|
15967
16642
|
if (!entityTags) {
|
|
15968
16643
|
entityTags = [];
|
|
@@ -15970,10 +16645,10 @@
|
|
|
15970
16645
|
return entityTags.some((tag) => {
|
|
15971
16646
|
return tagsToRender.indexOf(tag) !== -1;
|
|
15972
16647
|
});
|
|
15973
|
-
}));
|
|
16648
|
+
})));
|
|
15974
16649
|
}
|
|
15975
16650
|
else {
|
|
15976
|
-
this.distributeForRender(data.entities);
|
|
16651
|
+
this.distributeForRender(this.reRenderState.withSimulated(data.entities));
|
|
15977
16652
|
}
|
|
15978
16653
|
});
|
|
15979
16654
|
// Cesium itself handles single-visibility ranges very well.
|
|
@@ -16013,6 +16688,10 @@
|
|
|
16013
16688
|
// Remove regos directly.
|
|
16014
16689
|
if (event.action === "D") {
|
|
16015
16690
|
for (const entityId of affectedIds) {
|
|
16691
|
+
// Deleted in the API, but drawn from its simulation until that is cleared.
|
|
16692
|
+
if (this.reRenderState.isSimulated(entityId)) {
|
|
16693
|
+
continue;
|
|
16694
|
+
}
|
|
16016
16695
|
this.visualsManager.RemoveRegos({
|
|
16017
16696
|
entityId,
|
|
16018
16697
|
menuItemId: this.item.id,
|
|
@@ -16210,10 +16889,13 @@
|
|
|
16210
16889
|
console.warn("Geojson rendering does not support multiple zoom controls. Only the first one will be used.");
|
|
16211
16890
|
this.zoomControl = [this.zoomControl[0]];
|
|
16212
16891
|
}
|
|
16892
|
+
this.drawnSettings = this.getDrawnSettingsSignature();
|
|
16213
16893
|
changed = true;
|
|
16214
16894
|
}
|
|
16215
16895
|
if (scenario != null) {
|
|
16216
16896
|
this.scenario = scenario;
|
|
16897
|
+
// The drawn records now belong to a scenario the item does not name.
|
|
16898
|
+
this.drawnKey = null;
|
|
16217
16899
|
changed = true;
|
|
16218
16900
|
}
|
|
16219
16901
|
if (changed) {
|
|
@@ -16228,6 +16910,16 @@
|
|
|
16228
16910
|
this.doEntityCheck(entityIds);
|
|
16229
16911
|
}
|
|
16230
16912
|
}
|
|
16913
|
+
/**
|
|
16914
|
+
* Switches to another of the item's own styles, restyling what is drawn without re-creating it.
|
|
16915
|
+
*/
|
|
16916
|
+
SwapStyle(item) {
|
|
16917
|
+
if (this.disposed) {
|
|
16918
|
+
return;
|
|
16919
|
+
}
|
|
16920
|
+
this.item = item;
|
|
16921
|
+
this.UpdateSettings({ zoomControl: item.CameraZoomSettings });
|
|
16922
|
+
}
|
|
16231
16923
|
/**
|
|
16232
16924
|
* Narrows a camera-driven check to the entities whose zoom band could actually have changed.
|
|
16233
16925
|
* @param ids
|
|
@@ -16981,6 +17673,8 @@
|
|
|
16981
17673
|
AdoptHandoff(payload) {
|
|
16982
17674
|
var _a;
|
|
16983
17675
|
const { shouldRender } = this.applyItemSettings();
|
|
17676
|
+
this.drawnKey = shouldRender ? Manager.GetHandoffKey(this.item) : null;
|
|
17677
|
+
this.drawnSettings = this.getDrawnSettingsSignature();
|
|
16984
17678
|
this.visualsManager.ReassignMenuItem({
|
|
16985
17679
|
fromMenuItemId: payload.sourceMenuItemId,
|
|
16986
17680
|
toMenuItemId: this.item.id,
|
|
@@ -17136,7 +17830,6 @@
|
|
|
17136
17830
|
// Highly experimental flag to try improve rendering large sets of polygons and polylines.
|
|
17137
17831
|
// Many things are not supported when this is enabled.
|
|
17138
17832
|
this.useGeojson = false;
|
|
17139
|
-
this.reRenderState = new EntityReRenderMaintainState();
|
|
17140
17833
|
/**
|
|
17141
17834
|
* Our default path.
|
|
17142
17835
|
* We render each entity individually.
|
|
@@ -17146,6 +17839,7 @@
|
|
|
17146
17839
|
*/
|
|
17147
17840
|
this.renderAsIndividualsChain = Promise.resolve();
|
|
17148
17841
|
const { viewer, apiGetter, monitor, item, register: visualsManager } = params;
|
|
17842
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation);
|
|
17149
17843
|
this.viewer = viewer;
|
|
17150
17844
|
this.apiGetter = apiGetter;
|
|
17151
17845
|
this.monitor = monitor;
|
|
@@ -17268,7 +17962,8 @@
|
|
|
17268
17962
|
continue;
|
|
17269
17963
|
}
|
|
17270
17964
|
}
|
|
17271
|
-
|
|
17965
|
+
// The item carries its own Entities, so a simulated one among them is swapped for its blob.
|
|
17966
|
+
this.onGetterUpdate(this.reRenderState.withSimulated(entities));
|
|
17272
17967
|
});
|
|
17273
17968
|
this.getter.Start();
|
|
17274
17969
|
}
|
|
@@ -17355,6 +18050,16 @@
|
|
|
17355
18050
|
this.doEntityCheck(entityIds);
|
|
17356
18051
|
}
|
|
17357
18052
|
}
|
|
18053
|
+
/**
|
|
18054
|
+
* Switches to another of the item's own styles, restyling what is drawn without re-creating it.
|
|
18055
|
+
*/
|
|
18056
|
+
SwapStyle(item) {
|
|
18057
|
+
if (this.disposed) {
|
|
18058
|
+
return;
|
|
18059
|
+
}
|
|
18060
|
+
this.item = item;
|
|
18061
|
+
this.UpdateSettings({ zoomControl: item.CameraZoomSettings });
|
|
18062
|
+
}
|
|
17358
18063
|
async doEntityCheck(ids, force = false) {
|
|
17359
18064
|
var _a, _b;
|
|
17360
18065
|
const api = this.apiGetter.getApi();
|
|
@@ -17910,8 +18615,15 @@
|
|
|
17910
18615
|
this.renderQueueActive = false;
|
|
17911
18616
|
this.renderQueue = [];
|
|
17912
18617
|
this.renderQueueForceFlags = [];
|
|
17913
|
-
this.reRenderState = new EntityReRenderMaintainState();
|
|
17914
18618
|
const { viewer, apiGetter, monitor, item, register: visualsManager } = params;
|
|
18619
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation, () => {
|
|
18620
|
+
// Read at the scene's time only when the item follows history, the same choice its reads make.
|
|
18621
|
+
const bruceEntity = this.item.BruceEntity;
|
|
18622
|
+
if (!(bruceEntity === null || bruceEntity === void 0 ? void 0 : bruceEntity.historic) && !(bruceEntity === null || bruceEntity === void 0 ? void 0 : bruceEntity.historicAttrKey)) {
|
|
18623
|
+
return null;
|
|
18624
|
+
}
|
|
18625
|
+
return { timeMs: Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime(), attrKey: bruceEntity.historicAttrKey };
|
|
18626
|
+
});
|
|
17915
18627
|
this.sharedHistoric = params.sharedHistoric;
|
|
17916
18628
|
this.viewer = viewer;
|
|
17917
18629
|
this.apiGetter = apiGetter;
|
|
@@ -17924,7 +18636,8 @@
|
|
|
17924
18636
|
getApi: () => this.apiGetter.getApi(),
|
|
17925
18637
|
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
17926
18638
|
// Padding either side of a requested range, for clock desync between us and the server.
|
|
17927
|
-
paddingMs: 15000
|
|
18639
|
+
paddingMs: 15000,
|
|
18640
|
+
simulation: params.simulation
|
|
17928
18641
|
});
|
|
17929
18642
|
if (this.item.enableClustering) {
|
|
17930
18643
|
this.clustering = new PointClustering(visualsManager, this.item.id, (_a = this.item) === null || _a === void 0 ? void 0 : _a.clustering);
|
|
@@ -18047,6 +18760,16 @@
|
|
|
18047
18760
|
this.onGetterUpdate(entityIds);
|
|
18048
18761
|
}
|
|
18049
18762
|
}
|
|
18763
|
+
/**
|
|
18764
|
+
* Switches to another of the item's own styles, restyling what is drawn without re-creating it.
|
|
18765
|
+
*/
|
|
18766
|
+
SwapStyle(item) {
|
|
18767
|
+
if (this.disposed) {
|
|
18768
|
+
return;
|
|
18769
|
+
}
|
|
18770
|
+
this.item = item;
|
|
18771
|
+
this.UpdateSettings({ zoomControl: item.CameraZoomSettings });
|
|
18772
|
+
}
|
|
18050
18773
|
/*
|
|
18051
18774
|
* The lane this item reads through, or null when it does not follow the clock.
|
|
18052
18775
|
*/
|
|
@@ -18382,9 +19105,9 @@
|
|
|
18382
19105
|
this.getter = null;
|
|
18383
19106
|
this.getterSub = null;
|
|
18384
19107
|
this.disposed = false;
|
|
18385
|
-
this.reRenderState = new EntityReRenderMaintainState();
|
|
18386
19108
|
this.renderEntityChain = Promise.resolve();
|
|
18387
19109
|
const { viewer, apiGetter, monitor, item, register: visualsManager } = params;
|
|
19110
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation);
|
|
18388
19111
|
this.viewer = viewer;
|
|
18389
19112
|
this.apiGetter = apiGetter;
|
|
18390
19113
|
this.monitor = monitor;
|
|
@@ -18506,6 +19229,16 @@
|
|
|
18506
19229
|
this.onGetterUpdate(entityId, true);
|
|
18507
19230
|
}
|
|
18508
19231
|
}
|
|
19232
|
+
/**
|
|
19233
|
+
* Switches to another of the item's own styles, restyling what is drawn without re-creating it.
|
|
19234
|
+
*/
|
|
19235
|
+
SwapStyle(item) {
|
|
19236
|
+
if (this.disposed) {
|
|
19237
|
+
return;
|
|
19238
|
+
}
|
|
19239
|
+
this.item = item;
|
|
19240
|
+
this.UpdateSettings({ zoomControl: item.CameraZoomSettings });
|
|
19241
|
+
}
|
|
18509
19242
|
renderEntity(entity, force = false) {
|
|
18510
19243
|
// Waiting for prior call to finish resolving.
|
|
18511
19244
|
// This avoids race conditions against two sets of overlapping Entities.
|
|
@@ -18658,6 +19391,122 @@
|
|
|
18658
19391
|
];
|
|
18659
19392
|
})(CodeLogicExceptions || (CodeLogicExceptions = {}));
|
|
18660
19393
|
|
|
19394
|
+
/**
|
|
19395
|
+
* The line drawn through where a moving thing has been, from its history, as a whole path or a fading trail.
|
|
19396
|
+
*/
|
|
19397
|
+
var HistoricTrail;
|
|
19398
|
+
(function (HistoricTrail) {
|
|
19399
|
+
const BANDS = 12;
|
|
19400
|
+
const SAMPLES = 96;
|
|
19401
|
+
const WIDTH_FAR = 1;
|
|
19402
|
+
const ALPHA_FAR = 0.05;
|
|
19403
|
+
// Above 1, so width and alpha hold near the head and give way further back.
|
|
19404
|
+
const WIDTH_CURVE = 1.4;
|
|
19405
|
+
const ALPHA_CURVE = 1.25;
|
|
19406
|
+
// How strongly a line is drawn where it passes behind the globe, against its own alpha.
|
|
19407
|
+
const BEHIND_ALPHA = 0.35;
|
|
19408
|
+
/**
|
|
19409
|
+
* The trail length a menu item asks for in its historicTrackSeconds, or null for the whole path.
|
|
19410
|
+
*/
|
|
19411
|
+
function GetTrailSeconds(item) {
|
|
19412
|
+
const seconds = Number(item === null || item === void 0 ? void 0 : item.historicTrackSeconds);
|
|
19413
|
+
return seconds > 0 ? seconds : null;
|
|
19414
|
+
}
|
|
19415
|
+
HistoricTrail.GetTrailSeconds = GetTrailSeconds;
|
|
19416
|
+
class Trail {
|
|
19417
|
+
constructor(params) {
|
|
19418
|
+
this.entities = [];
|
|
19419
|
+
this.memoTime = null;
|
|
19420
|
+
this.memo = [];
|
|
19421
|
+
this.viewer = params.viewer;
|
|
19422
|
+
const trailing = params.trailSeconds > 0 && Boolean(params.positionAt);
|
|
19423
|
+
if (!trailing) {
|
|
19424
|
+
this.add(params, params.color, params.width, () => { var _a; return (_a = params.getSeries()) !== null && _a !== void 0 ? _a : []; });
|
|
19425
|
+
return;
|
|
19426
|
+
}
|
|
19427
|
+
for (let band = 0; band < BANDS; band++) {
|
|
19428
|
+
// 0 at the head, 1 at the far end.
|
|
19429
|
+
const age = band / (BANDS - 1);
|
|
19430
|
+
const width = params.width - (params.width - WIDTH_FAR) * Math.pow(age, WIDTH_CURVE);
|
|
19431
|
+
const alpha = params.color.alpha - (params.color.alpha - ALPHA_FAR) * Math.pow(age, ALPHA_CURVE);
|
|
19432
|
+
this.add(params, params.color.withAlpha(alpha), Math.max(WIDTH_FAR, width), (time) => {
|
|
19433
|
+
return this.slice(this.sample(params, time), band);
|
|
19434
|
+
});
|
|
19435
|
+
}
|
|
19436
|
+
}
|
|
19437
|
+
/*
|
|
19438
|
+
* One polyline of the trail, its positions read from the scene's time.
|
|
19439
|
+
*/
|
|
19440
|
+
add(params, color, width, positions) {
|
|
19441
|
+
const entity = this.viewer.entities.add({
|
|
19442
|
+
id: BModels.ObjectUtils.UId(15),
|
|
19443
|
+
polyline: {
|
|
19444
|
+
positions: new Cesium.CallbackProperty((time) => positions(time), false),
|
|
19445
|
+
width: width,
|
|
19446
|
+
material: color,
|
|
19447
|
+
clampToGround: params.clampToGround,
|
|
19448
|
+
// A path through the air follows no ellipsoid, so it is drawn as the straight runs it holds.
|
|
19449
|
+
arcType: params.clampToGround ? Cesium.ArcType.GEODESIC : Cesium.ArcType.NONE,
|
|
19450
|
+
// Drawn dimmer behind the globe rather than winking in and out against the terrain along the limb.
|
|
19451
|
+
depthFailMaterial: params.clampToGround ? undefined : color.withAlpha(color.alpha * BEHIND_ALPHA),
|
|
19452
|
+
zIndex: 0,
|
|
19453
|
+
classificationType: params.clampToGround ? Cesium.ClassificationType.BOTH : undefined
|
|
19454
|
+
}
|
|
19455
|
+
});
|
|
19456
|
+
entity._noEdit = true;
|
|
19457
|
+
entity._noSelect = true;
|
|
19458
|
+
exports.CesiumEntityStyler.SetDefaultColor({
|
|
19459
|
+
color: color,
|
|
19460
|
+
entity: entity,
|
|
19461
|
+
viewer: this.viewer,
|
|
19462
|
+
override: true,
|
|
19463
|
+
requestRender: false
|
|
19464
|
+
});
|
|
19465
|
+
this.entities.push(entity);
|
|
19466
|
+
}
|
|
19467
|
+
/*
|
|
19468
|
+
* The trail's positions at a time, newest last, kept for that time so every band reads the same set.
|
|
19469
|
+
*/
|
|
19470
|
+
sample(params, time) {
|
|
19471
|
+
var _a;
|
|
19472
|
+
if (this.memoTime && Cesium.JulianDate.equals(this.memoTime, time)) {
|
|
19473
|
+
return this.memo;
|
|
19474
|
+
}
|
|
19475
|
+
this.memoTime = Cesium.JulianDate.clone(time, (_a = this.memoTime) !== null && _a !== void 0 ? _a : new Cesium.JulianDate());
|
|
19476
|
+
const nowMs = Cesium.JulianDate.toDate(time).getTime();
|
|
19477
|
+
const spanMs = params.trailSeconds * 1000;
|
|
19478
|
+
const points = [];
|
|
19479
|
+
for (let i = 0; i <= SAMPLES; i++) {
|
|
19480
|
+
const pos3d = params.positionAt(nowMs - spanMs + spanMs * i / SAMPLES);
|
|
19481
|
+
if (pos3d) {
|
|
19482
|
+
points.push(pos3d);
|
|
19483
|
+
}
|
|
19484
|
+
}
|
|
19485
|
+
this.memo = points;
|
|
19486
|
+
return points;
|
|
19487
|
+
}
|
|
19488
|
+
/*
|
|
19489
|
+
* A band's run of the samples, counted back from the head, sharing its end point with the next band.
|
|
19490
|
+
*/
|
|
19491
|
+
slice(points, band) {
|
|
19492
|
+
if (points.length < 2) {
|
|
19493
|
+
return [];
|
|
19494
|
+
}
|
|
19495
|
+
const per = (points.length - 1) / BANDS;
|
|
19496
|
+
const end = points.length - 1 - Math.round(band * per);
|
|
19497
|
+
const start = points.length - 1 - Math.round((band + 1) * per);
|
|
19498
|
+
return start < end ? points.slice(Math.max(0, start), end + 1) : [];
|
|
19499
|
+
}
|
|
19500
|
+
Dispose() {
|
|
19501
|
+
for (const entity of this.entities) {
|
|
19502
|
+
RemoveCEntityFromScene(this.viewer, entity);
|
|
19503
|
+
}
|
|
19504
|
+
this.entities = [];
|
|
19505
|
+
}
|
|
19506
|
+
}
|
|
19507
|
+
HistoricTrail.Trail = Trail;
|
|
19508
|
+
})(HistoricTrail || (HistoricTrail = {}));
|
|
19509
|
+
|
|
18661
19510
|
class EntityGatherer {
|
|
18662
19511
|
get OnQueueProgress() {
|
|
18663
19512
|
if (!this._onQueueProgress) {
|
|
@@ -18665,7 +19514,11 @@
|
|
|
18665
19514
|
}
|
|
18666
19515
|
return this._onQueueProgress;
|
|
18667
19516
|
}
|
|
18668
|
-
|
|
19517
|
+
/**
|
|
19518
|
+
* @param simulation what callers simulate in place of API data, used where this gatherer has no override.
|
|
19519
|
+
*/
|
|
19520
|
+
constructor(api, viewer, emitEntities, simulation) {
|
|
19521
|
+
this.simulation = simulation;
|
|
18669
19522
|
this.disposed = false;
|
|
18670
19523
|
this.expandSources = false;
|
|
18671
19524
|
this.historic = null;
|
|
@@ -19242,15 +20095,19 @@
|
|
|
19242
20095
|
}
|
|
19243
20096
|
}
|
|
19244
20097
|
}
|
|
20098
|
+
// A historic read is as at the scene's time, and so is any simulated record laid over it.
|
|
20099
|
+
const rTimeMs = new Date(rTime).getTime();
|
|
20100
|
+
const atPoint = (entity) => this.historic && this.simulation ? this.simulation.ApplyAt(entity, rTimeMs) : entity;
|
|
19245
20101
|
for (const entityId of requestedBatch || []) {
|
|
20102
|
+
// A caller's own override is an unsaved edit, newer than any simulation, so it is used as is.
|
|
19246
20103
|
const override = this.entityDataOverrides.get(entityId);
|
|
19247
20104
|
if (override) {
|
|
19248
20105
|
resolvedEntities.push(override);
|
|
19249
20106
|
continue;
|
|
19250
20107
|
}
|
|
19251
|
-
const found = foundById.get(entityId);
|
|
20108
|
+
const found = this.simulation ? this.simulation.Resolve(entityId, foundById.get(entityId)) : foundById.get(entityId);
|
|
19252
20109
|
if (found) {
|
|
19253
|
-
resolvedEntities.push(found);
|
|
20110
|
+
resolvedEntities.push(atPoint(found));
|
|
19254
20111
|
continue;
|
|
19255
20112
|
}
|
|
19256
20113
|
resolvedEntities.push(this.createFallbackEntity(entityId));
|
|
@@ -19614,7 +20471,7 @@
|
|
|
19614
20471
|
this.styleTilesetFeatureFullData(feature, entity, eTags);
|
|
19615
20472
|
}
|
|
19616
20473
|
}
|
|
19617
|
-
});
|
|
20474
|
+
}, params.simulation);
|
|
19618
20475
|
// Only Entities Sets bake coordinates into their features, so for any other source this
|
|
19619
20476
|
// resolves nothing and the gather stays in insertion order.
|
|
19620
20477
|
this.entityGatherer.SetViewMonitor(this.monitor);
|
|
@@ -21138,6 +21995,9 @@
|
|
|
21138
21995
|
return this.modelTreeUpdate;
|
|
21139
21996
|
}
|
|
21140
21997
|
constructor(params) {
|
|
21998
|
+
this.simulationRemoval = null;
|
|
21999
|
+
// Where the tileset stands by its own record, so a cleared simulation puts it back without a refetch.
|
|
22000
|
+
this.restCoords = null;
|
|
21141
22001
|
this.disposed = false;
|
|
21142
22002
|
this.modelSpace = false;
|
|
21143
22003
|
this.cTileset = null;
|
|
@@ -21175,7 +22035,7 @@
|
|
|
21175
22035
|
this.historicAnimation = null;
|
|
21176
22036
|
this.historicGatherer = null;
|
|
21177
22037
|
// The trail through the root's own movement, which describes the whole assembly.
|
|
21178
|
-
this.
|
|
22038
|
+
this.trail = null;
|
|
21179
22039
|
this.historicPossesLoadingProm = null;
|
|
21180
22040
|
// Queue of loaded in features that we haven't processed yet.
|
|
21181
22041
|
this.featureQueue = [];
|
|
@@ -21189,6 +22049,7 @@
|
|
|
21189
22049
|
this.featurePropCache = new Map();
|
|
21190
22050
|
this.featurePropsChecked = 0;
|
|
21191
22051
|
const { viewer, register: visualsManager, getters, item, modelSpace, initQueue } = params;
|
|
22052
|
+
this.simulation = params.simulation;
|
|
21192
22053
|
this.viewer = viewer;
|
|
21193
22054
|
this.getters = getters;
|
|
21194
22055
|
this.item = item;
|
|
@@ -21353,7 +22214,7 @@
|
|
|
21353
22214
|
historicPoint: this.viewer.clock.currentTime.toString(),
|
|
21354
22215
|
api: api
|
|
21355
22216
|
});
|
|
21356
|
-
coords = coordsFromHistoricEntity(root);
|
|
22217
|
+
coords = coordsFromHistoricEntity(this.atClock(root));
|
|
21357
22218
|
}
|
|
21358
22219
|
catch (e) {
|
|
21359
22220
|
console.error(e);
|
|
@@ -21394,6 +22255,10 @@
|
|
|
21394
22255
|
this.doDispose();
|
|
21395
22256
|
return;
|
|
21396
22257
|
}
|
|
22258
|
+
this.restCoords = coords;
|
|
22259
|
+
if (this.simulatedRootCoords()) {
|
|
22260
|
+
this.applyCoords(tileset, this.simulatedRootCoords());
|
|
22261
|
+
}
|
|
21397
22262
|
this.viewer.scene.requestRender();
|
|
21398
22263
|
exports.TilesetRenderEngine.OnTilesetReady(this.cTileset).then(() => {
|
|
21399
22264
|
var _a, _b, _c;
|
|
@@ -21413,6 +22278,7 @@
|
|
|
21413
22278
|
}
|
|
21414
22279
|
this.onCTilesetLoad();
|
|
21415
22280
|
this.styler.Init({
|
|
22281
|
+
simulation: this.simulation,
|
|
21416
22282
|
viewer: this.viewer,
|
|
21417
22283
|
// Default API instead of the account one.
|
|
21418
22284
|
// Records are driven by the account loading it instead of the source account.
|
|
@@ -21428,6 +22294,7 @@
|
|
|
21428
22294
|
});
|
|
21429
22295
|
this.viewer.scene.requestRender();
|
|
21430
22296
|
// Monitor scene time changes and update the root Entity.
|
|
22297
|
+
this.followSimulation(tileset);
|
|
21431
22298
|
this.viewerDateTimeSub(tileset);
|
|
21432
22299
|
}
|
|
21433
22300
|
catch (e) {
|
|
@@ -21483,7 +22350,7 @@
|
|
|
21483
22350
|
*/
|
|
21484
22351
|
applyRootTrack() {
|
|
21485
22352
|
var _a;
|
|
21486
|
-
if (!this.item.historicDrawTrack || !this.historicAnimation || this.
|
|
22353
|
+
if (!this.item.historicDrawTrack || !this.historicAnimation || this.trail) {
|
|
21487
22354
|
return;
|
|
21488
22355
|
}
|
|
21489
22356
|
const trackStyle = exports.EntityRenderEngine.GetTrackStyle({
|
|
@@ -21493,26 +22360,14 @@
|
|
|
21493
22360
|
if (!trackStyle) {
|
|
21494
22361
|
return;
|
|
21495
22362
|
}
|
|
21496
|
-
this
|
|
21497
|
-
|
|
21498
|
-
polyline: {
|
|
21499
|
-
positions: new Cesium.CallbackProperty(() => { var _a, _b; return (_b = (_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.GetSeries()) !== null && _b !== void 0 ? _b : []; }, false),
|
|
21500
|
-
width: trackStyle.width,
|
|
21501
|
-
material: trackStyle.color,
|
|
21502
|
-
clampToGround: exports.EntityRenderEngine.GetHeightRefPolyline(Manager.GetRecordHeightRef(this.item))
|
|
21503
|
-
== Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
21504
|
-
zIndex: 0,
|
|
21505
|
-
classificationType: Cesium.ClassificationType.BOTH
|
|
21506
|
-
}
|
|
21507
|
-
});
|
|
21508
|
-
this.trackEntity._noEdit = true;
|
|
21509
|
-
this.trackEntity._noSelect = true;
|
|
21510
|
-
exports.CesiumEntityStyler.SetDefaultColor({
|
|
21511
|
-
color: trackStyle.color,
|
|
21512
|
-
entity: this.trackEntity,
|
|
22363
|
+
// The series has no position at an arbitrary time, so this draws the whole path rather than a trail.
|
|
22364
|
+
this.trail = new HistoricTrail.Trail({
|
|
21513
22365
|
viewer: this.viewer,
|
|
21514
|
-
|
|
21515
|
-
|
|
22366
|
+
color: trackStyle.color,
|
|
22367
|
+
width: trackStyle.width,
|
|
22368
|
+
clampToGround: exports.EntityRenderEngine.GetHeightRefPolyline(Manager.GetRecordHeightRef(this.item))
|
|
22369
|
+
== Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
22370
|
+
getSeries: () => { var _a, _b; return (_b = (_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.GetSeries()) !== null && _b !== void 0 ? _b : []; }
|
|
21516
22371
|
});
|
|
21517
22372
|
}
|
|
21518
22373
|
/**
|
|
@@ -21565,7 +22420,7 @@
|
|
|
21565
22420
|
}
|
|
21566
22421
|
// Returns null (fall back to a normal Dispose()) if the tileset hasn't finished loading yet.
|
|
21567
22422
|
PrepareHandoff() {
|
|
21568
|
-
var _a, _b, _c, _d;
|
|
22423
|
+
var _a, _b, _c, _d, _e;
|
|
21569
22424
|
if (this.disposed || !this.cTileset || this.cTileset.isDestroyed()) {
|
|
21570
22425
|
return null;
|
|
21571
22426
|
}
|
|
@@ -21583,9 +22438,11 @@
|
|
|
21583
22438
|
this.handoffSourceMenuItemId = null;
|
|
21584
22439
|
// Not transferred, the receiving manager sets up its own fresh copy if needed.
|
|
21585
22440
|
this.viewerDateTimeDispose();
|
|
21586
|
-
(_b = this.
|
|
21587
|
-
|
|
21588
|
-
(
|
|
22441
|
+
(_b = this.simulationRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
22442
|
+
this.simulationRemoval = null;
|
|
22443
|
+
(_c = this.styler) === null || _c === void 0 ? void 0 : _c.Dispose();
|
|
22444
|
+
(_d = this.tileLoadRemoval) === null || _d === void 0 ? void 0 : _d.call(this);
|
|
22445
|
+
(_e = this.tileUnloadRemoval) === null || _e === void 0 ? void 0 : _e.call(this);
|
|
21589
22446
|
this.tileLoadRemoval = null;
|
|
21590
22447
|
this.tileUnloadRemoval = null;
|
|
21591
22448
|
const payload = {
|
|
@@ -21606,7 +22463,7 @@
|
|
|
21606
22463
|
// Takes ownership of a PrepareHandoff() payload instead of loading via Init().
|
|
21607
22464
|
// Then re-parents every already-registered rego to this menu item and re-runs styling.
|
|
21608
22465
|
AdoptHandoff(payload) {
|
|
21609
|
-
var _a, _b, _c, _d;
|
|
22466
|
+
var _a, _b, _c, _d, _e;
|
|
21610
22467
|
this.cTileset = payload.cTileset;
|
|
21611
22468
|
this.tileset = payload.tileset;
|
|
21612
22469
|
this.rootId = payload.rootId;
|
|
@@ -21637,6 +22494,7 @@
|
|
|
21637
22494
|
// Same visuals, same registrations so just re-keyed onto this menu item.
|
|
21638
22495
|
this.onCTilesetLoad();
|
|
21639
22496
|
this.styler.Init({
|
|
22497
|
+
simulation: this.simulation,
|
|
21640
22498
|
viewer: this.viewer,
|
|
21641
22499
|
api: this.getters.GetBruceApi(),
|
|
21642
22500
|
cTileset: this.cTileset,
|
|
@@ -21670,7 +22528,9 @@
|
|
|
21670
22528
|
}
|
|
21671
22529
|
});
|
|
21672
22530
|
this.viewer.scene.requestRender();
|
|
21673
|
-
if (
|
|
22531
|
+
if (this.tileset) {
|
|
22532
|
+
this.restCoords = (_d = this.restCoords) !== null && _d !== void 0 ? _d : (_e = this.cTileset) === null || _e === void 0 ? void 0 : _e._bruceCoords;
|
|
22533
|
+
this.followSimulation(this.tileset);
|
|
21674
22534
|
this.viewerDateTimeSub(this.tileset);
|
|
21675
22535
|
}
|
|
21676
22536
|
}
|
|
@@ -22248,6 +23108,21 @@
|
|
|
22248
23108
|
}
|
|
22249
23109
|
return children;
|
|
22250
23110
|
}
|
|
23111
|
+
/**
|
|
23112
|
+
* Switches to another of the item's own styles, restyling the loaded tileset without reloading it.
|
|
23113
|
+
*/
|
|
23114
|
+
SwapStyle(item) {
|
|
23115
|
+
var _a;
|
|
23116
|
+
if (this.disposed) {
|
|
23117
|
+
return;
|
|
23118
|
+
}
|
|
23119
|
+
this.item = item;
|
|
23120
|
+
// Before the tileset loads this only stores the pick, and the styler's Init reads the new item.
|
|
23121
|
+
this.styler.UpdateStyleMapping({
|
|
23122
|
+
styleMapping: (_a = item.StyleMapping) !== null && _a !== void 0 ? _a : [],
|
|
23123
|
+
fallbackStyleId: item.styleId
|
|
23124
|
+
});
|
|
23125
|
+
}
|
|
22251
23126
|
Dispose() {
|
|
22252
23127
|
var _a;
|
|
22253
23128
|
if (this.disposed) {
|
|
@@ -22258,7 +23133,7 @@
|
|
|
22258
23133
|
this.doDispose();
|
|
22259
23134
|
}
|
|
22260
23135
|
doDispose() {
|
|
22261
|
-
var _a, _b, _c;
|
|
23136
|
+
var _a, _b, _c, _d;
|
|
22262
23137
|
if (this.featureQueueInterval) {
|
|
22263
23138
|
clearInterval(this.featureQueueInterval);
|
|
22264
23139
|
this.featureQueueInterval = null;
|
|
@@ -22293,6 +23168,8 @@
|
|
|
22293
23168
|
this.handoffSourceMenuItemId = null;
|
|
22294
23169
|
}
|
|
22295
23170
|
this.viewerDateTimeDispose();
|
|
23171
|
+
(_d = this.simulationRemoval) === null || _d === void 0 ? void 0 : _d.call(this);
|
|
23172
|
+
this.simulationRemoval = null;
|
|
22296
23173
|
}
|
|
22297
23174
|
async ReRender(params) {
|
|
22298
23175
|
let { entityIds, force, entities, maintain } = params;
|
|
@@ -22318,8 +23195,11 @@
|
|
|
22318
23195
|
* @param tileset
|
|
22319
23196
|
*/
|
|
22320
23197
|
viewerDateTimeSub(tileset) {
|
|
22321
|
-
var _a;
|
|
22322
|
-
|
|
23198
|
+
var _a, _b;
|
|
23199
|
+
// An item that is not historic still follows the root's simulated records, once there are some.
|
|
23200
|
+
const historic = Boolean((_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historic);
|
|
23201
|
+
const simulated = Boolean(this.rootId && ((_b = this.simulation) === null || _b === void 0 ? void 0 : _b.GetRecords(this.rootId).length));
|
|
23202
|
+
if ((!historic && !simulated) || this.historicGatherer || this.viewerDateTimeChangeRemoval) {
|
|
22323
23203
|
return;
|
|
22324
23204
|
}
|
|
22325
23205
|
const accountId = this.accountIdForRecords();
|
|
@@ -22348,6 +23228,8 @@
|
|
|
22348
23228
|
// Time padding in milliseconds (15 seconds).
|
|
22349
23229
|
// Helps account for desync between client and server.
|
|
22350
23230
|
paddingMs: 15000,
|
|
23231
|
+
simulation: this.simulation,
|
|
23232
|
+
simulatedOnly: !historic,
|
|
22351
23233
|
onRecords: (recordsByIds) => {
|
|
22352
23234
|
var _a;
|
|
22353
23235
|
const records = recordsByIds[this.rootId];
|
|
@@ -22375,6 +23257,7 @@
|
|
|
22375
23257
|
*/
|
|
22376
23258
|
const getInitialPosses = async () => {
|
|
22377
23259
|
this.historicPossesLoadingProm = new Promise(async (res) => {
|
|
23260
|
+
var _a;
|
|
22378
23261
|
try {
|
|
22379
23262
|
if (this.disposed) {
|
|
22380
23263
|
res(false);
|
|
@@ -22387,11 +23270,16 @@
|
|
|
22387
23270
|
return;
|
|
22388
23271
|
}
|
|
22389
23272
|
// Also request the current position in case its not in the range.
|
|
22390
|
-
|
|
23273
|
+
// A simulated root, or an item that is not historic, has no current record to ask the API for.
|
|
23274
|
+
if (!historic || ((_a = this.simulation) === null || _a === void 0 ? void 0 : _a.HasEntity(this.rootId))) {
|
|
23275
|
+
res(positions);
|
|
23276
|
+
return;
|
|
23277
|
+
}
|
|
23278
|
+
const entity = this.atClock((await BModels.Entity.Get({
|
|
22391
23279
|
entityId: this.rootId,
|
|
22392
23280
|
historicPoint: this.viewer.clock.currentTime.toString(),
|
|
22393
23281
|
api: api
|
|
22394
|
-
});
|
|
23282
|
+
})).entity);
|
|
22395
23283
|
if (this.disposed || !entity) {
|
|
22396
23284
|
res(false);
|
|
22397
23285
|
return;
|
|
@@ -22471,14 +23359,15 @@
|
|
|
22471
23359
|
}
|
|
22472
23360
|
});
|
|
22473
23361
|
this.viewerDateTimeChangeRemoval = () => {
|
|
23362
|
+
var _a, _b;
|
|
22474
23363
|
if (this.historicAnimation) {
|
|
22475
23364
|
this.historicAnimation.stop();
|
|
22476
23365
|
this.historicAnimation = null;
|
|
22477
23366
|
}
|
|
22478
|
-
|
|
22479
|
-
|
|
22480
|
-
|
|
22481
|
-
|
|
23367
|
+
(_a = this.historicGatherer) === null || _a === void 0 ? void 0 : _a.Dispose();
|
|
23368
|
+
this.historicGatherer = null;
|
|
23369
|
+
(_b = this.trail) === null || _b === void 0 ? void 0 : _b.Dispose();
|
|
23370
|
+
this.trail = null;
|
|
22482
23371
|
if (clockTickRemoval) {
|
|
22483
23372
|
clockTickRemoval();
|
|
22484
23373
|
clockTickRemoval = null;
|
|
@@ -22486,10 +23375,84 @@
|
|
|
22486
23375
|
};
|
|
22487
23376
|
});
|
|
22488
23377
|
}
|
|
22489
|
-
|
|
23378
|
+
/*
|
|
23379
|
+
* Keeps the tileset in line with what is simulated for its root Entity.
|
|
23380
|
+
*/
|
|
23381
|
+
followSimulation(tileset) {
|
|
23382
|
+
if (this.simulationRemoval || !this.simulation) {
|
|
23383
|
+
return;
|
|
23384
|
+
}
|
|
23385
|
+
this.simulationRemoval = this.simulation.OnChanged.Subscribe((change) => {
|
|
23386
|
+
var _a;
|
|
23387
|
+
if (this.disposed || !this.rootId || !change.entityIds.includes(this.rootId)) {
|
|
23388
|
+
return;
|
|
23389
|
+
}
|
|
23390
|
+
if (change.records) {
|
|
23391
|
+
this.regatherRoot(tileset);
|
|
23392
|
+
}
|
|
23393
|
+
// A simulated root is where the tileset stands outside its history; recorded positions still win.
|
|
23394
|
+
if (change.entities && !((_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.getDateRange().minDate)) {
|
|
23395
|
+
this.applyRootRest(tileset);
|
|
23396
|
+
}
|
|
23397
|
+
});
|
|
23398
|
+
}
|
|
23399
|
+
/*
|
|
23400
|
+
* Re-reads the root's history after its simulated records changed, following the clock if it was not.
|
|
23401
|
+
*/
|
|
23402
|
+
async regatherRoot(tileset) {
|
|
22490
23403
|
var _a;
|
|
23404
|
+
if (!this.historicGatherer) {
|
|
23405
|
+
this.viewerDateTimeSub(tileset);
|
|
23406
|
+
return;
|
|
23407
|
+
}
|
|
23408
|
+
await this.historicPossesLoadingProm;
|
|
23409
|
+
const { recordsByIds } = await this.historicGatherer.Gather([{ Bruce: { ID: this.rootId } }]);
|
|
23410
|
+
if (this.disposed) {
|
|
23411
|
+
return;
|
|
23412
|
+
}
|
|
23413
|
+
const posses = Manager.HistoricPossesFor({ viewer: this.viewer, item: this.item, records: recordsByIds[this.rootId] || [] });
|
|
23414
|
+
(_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.replacePositions(posses);
|
|
23415
|
+
if (!posses.length) {
|
|
23416
|
+
this.applyRootRest(tileset);
|
|
23417
|
+
}
|
|
23418
|
+
}
|
|
23419
|
+
/*
|
|
23420
|
+
* The root as read at the scene's time, with any simulated record at that time laid over it.
|
|
23421
|
+
*/
|
|
23422
|
+
atClock(root) {
|
|
23423
|
+
return this.simulation && root
|
|
23424
|
+
? this.simulation.ApplyAt(root, Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime())
|
|
23425
|
+
: root;
|
|
23426
|
+
}
|
|
23427
|
+
/*
|
|
23428
|
+
* Stands the tileset where its root is outside history: the simulated root, else the root's own record.
|
|
23429
|
+
*/
|
|
23430
|
+
applyRootRest(tileset) {
|
|
23431
|
+
var _a;
|
|
23432
|
+
this.applyCoords(tileset, (_a = this.simulatedRootCoords()) !== null && _a !== void 0 ? _a : this.restCoords);
|
|
23433
|
+
}
|
|
23434
|
+
/*
|
|
23435
|
+
* Where a simulated root puts the tileset, or null; a patch only places it when it names a whole location.
|
|
23436
|
+
*/
|
|
23437
|
+
simulatedRootCoords() {
|
|
23438
|
+
var _a, _b;
|
|
23439
|
+
const simulation = this.rootId ? this.simulation : null;
|
|
23440
|
+
const root = (_a = simulation === null || simulation === void 0 ? void 0 : simulation.GetEntity(this.rootId)) !== null && _a !== void 0 ? _a : ((simulation === null || simulation === void 0 ? void 0 : simulation.HasBlob(this.rootId)) ? simulation.Overlay({ Bruce: { ID: this.rootId } }) : null);
|
|
23441
|
+
const location = (_b = root === null || root === void 0 ? void 0 : root.Bruce) === null || _b === void 0 ? void 0 : _b.Location;
|
|
23442
|
+
if ((location === null || location === void 0 ? void 0 : location.latitude) == null || (location === null || location === void 0 ? void 0 : location.longitude) == null) {
|
|
23443
|
+
return null;
|
|
23444
|
+
}
|
|
23445
|
+
const pos3d = Cesium.Cartesian3.fromDegrees(+location.longitude, +location.latitude, EnsureNumber(location.altitude, 0));
|
|
23446
|
+
const transform = root.Bruce.Transform;
|
|
23447
|
+
return coordsFromHistoricPos3d(this.cTileset, this.rootId, pos3d, EnsureNumber(transform === null || transform === void 0 ? void 0 : transform.heading, 0), transform === null || transform === void 0 ? void 0 : transform.pitch, transform === null || transform === void 0 ? void 0 : transform.roll);
|
|
23448
|
+
}
|
|
23449
|
+
viewerDateTimeDispose() {
|
|
23450
|
+
var _a, _b;
|
|
22491
23451
|
(_a = this.viewerDateTimeChangeRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
22492
23452
|
this.viewerDateTimeChangeRemoval = null;
|
|
23453
|
+
// Made before the first positions land, so it can outlive a removal that was never set.
|
|
23454
|
+
(_b = this.historicGatherer) === null || _b === void 0 ? void 0 : _b.Dispose();
|
|
23455
|
+
this.historicGatherer = null;
|
|
22493
23456
|
}
|
|
22494
23457
|
/**
|
|
22495
23458
|
* Updates the Tileset with latest coordinates.
|
|
@@ -23630,11 +24593,11 @@
|
|
|
23630
24593
|
this.viewMonitorRemoval = null;
|
|
23631
24594
|
this.renderQueue = [];
|
|
23632
24595
|
this.renderQueueInterval = null;
|
|
23633
|
-
this.reRenderState = new EntityReRenderMaintainState();
|
|
23634
24596
|
this.zoomControl = [];
|
|
23635
24597
|
this.queryLoadId = 0;
|
|
23636
24598
|
this.renderDataLabEntitiesChain = Promise.resolve();
|
|
23637
24599
|
const { viewer, item, apiGetter, monitor, visualsRegister } = params;
|
|
24600
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation);
|
|
23638
24601
|
this.viewer = viewer;
|
|
23639
24602
|
this.item = item;
|
|
23640
24603
|
this.apiGetter = apiGetter;
|
|
@@ -23731,7 +24694,8 @@
|
|
|
23731
24694
|
if (!((_a = data === null || data === void 0 ? void 0 : data.entities) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
23732
24695
|
return;
|
|
23733
24696
|
}
|
|
23734
|
-
|
|
24697
|
+
// The getter answers from the API, so a simulated Entity in its answer is swapped for its blob.
|
|
24698
|
+
this.distributeForRender(this.reRenderState.withSimulated(data.entities));
|
|
23735
24699
|
});
|
|
23736
24700
|
}
|
|
23737
24701
|
unsetGetter() {
|
|
@@ -23886,6 +24850,16 @@
|
|
|
23886
24850
|
this.doEntityCheck(entityIds);
|
|
23887
24851
|
}
|
|
23888
24852
|
}
|
|
24853
|
+
/**
|
|
24854
|
+
* Switches to another of the item's own styles, restyling what is drawn without re-creating it.
|
|
24855
|
+
*/
|
|
24856
|
+
SwapStyle(item) {
|
|
24857
|
+
if (this.disposed) {
|
|
24858
|
+
return;
|
|
24859
|
+
}
|
|
24860
|
+
this.item = item;
|
|
24861
|
+
this.UpdateSettings({ zoomControl: item.CameraZoomSettings });
|
|
24862
|
+
}
|
|
23889
24863
|
async doEntityCheck(ids, force = false) {
|
|
23890
24864
|
var _a, _b, _c, _d;
|
|
23891
24865
|
if (this.isRunningCheck) {
|
|
@@ -25478,6 +26452,7 @@
|
|
|
25478
26452
|
this.featurePropCache = new Map();
|
|
25479
26453
|
this.featurePropsChecked = 0;
|
|
25480
26454
|
const { viewer, register: visualsManager, getters: apiGetter, item, initQueue, monitor } = params;
|
|
26455
|
+
this.simulation = params.simulation;
|
|
25481
26456
|
this.monitor = monitor;
|
|
25482
26457
|
this.viewer = viewer;
|
|
25483
26458
|
this.getters = apiGetter;
|
|
@@ -25578,6 +26553,7 @@
|
|
|
25578
26553
|
if (Manager.NeedsStyler(this.item)) {
|
|
25579
26554
|
const api = this.getters.GetBruceApi();
|
|
25580
26555
|
this.styler.Init({
|
|
26556
|
+
simulation: this.simulation,
|
|
25581
26557
|
viewer: this.viewer,
|
|
25582
26558
|
api: api,
|
|
25583
26559
|
cTileset: this.cTileset,
|
|
@@ -25793,6 +26769,21 @@
|
|
|
25793
26769
|
}
|
|
25794
26770
|
}
|
|
25795
26771
|
}
|
|
26772
|
+
/**
|
|
26773
|
+
* Switches to another of the item's own styles, restyling the loaded tileset without reloading it.
|
|
26774
|
+
*/
|
|
26775
|
+
SwapStyle(item) {
|
|
26776
|
+
if (this.disposed) {
|
|
26777
|
+
return;
|
|
26778
|
+
}
|
|
26779
|
+
this.item = item;
|
|
26780
|
+
if (Manager.NeedsStyler(item)) {
|
|
26781
|
+
this.styler.UpdateStyleMapping({
|
|
26782
|
+
styleMapping: [],
|
|
26783
|
+
fallbackStyleId: item.styleId
|
|
26784
|
+
});
|
|
26785
|
+
}
|
|
26786
|
+
}
|
|
25796
26787
|
Dispose() {
|
|
25797
26788
|
var _a;
|
|
25798
26789
|
if (this.disposed) {
|
|
@@ -25935,6 +26926,7 @@
|
|
|
25935
26926
|
const needsStyler = Manager.NeedsStyler(this.item);
|
|
25936
26927
|
if (needsStyler) {
|
|
25937
26928
|
this.styler.Init({
|
|
26929
|
+
simulation: this.simulation,
|
|
25938
26930
|
viewer: this.viewer,
|
|
25939
26931
|
api: this.getters.GetBruceApi(),
|
|
25940
26932
|
cTileset: this.cTileset,
|
|
@@ -26619,6 +27611,7 @@
|
|
|
26619
27611
|
// LCC object if we're using XGrids to render LCC data.
|
|
26620
27612
|
this.lccObject = null;
|
|
26621
27613
|
this.viewer = params.viewer;
|
|
27614
|
+
this.simulation = params.simulation;
|
|
26622
27615
|
this.getters = params.getters;
|
|
26623
27616
|
this.visualsManager = params.register;
|
|
26624
27617
|
// We modify the object due to a lot of backwards compatibility.
|
|
@@ -26853,6 +27846,7 @@
|
|
|
26853
27846
|
this.item.Type == BModels.MenuItem.EType.IonTileset) {
|
|
26854
27847
|
const api = this.getters.GetBruceApi();
|
|
26855
27848
|
this.styler.Init({
|
|
27849
|
+
simulation: this.simulation,
|
|
26856
27850
|
viewer: this.viewer,
|
|
26857
27851
|
api: api,
|
|
26858
27852
|
cTileset: this.cTileset,
|
|
@@ -27039,6 +28033,23 @@
|
|
|
27039
28033
|
this.viewer.zoomTo(this.cTileset, new Cesium.HeadingPitchRange(0.0, -0.5, this.cTileset.boundingSphere.radius / 4.0));
|
|
27040
28034
|
}
|
|
27041
28035
|
}
|
|
28036
|
+
/**
|
|
28037
|
+
* Switches to another of the item's own styles, restyling the loaded tileset without reloading it.
|
|
28038
|
+
*/
|
|
28039
|
+
SwapStyle(item) {
|
|
28040
|
+
var _a;
|
|
28041
|
+
if (this.disposed) {
|
|
28042
|
+
return;
|
|
28043
|
+
}
|
|
28044
|
+
// Copied for the same reason the constructor copies it.
|
|
28045
|
+
this.item = JSON.parse(JSON.stringify(item));
|
|
28046
|
+
if (this.item.ApplyStyles || this.item.Type == BModels.MenuItem.EType.IonTileset) {
|
|
28047
|
+
this.styler.UpdateStyleMapping({
|
|
28048
|
+
styleMapping: (_a = this.item.StyleMapping) !== null && _a !== void 0 ? _a : [],
|
|
28049
|
+
fallbackStyleId: this.item.styleId
|
|
28050
|
+
});
|
|
28051
|
+
}
|
|
28052
|
+
}
|
|
27042
28053
|
Dispose() {
|
|
27043
28054
|
if (this.disposed) {
|
|
27044
28055
|
return;
|
|
@@ -27193,14 +28204,32 @@
|
|
|
27193
28204
|
}
|
|
27194
28205
|
;
|
|
27195
28206
|
constructor(params) {
|
|
28207
|
+
var _a, _b;
|
|
27196
28208
|
// If true, this menu item is disposed and should not be used.
|
|
27197
28209
|
// Any rendering will be ignored.
|
|
27198
28210
|
this.disposed = false;
|
|
28211
|
+
this.simulationRemoval = null;
|
|
28212
|
+
this.FollowsSimulation = true;
|
|
27199
28213
|
const { apiGetter, item, register, viewer } = params;
|
|
27200
28214
|
this.apiGetter = apiGetter;
|
|
27201
28215
|
this.item = item;
|
|
27202
28216
|
this.register = register;
|
|
27203
28217
|
this.viewer = viewer;
|
|
28218
|
+
this.simulation = params.simulation;
|
|
28219
|
+
// Ends are not this item's own Entities, so it watches the store itself rather than wait to be asked.
|
|
28220
|
+
this.simulationRemoval = (_b = (_a = this.simulation) === null || _a === void 0 ? void 0 : _a.OnChanged.Subscribe((change) => {
|
|
28221
|
+
if (this.disposed) {
|
|
28222
|
+
return;
|
|
28223
|
+
}
|
|
28224
|
+
const relations = RelationRenderEngine.TakeRelationsTouching({
|
|
28225
|
+
visualRegister: this.register,
|
|
28226
|
+
menuItemId: this.item.id,
|
|
28227
|
+
entityIds: change.entityIds
|
|
28228
|
+
});
|
|
28229
|
+
if (relations.length) {
|
|
28230
|
+
this.onGetterUpdate(relations);
|
|
28231
|
+
}
|
|
28232
|
+
})) !== null && _b !== void 0 ? _b : null;
|
|
27204
28233
|
}
|
|
27205
28234
|
/**
|
|
27206
28235
|
* Starts rendering the menu item.
|
|
@@ -27269,10 +28298,13 @@
|
|
|
27269
28298
|
return items;
|
|
27270
28299
|
}
|
|
27271
28300
|
Dispose() {
|
|
28301
|
+
var _a;
|
|
27272
28302
|
if (this.disposed) {
|
|
27273
28303
|
return;
|
|
27274
28304
|
}
|
|
27275
28305
|
this.disposed = true;
|
|
28306
|
+
(_a = this.simulationRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
28307
|
+
this.simulationRemoval = null;
|
|
27276
28308
|
this.register.RemoveRegos({
|
|
27277
28309
|
menuItemId: this.item.id
|
|
27278
28310
|
});
|
|
@@ -27511,7 +28543,8 @@
|
|
|
27511
28543
|
menuItemId: this.item.id,
|
|
27512
28544
|
relations: relations,
|
|
27513
28545
|
viewer: this.viewer,
|
|
27514
|
-
visualRegister: this.register
|
|
28546
|
+
visualRegister: this.register,
|
|
28547
|
+
simulation: this.simulation
|
|
27515
28548
|
});
|
|
27516
28549
|
if (this.disposed) {
|
|
27517
28550
|
this.register.RemoveRegos({
|
|
@@ -27793,9 +28826,12 @@
|
|
|
27793
28826
|
}
|
|
27794
28827
|
;
|
|
27795
28828
|
constructor(params) {
|
|
28829
|
+
var _a, _b;
|
|
27796
28830
|
// If true, this menu item is disposed and should not be used.
|
|
27797
28831
|
// Any rendering will be ignored.
|
|
27798
28832
|
this.disposed = false;
|
|
28833
|
+
this.simulationRemoval = null;
|
|
28834
|
+
this.FollowsSimulation = true;
|
|
27799
28835
|
// Record of the currently drawn entity IDs.
|
|
27800
28836
|
// This is to avoid re-queueing already drawn entities when Init is called multiple times.
|
|
27801
28837
|
this.drawnIds = [];
|
|
@@ -27804,6 +28840,21 @@
|
|
|
27804
28840
|
this.item = item;
|
|
27805
28841
|
this.register = register;
|
|
27806
28842
|
this.viewer = viewer;
|
|
28843
|
+
this.simulation = params.simulation;
|
|
28844
|
+
// Ends are not this item's own Entities, so it watches the store itself rather than wait to be asked.
|
|
28845
|
+
this.simulationRemoval = (_b = (_a = this.simulation) === null || _a === void 0 ? void 0 : _a.OnChanged.Subscribe((change) => {
|
|
28846
|
+
if (this.disposed) {
|
|
28847
|
+
return;
|
|
28848
|
+
}
|
|
28849
|
+
const relations = RelationRenderEngine.TakeRelationsTouching({
|
|
28850
|
+
visualRegister: this.register,
|
|
28851
|
+
menuItemId: this.item.id,
|
|
28852
|
+
entityIds: change.entityIds
|
|
28853
|
+
});
|
|
28854
|
+
if (relations.length) {
|
|
28855
|
+
this.onGetterUpdate(relations);
|
|
28856
|
+
}
|
|
28857
|
+
})) !== null && _b !== void 0 ? _b : null;
|
|
27807
28858
|
}
|
|
27808
28859
|
/**
|
|
27809
28860
|
* Starts rendering the menu item.
|
|
@@ -27846,10 +28897,13 @@
|
|
|
27846
28897
|
this.drawnIds = [].concat(entityIds);
|
|
27847
28898
|
}
|
|
27848
28899
|
Dispose() {
|
|
28900
|
+
var _a;
|
|
27849
28901
|
if (this.disposed) {
|
|
27850
28902
|
return;
|
|
27851
28903
|
}
|
|
27852
28904
|
this.disposed = true;
|
|
28905
|
+
(_a = this.simulationRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
28906
|
+
this.simulationRemoval = null;
|
|
27853
28907
|
this.register.RemoveRegos({
|
|
27854
28908
|
menuItemId: this.item.id
|
|
27855
28909
|
});
|
|
@@ -28010,7 +29064,8 @@
|
|
|
28010
29064
|
menuItemId: this.item.id,
|
|
28011
29065
|
relations: relations,
|
|
28012
29066
|
viewer: this.viewer,
|
|
28013
|
-
visualRegister: this.register
|
|
29067
|
+
visualRegister: this.register,
|
|
29068
|
+
simulation: this.simulation
|
|
28014
29069
|
});
|
|
28015
29070
|
if (this.disposed) {
|
|
28016
29071
|
this.register.RemoveRegos({
|
|
@@ -29235,6 +30290,55 @@
|
|
|
29235
30290
|
get ModelSpace() {
|
|
29236
30291
|
return this.modelSpace;
|
|
29237
30292
|
}
|
|
30293
|
+
/**
|
|
30294
|
+
* Every node of the Assembly read so far, so a caller can work out motion in the Assembly's own terms.
|
|
30295
|
+
* @param timeMs the scene time for each node's current pose. Default: the clock's.
|
|
30296
|
+
* @returns per node its pose within its parent from the API (local) and as drawn at the time (current).
|
|
30297
|
+
*/
|
|
30298
|
+
GetNodes(timeMs) {
|
|
30299
|
+
const at = timeMs !== null && timeMs !== void 0 ? timeMs : Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime();
|
|
30300
|
+
const rowsOf = (m) => m ? [0, 1, 2, 3].map(row => [0, 1, 2, 3].map(column => m[(column * 4) + row])) : null;
|
|
30301
|
+
return Object.values(this.hierarchyNodeByEntityId || {}).map(node => {
|
|
30302
|
+
var _a, _b, _c;
|
|
30303
|
+
const entity = (_a = this.apiEntities.get(node.entityId)) !== null && _a !== void 0 ? _a : null;
|
|
30304
|
+
const rows = (_b = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _b === void 0 ? void 0 : _b.AssemblyPosition;
|
|
30305
|
+
return {
|
|
30306
|
+
entityId: node.entityId,
|
|
30307
|
+
name: node.name,
|
|
30308
|
+
parentId: (_c = node.parentId) !== null && _c !== void 0 ? _c : null,
|
|
30309
|
+
local: Manager.MatrixFromRows(rows) ? rows : null,
|
|
30310
|
+
current: rowsOf(this.localAt(node.entityId, at)),
|
|
30311
|
+
entity
|
|
30312
|
+
};
|
|
30313
|
+
});
|
|
30314
|
+
}
|
|
30315
|
+
/**
|
|
30316
|
+
* The root's world frame at a time, history and simulation included, eg. to follow or frame the Assembly.
|
|
30317
|
+
* @param timeMs the scene time. Default: the clock's.
|
|
30318
|
+
* @returns null until the root has been read.
|
|
30319
|
+
*/
|
|
30320
|
+
GetRootFrame(timeMs) {
|
|
30321
|
+
const root = this.rootAt(timeMs !== null && timeMs !== void 0 ? timeMs : Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime());
|
|
30322
|
+
return root ? Manager.rootFrame(root.pos3d, root.heading, root.pitch, root.roll) : null;
|
|
30323
|
+
}
|
|
30324
|
+
/**
|
|
30325
|
+
* A part's world frame at a time as its records and its parents place it, size included.
|
|
30326
|
+
* @param entityId the part.
|
|
30327
|
+
* @param timeMs the scene time. Default: the clock's.
|
|
30328
|
+
* @returns null until the root and the part have been read.
|
|
30329
|
+
*/
|
|
30330
|
+
GetPartFrame(entityId, timeMs) {
|
|
30331
|
+
const at = timeMs !== null && timeMs !== void 0 ? timeMs : Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime();
|
|
30332
|
+
const rootFrame = this.GetRootFrame(at);
|
|
30333
|
+
const world = entityId === this.rootId ? Cesium.Matrix4.IDENTITY : this.composeWorld(entityId, at);
|
|
30334
|
+
if (!rootFrame || !world) {
|
|
30335
|
+
return null;
|
|
30336
|
+
}
|
|
30337
|
+
// Where the part is drawn, so its own ground offset is part of its frame.
|
|
30338
|
+
const ground = this.groundOffsets.get(entityId);
|
|
30339
|
+
const placed = ground ? Cesium.Matrix4.multiply(Cesium.Matrix4.fromTranslation(ground), world, new Cesium.Matrix4()) : world;
|
|
30340
|
+
return Cesium.Matrix4.multiply(rootFrame, placed, new Cesium.Matrix4());
|
|
30341
|
+
}
|
|
29238
30342
|
constructor(params) {
|
|
29239
30343
|
this.disposed = false;
|
|
29240
30344
|
// Cache of the hierarchy so that our scene-tree can reference it.
|
|
@@ -29244,19 +30348,41 @@
|
|
|
29244
30348
|
this.hierarchyNodeByEntityId = null;
|
|
29245
30349
|
this.modelSpace = false;
|
|
29246
30350
|
this.rootId = null;
|
|
29247
|
-
// Where the root sits
|
|
29248
|
-
// Every child is placed through this, so a root move is one value changing rather than a refetch of the whole Assembly.
|
|
30351
|
+
// Where the root sits outside its history, and which way it faces in degrees. Children are placed through it.
|
|
29249
30352
|
this.rootPos3d = null;
|
|
29250
30353
|
this.rootHeading = 0;
|
|
29251
|
-
|
|
30354
|
+
this.rootPitch = 0;
|
|
30355
|
+
this.rootRoll = 0;
|
|
30356
|
+
// The root's recorded positions and attitudes, oldest first, kept apart since a record may name only one.
|
|
30357
|
+
this.rootSeries = [];
|
|
30358
|
+
this.rootAttitude = [];
|
|
30359
|
+
// Every placement worked out for the scene time last asked about, shared by all parts drawn at it.
|
|
30360
|
+
this.pose = null;
|
|
30361
|
+
// Entity ID -> what was drawn for it.
|
|
29252
30362
|
this.children = new Map();
|
|
30363
|
+
// Entity ID -> its live position within its parent, for every node fetched including undrawn groups.
|
|
30364
|
+
this.localPositions = new Map();
|
|
30365
|
+
// Entity ID -> how much higher the ground under it is than under the root, along the root's up.
|
|
30366
|
+
this.groundOffsets = new Map();
|
|
30367
|
+
// Entity ID -> its recorded poses within its parent, oldest first.
|
|
30368
|
+
this.jointSeries = new Map();
|
|
30369
|
+
// Drawn children that can move with the clock, so a tick places only these and not the whole Assembly.
|
|
30370
|
+
this.animatedIds = new Set();
|
|
29253
30371
|
// The trail through the root's own movement, which describes the whole Assembly.
|
|
29254
|
-
this.
|
|
30372
|
+
this.trail = null;
|
|
30373
|
+
this.simulationRemoval = null;
|
|
30374
|
+
this.FollowsSimulation = true;
|
|
30375
|
+
// Entity ID -> the record the API gave, so a cleared simulation falls back to it without a refetch.
|
|
30376
|
+
this.apiEntities = new Map();
|
|
30377
|
+
// Re-reads history and re-applies it, eg. after simulated records change. Set while the clock is followed.
|
|
30378
|
+
this.regather = null;
|
|
30379
|
+
this.followingClock = false;
|
|
29255
30380
|
// Callback to dispose the link between scene time and the root's historic position.
|
|
29256
30381
|
this.viewerDateTimeChangeRemoval = null;
|
|
29257
30382
|
this.historicGatherer = null;
|
|
29258
30383
|
this.historicAnimation = null;
|
|
29259
30384
|
const { viewer, register: visualsManager, getters, item } = params;
|
|
30385
|
+
this.simulation = params.simulation;
|
|
29260
30386
|
this.viewer = viewer;
|
|
29261
30387
|
this.getters = getters;
|
|
29262
30388
|
this.item = item;
|
|
@@ -29280,10 +30406,10 @@
|
|
|
29280
30406
|
return exports.EntityRenderEngine.GetHeightRef((_b = (_a = item === null || item === void 0 ? void 0 : item.Style) === null || _a === void 0 ? void 0 : _a.Settings) === null || _b === void 0 ? void 0 : _b["modelStyle"]);
|
|
29281
30407
|
}
|
|
29282
30408
|
/*
|
|
29283
|
-
* The root's frame: east-north-up at its position, turned by its heading.
|
|
30409
|
+
* The root's frame: east-north-up at its position, turned by its heading, pitch and roll.
|
|
29284
30410
|
*/
|
|
29285
|
-
static rootFrame(rootPos3d, headingDegrees) {
|
|
29286
|
-
const hpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(headingDegrees || 0), 0, 0);
|
|
30411
|
+
static rootFrame(rootPos3d, headingDegrees, pitchDegrees = 0, rollDegrees = 0) {
|
|
30412
|
+
const hpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(headingDegrees || 0), Cesium.Math.toRadians(pitchDegrees || 0), Cesium.Math.toRadians(rollDegrees || 0));
|
|
29287
30413
|
return Cesium.Transforms.headingPitchRollToFixedFrame(rootPos3d, hpr);
|
|
29288
30414
|
}
|
|
29289
30415
|
/**
|
|
@@ -29306,28 +30432,553 @@
|
|
|
29306
30432
|
return Cesium.Matrix4.multiplyByPoint(Manager.rootFrame(rootPos3d, headingDegrees), offset, new Cesium.Cartesian3());
|
|
29307
30433
|
}
|
|
29308
30434
|
/**
|
|
29309
|
-
* Moves the
|
|
30435
|
+
* Moves where the root sits outside its history, without refetching children; recorded poses still win.
|
|
29310
30436
|
* @param params
|
|
29311
30437
|
*/
|
|
29312
30438
|
ApplyRootPosition(params) {
|
|
29313
|
-
var _a, _b;
|
|
30439
|
+
var _a, _b, _c, _d, _e, _f;
|
|
29314
30440
|
if (this.disposed || !(params === null || params === void 0 ? void 0 : params.pos3d)) {
|
|
29315
30441
|
return;
|
|
29316
30442
|
}
|
|
29317
30443
|
this.rootPos3d = params.pos3d;
|
|
29318
30444
|
this.rootHeading = (_b = (_a = params.heading) !== null && _a !== void 0 ? _a : this.rootHeading) !== null && _b !== void 0 ? _b : 0;
|
|
30445
|
+
this.rootPitch = (_d = (_c = params.pitch) !== null && _c !== void 0 ? _c : this.rootPitch) !== null && _d !== void 0 ? _d : 0;
|
|
30446
|
+
this.rootRoll = (_f = (_e = params.roll) !== null && _e !== void 0 ? _e : this.rootRoll) !== null && _f !== void 0 ? _f : 0;
|
|
30447
|
+
this.repose(true);
|
|
30448
|
+
}
|
|
30449
|
+
/*
|
|
30450
|
+
* Drops every placement worked out so far, after the root or a joint's records change.
|
|
30451
|
+
* @param everyChild re-place the parts that cannot move as well, because where they rest has changed.
|
|
30452
|
+
*/
|
|
30453
|
+
repose(everyChild = false) {
|
|
30454
|
+
this.pose = null;
|
|
29319
30455
|
for (const child of this.children.values()) {
|
|
29320
|
-
|
|
29321
|
-
|
|
30456
|
+
if (everyChild || Boolean(child.moving) != this.canMove(child.entityId)) {
|
|
30457
|
+
this.bindPlacement(child);
|
|
30458
|
+
}
|
|
30459
|
+
}
|
|
30460
|
+
this.viewer.scene.requestRender();
|
|
30461
|
+
}
|
|
30462
|
+
/*
|
|
30463
|
+
* Takes a node's pose outside its history from its record, and for the root where it stands and faces.
|
|
30464
|
+
*/
|
|
30465
|
+
absorbNode(entity) {
|
|
30466
|
+
var _a, _b, _c, _d, _e;
|
|
30467
|
+
const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
30468
|
+
const local = Manager.MatrixFromRows((_b = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _b === void 0 ? void 0 : _b.AssemblyPosition);
|
|
30469
|
+
if (local) {
|
|
30470
|
+
this.localPositions.set(id, local);
|
|
30471
|
+
}
|
|
30472
|
+
// Anchored on the root, which is usually never drawn; everything under it is placed from the hierarchy.
|
|
30473
|
+
if (id === this.rootId || (!this.rootId && !this.rootPos3d)) {
|
|
30474
|
+
const rootPos3d = exports.EntityUtils.GetPos({
|
|
30475
|
+
viewer: this.viewer,
|
|
30476
|
+
entity,
|
|
30477
|
+
recordHeightRef: Manager.GetRecordHeightRef(this.item),
|
|
30478
|
+
returnHeightRef: Cesium.HeightReference.NONE,
|
|
30479
|
+
allowRendered: false
|
|
30480
|
+
});
|
|
30481
|
+
if (rootPos3d) {
|
|
30482
|
+
this.rootPos3d = rootPos3d;
|
|
30483
|
+
this.rootHeading = EnsureNumber((_c = entity.Bruce.Transform) === null || _c === void 0 ? void 0 : _c.heading, 0);
|
|
30484
|
+
this.rootPitch = EnsureNumber((_d = entity.Bruce.Transform) === null || _d === void 0 ? void 0 : _d.pitch, 0);
|
|
30485
|
+
this.rootRoll = EnsureNumber((_e = entity.Bruce.Transform) === null || _e === void 0 ? void 0 : _e.roll, 0);
|
|
30486
|
+
}
|
|
30487
|
+
}
|
|
30488
|
+
}
|
|
30489
|
+
/*
|
|
30490
|
+
* A node's record with its simulation laid over it, keeping what a stand-in leaves out, eg. its model.
|
|
30491
|
+
*/
|
|
30492
|
+
withSimulation(entity) {
|
|
30493
|
+
var _a;
|
|
30494
|
+
const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
30495
|
+
if (!this.simulation || !id) {
|
|
30496
|
+
return entity;
|
|
30497
|
+
}
|
|
30498
|
+
const standIn = this.simulation.GetEntity(id);
|
|
30499
|
+
if (!standIn) {
|
|
30500
|
+
return this.simulation.Overlay(entity);
|
|
30501
|
+
}
|
|
30502
|
+
return { ...entity, ...standIn, Bruce: { ...entity.Bruce, ...standIn.Bruce } };
|
|
30503
|
+
}
|
|
30504
|
+
/*
|
|
30505
|
+
* Brings the Assembly in line with a change to what is simulated.
|
|
30506
|
+
*/
|
|
30507
|
+
onSimulationChanged(change) {
|
|
30508
|
+
var _a;
|
|
30509
|
+
if (this.disposed || !this.hierarchyNodeByEntityId) {
|
|
30510
|
+
return;
|
|
30511
|
+
}
|
|
30512
|
+
const ids = change.entityIds.filter(id => this.hierarchyNodeByEntityId[id]);
|
|
30513
|
+
if (!ids.length) {
|
|
30514
|
+
return;
|
|
30515
|
+
}
|
|
30516
|
+
if (change.entities) {
|
|
30517
|
+
for (const id of ids) {
|
|
30518
|
+
const api = this.apiEntities.get(id);
|
|
30519
|
+
if (!api) {
|
|
30520
|
+
// Not loaded yet, and it will be drawn from its simulation when it is.
|
|
30521
|
+
continue;
|
|
30522
|
+
}
|
|
30523
|
+
const entity = this.withSimulation(api);
|
|
30524
|
+
// A cleared blob leaves the node's own matrix where the API has none, so it is reset.
|
|
30525
|
+
if (!((_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.AssemblyPosition)) {
|
|
30526
|
+
this.localPositions.delete(id);
|
|
30527
|
+
}
|
|
30528
|
+
this.absorbNode(entity);
|
|
30529
|
+
const child = this.children.get(id);
|
|
30530
|
+
if (child) {
|
|
30531
|
+
child.entity = entity;
|
|
30532
|
+
}
|
|
30533
|
+
}
|
|
30534
|
+
this.repose(true);
|
|
30535
|
+
}
|
|
30536
|
+
if (change.records) {
|
|
30537
|
+
if (this.regather) {
|
|
30538
|
+
this.regather(true);
|
|
30539
|
+
}
|
|
30540
|
+
else {
|
|
30541
|
+
this.viewerDateTimeSub();
|
|
30542
|
+
}
|
|
30543
|
+
}
|
|
30544
|
+
}
|
|
30545
|
+
/*
|
|
30546
|
+
* Nodes of this Assembly with simulated history.
|
|
30547
|
+
*/
|
|
30548
|
+
simulatedNodeIds() {
|
|
30549
|
+
if (!this.simulation || !this.hierarchyNodeByEntityId) {
|
|
30550
|
+
return [];
|
|
30551
|
+
}
|
|
30552
|
+
return this.simulation.GetRecordEntityIds().filter(id => this.hierarchyNodeByEntityId[id]);
|
|
30553
|
+
}
|
|
30554
|
+
/*
|
|
30555
|
+
* Whether a node can move with time: the root has history, or it or an ancestor does.
|
|
30556
|
+
*/
|
|
30557
|
+
canMove(entityId) {
|
|
30558
|
+
return this.rootSeries.length > 0 || this.rootAttitude.length > 0 || this.animatedIds.has(entityId);
|
|
30559
|
+
}
|
|
30560
|
+
/*
|
|
30561
|
+
* Gives a child its position and orientation, as functions of scene time only when it can move.
|
|
30562
|
+
*/
|
|
30563
|
+
bindPlacement(child) {
|
|
30564
|
+
const id = child.entityId;
|
|
30565
|
+
const moving = this.canMove(id);
|
|
30566
|
+
if (moving) {
|
|
30567
|
+
if (!child.moving) {
|
|
30568
|
+
child.cEntity.position = new Cesium.CallbackProperty((time, result) => { var _a; return Manager.cloneOrUndefined((_a = this.placementAt(id, time)) === null || _a === void 0 ? void 0 : _a.pos3d, result); }, false);
|
|
30569
|
+
child.cEntity.orientation = new Cesium.CallbackProperty((time, result) => {
|
|
30570
|
+
var _a;
|
|
30571
|
+
const orient = (_a = this.placementAt(id, time)) === null || _a === void 0 ? void 0 : _a.orient;
|
|
30572
|
+
return orient ? Cesium.Quaternion.clone(orient, result) : undefined;
|
|
30573
|
+
}, false);
|
|
30574
|
+
child.cEntity.model.scale = new Cesium.CallbackProperty((time) => { var _a, _b; return (_b = (_a = this.placementAt(id, time)) === null || _a === void 0 ? void 0 : _a.scale) !== null && _b !== void 0 ? _b : 1; }, false);
|
|
30575
|
+
}
|
|
30576
|
+
}
|
|
30577
|
+
else {
|
|
30578
|
+
const placed = this.placementAt(id, this.viewer.clock.currentTime);
|
|
30579
|
+
if (placed) {
|
|
30580
|
+
child.cEntity.position = new Cesium.ConstantPositionProperty(placed.pos3d);
|
|
30581
|
+
if (placed.orient) {
|
|
30582
|
+
child.cEntity.orientation = new Cesium.ConstantProperty(placed.orient);
|
|
30583
|
+
}
|
|
30584
|
+
child.cEntity.model.scale = new Cesium.ConstantProperty(placed.scale);
|
|
30585
|
+
}
|
|
30586
|
+
}
|
|
30587
|
+
if (Boolean(child.moving) != moving) {
|
|
30588
|
+
child.moving = moving;
|
|
30589
|
+
this.visualsManager.SetMoving({ moving, entityIds: [id], menuItemId: this.item.id });
|
|
30590
|
+
}
|
|
30591
|
+
}
|
|
30592
|
+
/*
|
|
30593
|
+
* The one scale a model takes from its part's composed matrix, the largest when they are uneven.
|
|
30594
|
+
*/
|
|
30595
|
+
static uniformScale(world) {
|
|
30596
|
+
return Cesium.Cartesian3.maximumComponent(Cesium.Matrix4.getScale(world, new Cesium.Cartesian3()));
|
|
30597
|
+
}
|
|
30598
|
+
static cloneOrUndefined(pos3d, result) {
|
|
30599
|
+
return pos3d ? Cesium.Cartesian3.clone(pos3d, result) : undefined;
|
|
30600
|
+
}
|
|
30601
|
+
/*
|
|
30602
|
+
* Where a node draws at a scene time, from one composition shared by every part asked about at that time.
|
|
30603
|
+
*/
|
|
30604
|
+
placementAt(entityId, time) {
|
|
30605
|
+
if (this.disposed || !time) {
|
|
30606
|
+
return null;
|
|
30607
|
+
}
|
|
30608
|
+
const timeMs = Cesium.JulianDate.toDate(time).getTime();
|
|
30609
|
+
if (!this.pose || this.pose.timeMs !== timeMs) {
|
|
30610
|
+
const root = this.rootAt(timeMs);
|
|
30611
|
+
this.pose = {
|
|
30612
|
+
timeMs,
|
|
30613
|
+
rootFrame: root ? Manager.rootFrame(root.pos3d, root.heading, root.pitch, root.roll) : null,
|
|
30614
|
+
worlds: new Map(),
|
|
30615
|
+
placements: new Map()
|
|
30616
|
+
};
|
|
30617
|
+
}
|
|
30618
|
+
const pose = this.pose;
|
|
30619
|
+
if (!pose.rootFrame) {
|
|
30620
|
+
return null;
|
|
30621
|
+
}
|
|
30622
|
+
let placed = pose.placements.get(entityId);
|
|
30623
|
+
if (!placed) {
|
|
30624
|
+
const world = this.composeWorld(entityId, timeMs, pose.worlds);
|
|
30625
|
+
const offset = world
|
|
30626
|
+
? Cesium.Matrix4.getTranslation(world, new Cesium.Cartesian3())
|
|
30627
|
+
: new Cesium.Cartesian3(0, 0, 0);
|
|
30628
|
+
const ground = this.groundOffsets.get(entityId);
|
|
30629
|
+
if (ground) {
|
|
30630
|
+
Cesium.Cartesian3.add(offset, ground, offset);
|
|
30631
|
+
}
|
|
30632
|
+
placed = {
|
|
30633
|
+
pos3d: Cesium.Matrix4.multiplyByPoint(pose.rootFrame, offset, new Cesium.Cartesian3()),
|
|
30634
|
+
// Without a matrix, eg. the root itself, there is no orientation of its own to apply.
|
|
30635
|
+
orient: world ? exports.EntityUtils.GetAssemblyOrientationInFrame(pose.rootFrame, world) : null,
|
|
30636
|
+
scale: world ? Manager.uniformScale(world) : 1
|
|
30637
|
+
};
|
|
30638
|
+
pose.placements.set(entityId, placed);
|
|
30639
|
+
}
|
|
30640
|
+
return placed;
|
|
30641
|
+
}
|
|
30642
|
+
/*
|
|
30643
|
+
* The root's pose at a time, position and attitude each following their own records as a joint's do.
|
|
30644
|
+
*/
|
|
30645
|
+
rootAt(timeMs) {
|
|
30646
|
+
const pos3d = this.rootPositionAt(timeMs);
|
|
30647
|
+
if (!pos3d) {
|
|
30648
|
+
return null;
|
|
30649
|
+
}
|
|
30650
|
+
const live = { heading: this.rootHeading, pitch: this.rootPitch, roll: this.rootRoll };
|
|
30651
|
+
const series = this.rootAttitude;
|
|
30652
|
+
if (!series.length || timeMs < series[0].timeMs) {
|
|
30653
|
+
return { pos3d, ...live };
|
|
30654
|
+
}
|
|
30655
|
+
let i = 0;
|
|
30656
|
+
while (i < series.length - 1 && series[i + 1].timeMs <= timeMs) {
|
|
30657
|
+
i++;
|
|
30658
|
+
}
|
|
30659
|
+
const a = series[i];
|
|
30660
|
+
const b = series[i + 1];
|
|
30661
|
+
const t = b ? (timeMs - a.timeMs) / (b.timeMs - a.timeMs) : 0;
|
|
30662
|
+
const turn = (from, to, fallback) => {
|
|
30663
|
+
var _a, _b, _c;
|
|
30664
|
+
const x = (_a = from !== null && from !== void 0 ? from : fallback) !== null && _a !== void 0 ? _a : 0;
|
|
30665
|
+
const y = (_c = (_b = (b ? to : from)) !== null && _b !== void 0 ? _b : fallback) !== null && _c !== void 0 ? _c : 0;
|
|
30666
|
+
// The short way round, so 350 to 10 degrees turns through north rather than all the way back.
|
|
30667
|
+
return x + (Cesium.Math.negativePiToPi(Cesium.Math.toRadians(y - x)) * 180 / Math.PI) * t;
|
|
30668
|
+
};
|
|
30669
|
+
return {
|
|
30670
|
+
pos3d,
|
|
30671
|
+
heading: turn(a.heading, b === null || b === void 0 ? void 0 : b.heading, live.heading),
|
|
30672
|
+
pitch: turn(a.pitch, b === null || b === void 0 ? void 0 : b.pitch, live.pitch),
|
|
30673
|
+
roll: turn(a.roll, b === null || b === void 0 ? void 0 : b.roll, live.roll)
|
|
30674
|
+
};
|
|
30675
|
+
}
|
|
30676
|
+
/*
|
|
30677
|
+
* Where the root is at a time, from its recorded positions.
|
|
30678
|
+
*/
|
|
30679
|
+
rootPositionAt(timeMs) {
|
|
30680
|
+
const series = this.rootSeries;
|
|
30681
|
+
if (!series.length || timeMs < series[0].timeMs) {
|
|
30682
|
+
return this.rootPos3d;
|
|
30683
|
+
}
|
|
30684
|
+
let i = 0;
|
|
30685
|
+
while (i < series.length - 1 && series[i + 1].timeMs <= timeMs) {
|
|
30686
|
+
i++;
|
|
30687
|
+
}
|
|
30688
|
+
const a = series[i];
|
|
30689
|
+
const b = series[i + 1];
|
|
30690
|
+
if (!b) {
|
|
30691
|
+
return a.pos3d;
|
|
30692
|
+
}
|
|
30693
|
+
const t = (timeMs - a.timeMs) / (b.timeMs - a.timeMs);
|
|
30694
|
+
// A straight line between orbit samples cuts up to a kilometre inside the path, so it is lifted back out.
|
|
30695
|
+
const chord = Cesium.Cartesian3.lerp(a.pos3d, b.pos3d, t, new Cesium.Cartesian3());
|
|
30696
|
+
const carto = Cesium.Cartographic.fromCartesian(chord);
|
|
30697
|
+
return carto
|
|
30698
|
+
? Cesium.Cartesian3.fromRadians(carto.longitude, carto.latitude, Cesium.Math.lerp(a.height, b.height, t))
|
|
30699
|
+
: chord;
|
|
30700
|
+
}
|
|
30701
|
+
/*
|
|
30702
|
+
* Takes the root's records into its series.
|
|
30703
|
+
* @param replace the records are everything held for the root, so the series becomes exactly them.
|
|
30704
|
+
* @returns whether the series changed.
|
|
30705
|
+
*/
|
|
30706
|
+
absorbRootRecords(posses, replace) {
|
|
30707
|
+
if (!(posses === null || posses === void 0 ? void 0 : posses.length) && !(replace && this.rootSeries.length)) {
|
|
30708
|
+
return false;
|
|
30709
|
+
}
|
|
30710
|
+
const byTime = new Map(replace ? [] : this.rootSeries.map(k => [k.timeMs, k]));
|
|
30711
|
+
for (const pos of posses) {
|
|
30712
|
+
const carto = Cesium.Cartographic.fromCartesian(pos.pos3d);
|
|
30713
|
+
if (!carto) {
|
|
29322
30714
|
continue;
|
|
29323
30715
|
}
|
|
29324
|
-
|
|
29325
|
-
|
|
29326
|
-
|
|
29327
|
-
|
|
30716
|
+
byTime.set(pos.dateTime.getTime(), {
|
|
30717
|
+
timeMs: pos.dateTime.getTime(),
|
|
30718
|
+
pos3d: pos.pos3d,
|
|
30719
|
+
height: carto.height
|
|
30720
|
+
});
|
|
30721
|
+
}
|
|
30722
|
+
const series = Array.from(byTime.values()).sort((x, y) => x.timeMs - y.timeMs);
|
|
30723
|
+
const changed = (series.length !== this.rootSeries.length ||
|
|
30724
|
+
series.some((k, i) => !Cesium.Cartesian3.equals(k.pos3d, this.rootSeries[i].pos3d)));
|
|
30725
|
+
this.rootSeries = series;
|
|
30726
|
+
return changed;
|
|
30727
|
+
}
|
|
30728
|
+
/*
|
|
30729
|
+
* Takes the angles the root's records name into its attitude series, apart from where it is.
|
|
30730
|
+
* @param replace the records are everything held for the root, as for absorbRootRecords.
|
|
30731
|
+
* @returns whether the series changed.
|
|
30732
|
+
*/
|
|
30733
|
+
absorbRootAttitude(records, replace) {
|
|
30734
|
+
const angle = (transform, key) => {
|
|
30735
|
+
var _a;
|
|
30736
|
+
const value = (_a = transform === null || transform === void 0 ? void 0 : transform[key]) !== null && _a !== void 0 ? _a : transform === null || transform === void 0 ? void 0 : transform[key[0].toUpperCase() + key.slice(1)];
|
|
30737
|
+
return value == null || isNaN(+value) ? null : +value;
|
|
30738
|
+
};
|
|
30739
|
+
const byTime = new Map(replace ? [] : this.rootAttitude.map(k => [k.timeMs, k]));
|
|
30740
|
+
for (const record of records || []) {
|
|
30741
|
+
const timeMs = (record === null || record === void 0 ? void 0 : record.dateTime) ? new Date(record.dateTime).getTime() : NaN;
|
|
30742
|
+
const key = {
|
|
30743
|
+
timeMs,
|
|
30744
|
+
heading: angle(record === null || record === void 0 ? void 0 : record.transform, "heading"),
|
|
30745
|
+
pitch: angle(record === null || record === void 0 ? void 0 : record.transform, "pitch"),
|
|
30746
|
+
roll: angle(record === null || record === void 0 ? void 0 : record.transform, "roll")
|
|
30747
|
+
};
|
|
30748
|
+
if (isNaN(timeMs) || (key.heading == null && key.pitch == null && key.roll == null)) {
|
|
30749
|
+
continue;
|
|
30750
|
+
}
|
|
30751
|
+
byTime.set(timeMs, key);
|
|
30752
|
+
}
|
|
30753
|
+
const series = Array.from(byTime.values()).sort((x, y) => x.timeMs - y.timeMs);
|
|
30754
|
+
const held = this.rootAttitude;
|
|
30755
|
+
const differs = (k, i) => (k.timeMs !== held[i].timeMs ||
|
|
30756
|
+
k.heading !== held[i].heading ||
|
|
30757
|
+
k.pitch !== held[i].pitch ||
|
|
30758
|
+
k.roll !== held[i].roll);
|
|
30759
|
+
const changed = series.length !== held.length || series.some(differs);
|
|
30760
|
+
this.rootAttitude = series;
|
|
30761
|
+
return changed;
|
|
30762
|
+
}
|
|
30763
|
+
/*
|
|
30764
|
+
* A node's matrix in the root's frame at a time, from each ancestor's pose within its parent.
|
|
30765
|
+
*/
|
|
30766
|
+
composeWorld(entityId, timeMs, memo, localOf = (id) => this.localAt(id, timeMs)) {
|
|
30767
|
+
var _a, _b, _c, _d;
|
|
30768
|
+
if (memo === null || memo === void 0 ? void 0 : memo.has(entityId)) {
|
|
30769
|
+
return memo.get(entityId);
|
|
30770
|
+
}
|
|
30771
|
+
let world = null;
|
|
30772
|
+
const local = localOf(entityId);
|
|
30773
|
+
if (local) {
|
|
30774
|
+
const parentId = (_b = (_a = this.hierarchyNodeByEntityId) === null || _a === void 0 ? void 0 : _a[entityId]) === null || _b === void 0 ? void 0 : _b.parentId;
|
|
30775
|
+
const parent = parentId ? this.composeWorld(parentId, timeMs, memo, localOf) : null;
|
|
30776
|
+
world = parent ? Cesium.Matrix4.multiply(parent, local, new Cesium.Matrix4()) : Cesium.Matrix4.clone(local);
|
|
30777
|
+
}
|
|
30778
|
+
else if (entityId !== this.rootId) {
|
|
30779
|
+
// A node whose own position was not fetched falls back to the API's composed matrix.
|
|
30780
|
+
const child = this.children.get(entityId);
|
|
30781
|
+
world = Manager.MatrixFromRows((_d = (_c = child === null || child === void 0 ? void 0 : child.entity) === null || _c === void 0 ? void 0 : _c.Bruce) === null || _d === void 0 ? void 0 : _d.AssemblyWorldPosition);
|
|
30782
|
+
}
|
|
30783
|
+
memo === null || memo === void 0 ? void 0 : memo.set(entityId, world);
|
|
30784
|
+
return world;
|
|
30785
|
+
}
|
|
30786
|
+
/*
|
|
30787
|
+
* Under a clamped or relative style, lifts a part by how much higher its ground is than the root's.
|
|
30788
|
+
*/
|
|
30789
|
+
measureGroundOffset(entity) {
|
|
30790
|
+
var _a;
|
|
30791
|
+
const entityId = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
30792
|
+
this.groundOffsets.delete(entityId);
|
|
30793
|
+
const root = this.apiEntities.get(this.rootId);
|
|
30794
|
+
if (!entityId ||
|
|
30795
|
+
entityId === this.rootId ||
|
|
30796
|
+
!root ||
|
|
30797
|
+
!this.rootPos3d ||
|
|
30798
|
+
Manager.GetRecordHeightRef(this.item) === Cesium.HeightReference.NONE) {
|
|
30799
|
+
return;
|
|
30800
|
+
}
|
|
30801
|
+
const rootFrame = Manager.rootFrame(this.rootPos3d, this.rootHeading, this.rootPitch, this.rootRoll);
|
|
30802
|
+
const toRoot = Cesium.Matrix4.inverse(rootFrame, new Cesium.Matrix4());
|
|
30803
|
+
const groundUp = (record) => {
|
|
30804
|
+
const pos3d = exports.EntityUtils.GetPos({
|
|
30805
|
+
viewer: this.viewer,
|
|
30806
|
+
entity: record,
|
|
30807
|
+
recordHeightRef: Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
30808
|
+
returnHeightRef: Cesium.HeightReference.NONE,
|
|
30809
|
+
allowRendered: false
|
|
30810
|
+
});
|
|
30811
|
+
return pos3d ? Cesium.Matrix4.multiplyByPoint(toRoot, pos3d, new Cesium.Cartesian3()).z : null;
|
|
30812
|
+
};
|
|
30813
|
+
const part = groundUp(entity);
|
|
30814
|
+
const under = groundUp(root);
|
|
30815
|
+
if (part == null || under == null || Math.abs(part - under) < 1e-6) {
|
|
30816
|
+
return;
|
|
30817
|
+
}
|
|
30818
|
+
this.groundOffsets.set(entityId, new Cesium.Cartesian3(0, 0, part - under));
|
|
30819
|
+
}
|
|
30820
|
+
/*
|
|
30821
|
+
* The rigid Earth-fixed motion from where a part's record places it to where it is drawn at a time.
|
|
30822
|
+
*/
|
|
30823
|
+
motionAt(entityId, time) {
|
|
30824
|
+
if (this.disposed || !time || !this.rootPos3d) {
|
|
30825
|
+
return null;
|
|
30826
|
+
}
|
|
30827
|
+
const timeMs = Cesium.JulianDate.toDate(time).getTime();
|
|
30828
|
+
const root = this.rootAt(timeMs);
|
|
30829
|
+
const drawn = this.composeWorld(entityId, timeMs, new Map());
|
|
30830
|
+
const stored = this.composeWorld(entityId, timeMs, new Map(), (id) => {
|
|
30831
|
+
var _a, _b, _c, _d;
|
|
30832
|
+
return ((_d = (_c = Manager.MatrixFromRows((_b = (_a = this.apiEntities.get(id)) === null || _a === void 0 ? void 0 : _a.Bruce) === null || _b === void 0 ? void 0 : _b.AssemblyPosition)) !== null && _c !== void 0 ? _c : this.localPositions.get(id)) !== null && _d !== void 0 ? _d : null);
|
|
30833
|
+
});
|
|
30834
|
+
if (!root || !drawn || !stored) {
|
|
30835
|
+
return null;
|
|
30836
|
+
}
|
|
30837
|
+
const drawnFixed = Cesium.Matrix4.multiply(Manager.rootFrame(root.pos3d, root.heading, root.pitch, root.roll), drawn, new Cesium.Matrix4());
|
|
30838
|
+
const storedFixed = Cesium.Matrix4.multiply(Manager.rootFrame(this.rootPos3d, this.rootHeading, this.rootPitch, this.rootRoll), stored, new Cesium.Matrix4());
|
|
30839
|
+
return Cesium.Matrix4.multiply(drawnFixed, Cesium.Matrix4.inverse(storedFixed, new Cesium.Matrix4()), new Cesium.Matrix4());
|
|
30840
|
+
}
|
|
30841
|
+
/*
|
|
30842
|
+
* A node's pose within its parent at a time, interpolated between the records either side.
|
|
30843
|
+
*/
|
|
30844
|
+
localAt(entityId, timeMs) {
|
|
30845
|
+
var _a;
|
|
30846
|
+
// The live pose stands before the first record and the last record holds after it, as in an API read.
|
|
30847
|
+
const live = (_a = this.localPositions.get(entityId)) !== null && _a !== void 0 ? _a : null;
|
|
30848
|
+
const series = this.jointSeries.get(entityId);
|
|
30849
|
+
if (!(series === null || series === void 0 ? void 0 : series.length) || timeMs == null || timeMs < series[0].timeMs) {
|
|
30850
|
+
return live;
|
|
30851
|
+
}
|
|
30852
|
+
let i = 0;
|
|
30853
|
+
while (i < series.length - 1 && series[i + 1].timeMs <= timeMs) {
|
|
30854
|
+
i++;
|
|
30855
|
+
}
|
|
30856
|
+
const a = series[i];
|
|
30857
|
+
const b = series[i + 1];
|
|
30858
|
+
if (!b) {
|
|
30859
|
+
return Cesium.Matrix4.fromTranslationQuaternionRotationScale(a.translation, a.rotation, a.scale);
|
|
30860
|
+
}
|
|
30861
|
+
const t = (timeMs - a.timeMs) / (b.timeMs - a.timeMs);
|
|
30862
|
+
return Cesium.Matrix4.fromTranslationQuaternionRotationScale(Cesium.Cartesian3.lerp(a.translation, b.translation, t, new Cesium.Cartesian3()), Cesium.Quaternion.slerp(a.rotation, b.rotation, t, new Cesium.Quaternion()), Cesium.Cartesian3.lerp(a.scale, b.scale, t, new Cesium.Cartesian3()));
|
|
30863
|
+
}
|
|
30864
|
+
/*
|
|
30865
|
+
* Rebuilds each node's keyframes from the historic records held so far.
|
|
30866
|
+
* @returns whether any node has keyframes.
|
|
30867
|
+
*/
|
|
30868
|
+
absorbJointRecords(recordsByIds) {
|
|
30869
|
+
var _a;
|
|
30870
|
+
// Everything held is given, so a node with nothing left, eg. its simulated records cleared, stops moving.
|
|
30871
|
+
for (const entityId of Array.from(this.jointSeries.keys())) {
|
|
30872
|
+
if (!((_a = recordsByIds === null || recordsByIds === void 0 ? void 0 : recordsByIds[entityId]) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
30873
|
+
this.jointSeries.delete(entityId);
|
|
30874
|
+
}
|
|
30875
|
+
}
|
|
30876
|
+
for (const entityId of Object.keys(recordsByIds || {})) {
|
|
30877
|
+
const keyframes = [];
|
|
30878
|
+
for (const record of recordsByIds[entityId] || []) {
|
|
30879
|
+
const matrix = Manager.MatrixFromRows(record.assemblyPosition);
|
|
30880
|
+
const timeMs = new Date(record.dateTime).getTime();
|
|
30881
|
+
if (!matrix || isNaN(timeMs)) {
|
|
30882
|
+
continue;
|
|
30883
|
+
}
|
|
30884
|
+
const scale = Cesium.Matrix4.getScale(matrix, new Cesium.Cartesian3());
|
|
30885
|
+
const rotation = Cesium.Matrix4.getRotation(matrix, new Cesium.Matrix3());
|
|
30886
|
+
keyframes.push({
|
|
30887
|
+
timeMs,
|
|
30888
|
+
translation: Cesium.Matrix4.getTranslation(matrix, new Cesium.Cartesian3()),
|
|
30889
|
+
rotation: Cesium.Quaternion.fromRotationMatrix(rotation),
|
|
30890
|
+
scale
|
|
30891
|
+
});
|
|
30892
|
+
}
|
|
30893
|
+
if (keyframes.length) {
|
|
30894
|
+
keyframes.sort((x, y) => x.timeMs - y.timeMs);
|
|
30895
|
+
this.jointSeries.set(entityId, keyframes);
|
|
30896
|
+
}
|
|
30897
|
+
}
|
|
30898
|
+
this.refreshAnimated();
|
|
30899
|
+
return this.jointSeries.size > 0;
|
|
30900
|
+
}
|
|
30901
|
+
/*
|
|
30902
|
+
* Rebuilds which drawn children can move with the clock, by walking each one up to the root.
|
|
30903
|
+
*/
|
|
30904
|
+
refreshAnimated() {
|
|
30905
|
+
this.animatedIds.clear();
|
|
30906
|
+
if (!this.jointSeries.size) {
|
|
30907
|
+
return;
|
|
30908
|
+
}
|
|
30909
|
+
for (const entityId of this.children.keys()) {
|
|
30910
|
+
if (this.hasAnimatedAncestry(entityId)) {
|
|
30911
|
+
this.animatedIds.add(entityId);
|
|
29328
30912
|
}
|
|
29329
30913
|
}
|
|
29330
|
-
|
|
30914
|
+
}
|
|
30915
|
+
/*
|
|
30916
|
+
* Whether a node or anything above it has keyframes, so the clock can move it.
|
|
30917
|
+
*/
|
|
30918
|
+
hasAnimatedAncestry(entityId) {
|
|
30919
|
+
var _a, _b;
|
|
30920
|
+
let at = entityId;
|
|
30921
|
+
while (at && this.jointSeries.size) {
|
|
30922
|
+
if (this.jointSeries.has(at)) {
|
|
30923
|
+
return true;
|
|
30924
|
+
}
|
|
30925
|
+
at = (_b = (_a = this.hierarchyNodeByEntityId) === null || _a === void 0 ? void 0 : _a[at]) === null || _b === void 0 ? void 0 : _b.parentId;
|
|
30926
|
+
}
|
|
30927
|
+
return false;
|
|
30928
|
+
}
|
|
30929
|
+
/*
|
|
30930
|
+
* Which nodes to ask history for.
|
|
30931
|
+
*/
|
|
30932
|
+
async historicEntityIds(api) {
|
|
30933
|
+
var _a, _b;
|
|
30934
|
+
// Through the Assembly when there is one, so the hierarchy follows the relation type on its record.
|
|
30935
|
+
const assemblyId = this.item["Assembly.ID"];
|
|
30936
|
+
const root = assemblyId ? { key: "root", AssemblyID: assemblyId } : { key: "root", RootID: this.rootId };
|
|
30937
|
+
const historic = {
|
|
30938
|
+
key: "historic",
|
|
30939
|
+
Historic: { HistoricKey: ((_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey) || undefined }
|
|
30940
|
+
};
|
|
30941
|
+
const query = {
|
|
30942
|
+
[BModels.DataLab.EReqKey.Primary]: { Items: [root, historic], Select: { Type: BModels.DataLab.ESelectType.Id } }
|
|
30943
|
+
};
|
|
30944
|
+
const load = 1000;
|
|
30945
|
+
try {
|
|
30946
|
+
const ids = [];
|
|
30947
|
+
for (let skip = 0;; skip += load) {
|
|
30948
|
+
const { items } = await BModels.DataLab.Run({ api, query, skip, load });
|
|
30949
|
+
ids.push(...(items !== null && items !== void 0 ? items : []));
|
|
30950
|
+
if (!items || items.length < load) {
|
|
30951
|
+
return ids;
|
|
30952
|
+
}
|
|
30953
|
+
}
|
|
30954
|
+
}
|
|
30955
|
+
catch (e) {
|
|
30956
|
+
// An API without the historic criterion gets asked about every node, as before it existed.
|
|
30957
|
+
console.warn("AssemblyRenderManager.historicEntityIds()", e);
|
|
30958
|
+
}
|
|
30959
|
+
return Object.keys((_b = this.hierarchyNodeByEntityId) !== null && _b !== void 0 ? _b : { [this.rootId]: null });
|
|
30960
|
+
}
|
|
30961
|
+
/**
|
|
30962
|
+
* Builds a matrix from the row-major rows that Bruce/AssemblyPosition and AssemblyWorldPosition use.
|
|
30963
|
+
* @param rows
|
|
30964
|
+
*/
|
|
30965
|
+
static MatrixFromRows(rows) {
|
|
30966
|
+
if (!Array.isArray(rows) || rows.length !== 4 || rows.some(r => !Array.isArray(r) || r.length !== 4)) {
|
|
30967
|
+
return null;
|
|
30968
|
+
}
|
|
30969
|
+
return new Cesium.Matrix4(+rows[0][0], +rows[0][1], +rows[0][2], +rows[0][3], +rows[1][0], +rows[1][1], +rows[1][2], +rows[1][3], +rows[2][0], +rows[2][1], +rows[2][2], +rows[2][3], +rows[3][0], +rows[3][1], +rows[3][2], +rows[3][3]);
|
|
30970
|
+
}
|
|
30971
|
+
/**
|
|
30972
|
+
* The inverse of MatrixFromRows.
|
|
30973
|
+
* @param matrix
|
|
30974
|
+
*/
|
|
30975
|
+
static RowsFromMatrix(matrix) {
|
|
30976
|
+
const rows = [];
|
|
30977
|
+
for (let r = 0; r < 4; r++) {
|
|
30978
|
+
const row = Cesium.Matrix4.getRow(matrix, r, new Cesium.Cartesian4());
|
|
30979
|
+
rows.push([row.x, row.y, row.z, row.w]);
|
|
30980
|
+
}
|
|
30981
|
+
return rows;
|
|
29331
30982
|
}
|
|
29332
30983
|
Init() {
|
|
29333
30984
|
this.renderPriority = this.item.renderPriority;
|
|
@@ -29335,6 +30986,7 @@
|
|
|
29335
30986
|
this.renderPriority = 1;
|
|
29336
30987
|
}
|
|
29337
30988
|
(async () => {
|
|
30989
|
+
var _a, _b;
|
|
29338
30990
|
if (this.disposed) {
|
|
29339
30991
|
return;
|
|
29340
30992
|
}
|
|
@@ -29350,6 +31002,8 @@
|
|
|
29350
31002
|
this.hierarchyUpdate.Trigger(hierarchy);
|
|
29351
31003
|
// Build hierarchy node cache for quick lookups
|
|
29352
31004
|
this.buildHierarchyNodes(hierarchy);
|
|
31005
|
+
// A set for membership, since searching the list took minutes at 200k nodes.
|
|
31006
|
+
const seenIds = new Set();
|
|
29353
31007
|
const traverseHierarchy = (node, leavesOnly) => {
|
|
29354
31008
|
var _a;
|
|
29355
31009
|
if (node.Children) {
|
|
@@ -29358,7 +31012,8 @@
|
|
|
29358
31012
|
}
|
|
29359
31013
|
}
|
|
29360
31014
|
const addNode = !leavesOnly || !((_a = node.Children) === null || _a === void 0 ? void 0 : _a.length);
|
|
29361
|
-
if (addNode && node.ID && !
|
|
31015
|
+
if (addNode && node.ID && !seenIds.has(node.ID)) {
|
|
31016
|
+
seenIds.add(node.ID);
|
|
29362
31017
|
flatEntityIds.push(node.ID);
|
|
29363
31018
|
}
|
|
29364
31019
|
};
|
|
@@ -29377,17 +31032,17 @@
|
|
|
29377
31032
|
}
|
|
29378
31033
|
}
|
|
29379
31034
|
this.rootId = rootId;
|
|
31035
|
+
this.simulationRemoval = (_b = (_a = this.simulation) === null || _a === void 0 ? void 0 : _a.OnChanged.Subscribe((change) => this.onSimulationChanged(change))) !== null && _b !== void 0 ? _b : null;
|
|
29380
31036
|
if (this.disposed) {
|
|
29381
31037
|
return;
|
|
29382
31038
|
}
|
|
29383
31039
|
else if (flatEntityIds.length === 0) {
|
|
29384
31040
|
return;
|
|
29385
31041
|
}
|
|
31042
|
+
// Followed while the parts load: in a large Assembly loading takes far longer than anyone waits.
|
|
31043
|
+
const following = this.viewerDateTimeSub();
|
|
29386
31044
|
await this.processEntityIds(flatEntityIds);
|
|
29387
|
-
|
|
29388
|
-
return;
|
|
29389
|
-
}
|
|
29390
|
-
this.viewerDateTimeSub();
|
|
31045
|
+
await following;
|
|
29391
31046
|
}
|
|
29392
31047
|
catch (e) {
|
|
29393
31048
|
console.error("AssemblyRenderManager.Manager.Init()", e);
|
|
@@ -29414,7 +31069,7 @@
|
|
|
29414
31069
|
if (!batch.length) {
|
|
29415
31070
|
continue;
|
|
29416
31071
|
}
|
|
29417
|
-
const { entities:
|
|
31072
|
+
const { entities: apiEntities } = await BModels.Entity.GetListByIds({
|
|
29418
31073
|
entityIds: batch,
|
|
29419
31074
|
api: this.getters.GetBruceApi(),
|
|
29420
31075
|
expandLODs: true,
|
|
@@ -29426,6 +31081,16 @@
|
|
|
29426
31081
|
if (this.disposed) {
|
|
29427
31082
|
return;
|
|
29428
31083
|
}
|
|
31084
|
+
const fetched = apiEntities.map((entity) => {
|
|
31085
|
+
var _a;
|
|
31086
|
+
this.apiEntities.set((_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID, entity);
|
|
31087
|
+
return this.withSimulation(entity);
|
|
31088
|
+
});
|
|
31089
|
+
for (const entity of fetched) {
|
|
31090
|
+
this.absorbNode(entity);
|
|
31091
|
+
}
|
|
31092
|
+
// Placements already worked out did not know about this batch's positions.
|
|
31093
|
+
this.pose = null;
|
|
29429
31094
|
for (const entity of fetched) {
|
|
29430
31095
|
// Filter for valid LODs then take the highest quality one (lowest level).
|
|
29431
31096
|
let lods = entity.Bruce.LOD || [];
|
|
@@ -29448,57 +31113,46 @@
|
|
|
29448
31113
|
// Won't bother with vector data for this experiment.
|
|
29449
31114
|
continue;
|
|
29450
31115
|
}
|
|
29451
|
-
const
|
|
29452
|
-
|
|
29453
|
-
|
|
29454
|
-
|
|
29455
|
-
|
|
29456
|
-
returnHeightRef: Cesium.HeightReference.NONE,
|
|
29457
|
-
allowRendered: false
|
|
29458
|
-
});
|
|
29459
|
-
if (!recordPos3d) {
|
|
31116
|
+
const entityId = entity.Bruce.ID;
|
|
31117
|
+
this.measureGroundOffset(entity);
|
|
31118
|
+
// A placement cached before the offset was known would leave the part off its ground.
|
|
31119
|
+
(_a = this.pose) === null || _a === void 0 ? void 0 : _a.placements.delete(entityId);
|
|
31120
|
+
if (!this.canMove(entityId) && !this.placementAt(entityId, this.viewer.clock.currentTime)) {
|
|
29460
31121
|
continue;
|
|
29461
31122
|
}
|
|
29462
|
-
const entityId = entity.Bruce.ID;
|
|
29463
|
-
if (entityId === this.rootId || !this.rootPos3d) {
|
|
29464
|
-
// Nothing has a frame to be relative to until the root has one.
|
|
29465
|
-
this.rootPos3d = recordPos3d;
|
|
29466
|
-
this.rootHeading = EnsureNumber((_a = entity.Bruce.Transform) === null || _a === void 0 ? void 0 : _a.heading, 0);
|
|
29467
|
-
}
|
|
29468
|
-
// Held as an offset in the root's frame, so a root move places it again without
|
|
29469
|
-
// anything being fetched. Where the root already moved, that is where it goes.
|
|
29470
|
-
const offset = Manager.ChildOffsetIn(this.rootPos3d, this.rootHeading, recordPos3d);
|
|
29471
|
-
const pos3d = Manager.ChildPositionFrom(this.rootPos3d, this.rootHeading, offset);
|
|
29472
|
-
// Optional: a child with no world matrix is still worth drawing, it just has no
|
|
29473
|
-
// orientation of its own to apply.
|
|
29474
|
-
const orient = exports.EntityUtils.GetAssemblyOrientation(entity, pos3d);
|
|
29475
31123
|
const cEntity = this.viewer.entities.add({
|
|
29476
31124
|
model: {
|
|
29477
31125
|
uri: lod["ClientFile"].URL,
|
|
29478
31126
|
...exports.ViewUtils.DefaultLightingProps(),
|
|
29479
31127
|
heightReference: Cesium.HeightReference.NONE
|
|
29480
|
-
}
|
|
29481
|
-
position: pos3d,
|
|
29482
|
-
orientation: orient ? new Cesium.ConstantProperty(orient) : undefined
|
|
31128
|
+
}
|
|
29483
31129
|
});
|
|
29484
31130
|
const prior = this.children.get(entityId);
|
|
29485
31131
|
if (prior && prior.cEntity !== cEntity) {
|
|
29486
31132
|
RemoveCEntityFromScene(this.viewer, prior.cEntity);
|
|
29487
31133
|
}
|
|
29488
|
-
|
|
31134
|
+
const child = {
|
|
29489
31135
|
entityId: entityId,
|
|
29490
31136
|
entity: entity,
|
|
29491
|
-
cEntity: cEntity
|
|
29492
|
-
|
|
29493
|
-
|
|
31137
|
+
cEntity: cEntity
|
|
31138
|
+
};
|
|
31139
|
+
this.children.set(entityId, child);
|
|
31140
|
+
// Joins the animated set by its own ancestry, so a late part never re-walks the rest.
|
|
31141
|
+
if (this.hasAnimatedAncestry(entityId)) {
|
|
31142
|
+
this.animatedIds.add(entityId);
|
|
31143
|
+
}
|
|
29494
31144
|
const geometryRadius = BModels.Entity.GetValue({
|
|
29495
31145
|
entity: entity,
|
|
29496
31146
|
path: ["Bruce", "GeometryRadius"]
|
|
29497
31147
|
});
|
|
29498
31148
|
cEntity.model["_radius"] = geometryRadius;
|
|
29499
31149
|
cEntity.model["_radiusLoaded"] = true;
|
|
31150
|
+
// Placed before it is registered, so the register never measures a visual with no position.
|
|
31151
|
+
this.bindPlacement(child);
|
|
29500
31152
|
this.visualsManager.AddRego({
|
|
29501
31153
|
rego: {
|
|
31154
|
+
moving: child.moving ? true : null,
|
|
31155
|
+
motion: (time) => this.motionAt(entity.Bruce.ID, time),
|
|
29502
31156
|
canEdit: true,
|
|
29503
31157
|
entityId: entity.Bruce.ID,
|
|
29504
31158
|
menuItemId: this.item.id,
|
|
@@ -29518,47 +31172,89 @@
|
|
|
29518
31172
|
}
|
|
29519
31173
|
}
|
|
29520
31174
|
/*
|
|
29521
|
-
* Follows the scene clock
|
|
29522
|
-
* Only the root is fetched: everything under it is placed through ApplyRootPosition.
|
|
31175
|
+
* Follows the scene clock, moving the Assembly along the root's history and each joint along its own.
|
|
29523
31176
|
*/
|
|
29524
|
-
viewerDateTimeSub() {
|
|
29525
|
-
|
|
31177
|
+
async viewerDateTimeSub() {
|
|
31178
|
+
var _a;
|
|
31179
|
+
const historic = Manager.IsHistoric(this.item);
|
|
31180
|
+
if (this.followingClock || !this.rootId || (!historic && !this.simulatedNodeIds().length)) {
|
|
29526
31181
|
return;
|
|
29527
31182
|
}
|
|
31183
|
+
this.followingClock = true;
|
|
29528
31184
|
const api = this.getters.GetBruceApi();
|
|
29529
|
-
const
|
|
31185
|
+
const historicIds = historic ? await this.historicEntityIds(api) : [];
|
|
31186
|
+
if (this.disposed) {
|
|
31187
|
+
return;
|
|
31188
|
+
}
|
|
31189
|
+
const attrKey = (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey;
|
|
29530
31190
|
const recordHeightRef = Manager.GetRecordHeightRef(this.item);
|
|
29531
31191
|
const toPosses = (records) => {
|
|
29532
31192
|
return exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(this.viewer, recordHeightRef, Cesium.HeightReference.NONE, records);
|
|
29533
31193
|
};
|
|
29534
|
-
|
|
29535
|
-
|
|
29536
|
-
|
|
29537
|
-
|
|
29538
|
-
|
|
29539
|
-
|
|
29540
|
-
|
|
29541
|
-
|
|
29542
|
-
|
|
29543
|
-
|
|
31194
|
+
if (historicIds.length) {
|
|
31195
|
+
this.historicGatherer = new HistoricGatherer({
|
|
31196
|
+
viewer: this.viewer,
|
|
31197
|
+
getApi: () => api,
|
|
31198
|
+
getAttrKey: () => attrKey,
|
|
31199
|
+
// For clock desync between whatever wrote the record and this client.
|
|
31200
|
+
paddingMs: 15000,
|
|
31201
|
+
simulation: this.simulation,
|
|
31202
|
+
onRecords: (recordsByIds) => {
|
|
31203
|
+
var _a;
|
|
31204
|
+
const records = recordsByIds[this.rootId];
|
|
31205
|
+
if (records === null || records === void 0 ? void 0 : records.length) {
|
|
31206
|
+
const posses = toPosses(records);
|
|
31207
|
+
(_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.SupplementSeries(posses);
|
|
31208
|
+
const moved = this.absorbRootRecords(posses, false);
|
|
31209
|
+
if (this.absorbRootAttitude(records, false) || moved) {
|
|
31210
|
+
this.repose();
|
|
31211
|
+
}
|
|
31212
|
+
}
|
|
31213
|
+
// Joint records go in together once the gather lands, so parents never draw apart from children.
|
|
29544
31214
|
}
|
|
29545
|
-
}
|
|
29546
|
-
}
|
|
31215
|
+
});
|
|
31216
|
+
}
|
|
31217
|
+
// The nodes with history: what the API has records for, and whatever has been simulated since.
|
|
31218
|
+
const nodes = () => Array.from(new Set([...historicIds, ...this.simulatedNodeIds()]));
|
|
29547
31219
|
let gathering = false;
|
|
29548
|
-
|
|
31220
|
+
// Set when what is held changed without a fetch, eg. a simulated record arriving.
|
|
31221
|
+
let stale = true;
|
|
31222
|
+
const gather = async (force) => {
|
|
31223
|
+
var _a, _b;
|
|
31224
|
+
stale = stale || Boolean(force);
|
|
29549
31225
|
if (this.disposed || gathering) {
|
|
29550
31226
|
return;
|
|
29551
31227
|
}
|
|
29552
31228
|
gathering = true;
|
|
29553
31229
|
try {
|
|
29554
|
-
const
|
|
31230
|
+
const ids = nodes();
|
|
31231
|
+
let fetched = false;
|
|
31232
|
+
let recordsByIds;
|
|
31233
|
+
if (this.historicGatherer) {
|
|
31234
|
+
({ fetched, recordsByIds } = await this.historicGatherer.Gather(ids.map(id => ({ Bruce: { ID: id } }))));
|
|
31235
|
+
}
|
|
31236
|
+
else {
|
|
31237
|
+
recordsByIds = (_b = (_a = this.simulation) === null || _a === void 0 ? void 0 : _a.MergeRecords({}, attrKey, ids)) !== null && _b !== void 0 ? _b : {};
|
|
31238
|
+
}
|
|
29555
31239
|
if (this.disposed) {
|
|
29556
31240
|
return;
|
|
29557
31241
|
}
|
|
31242
|
+
// A gather served from what is held changes nothing and runs every tick, so it stops here.
|
|
31243
|
+
if (!fetched && !stale && this.jointSeries.size) {
|
|
31244
|
+
return;
|
|
31245
|
+
}
|
|
31246
|
+
stale = false;
|
|
31247
|
+
let changed = this.absorbJointRecords(recordsByIds);
|
|
29558
31248
|
const posses = toPosses(recordsByIds[this.rootId] || []);
|
|
31249
|
+
changed = this.absorbRootRecords(posses, true) || changed;
|
|
31250
|
+
changed = this.absorbRootAttitude(recordsByIds[this.rootId] || [], true) || changed;
|
|
31251
|
+
if (changed) {
|
|
31252
|
+
this.repose();
|
|
31253
|
+
}
|
|
29559
31254
|
if (!posses.length) {
|
|
29560
31255
|
return;
|
|
29561
31256
|
}
|
|
31257
|
+
// Held for the trail alone; where the root is drawn comes from rootAt(), never from its smoothing.
|
|
29562
31258
|
if (!this.historicAnimation) {
|
|
29563
31259
|
this.historicAnimation = new exports.CesiumAnimatedProperty.AnimatePositionSeries({
|
|
29564
31260
|
posses: posses,
|
|
@@ -29572,15 +31268,21 @@
|
|
|
29572
31268
|
}
|
|
29573
31269
|
catch (e) {
|
|
29574
31270
|
console.error("AssemblyRenderManager.viewerDateTimeSub()", e);
|
|
31271
|
+
// A gather that throws would throw again straight away, so the retry waits for the next tick.
|
|
31272
|
+
stale = false;
|
|
29575
31273
|
}
|
|
29576
31274
|
finally {
|
|
29577
31275
|
gathering = false;
|
|
31276
|
+
// A change that landed mid-gather is not left for a tick that may never come on a paused clock.
|
|
31277
|
+
if (stale && !this.disposed) {
|
|
31278
|
+
gather();
|
|
31279
|
+
}
|
|
29578
31280
|
}
|
|
29579
31281
|
};
|
|
31282
|
+
this.regather = gather;
|
|
29580
31283
|
gather();
|
|
29581
31284
|
let lastTime = null;
|
|
29582
31285
|
const tickRemoval = this.viewer.clock.onTick.addEventListener(() => {
|
|
29583
|
-
var _a;
|
|
29584
31286
|
if (this.disposed) {
|
|
29585
31287
|
return;
|
|
29586
31288
|
}
|
|
@@ -29590,15 +31292,9 @@
|
|
|
29590
31292
|
}
|
|
29591
31293
|
lastTime = now;
|
|
29592
31294
|
gather();
|
|
29593
|
-
|
|
29594
|
-
|
|
29595
|
-
|
|
29596
|
-
const pos3d = this.historicAnimation.GetValue();
|
|
29597
|
-
if (pos3d) {
|
|
29598
|
-
this.ApplyRootPosition({
|
|
29599
|
-
pos3d: pos3d,
|
|
29600
|
-
heading: (_a = this.historicAnimation.GetHeadingDegrees()) !== null && _a !== void 0 ? _a : this.rootHeading
|
|
29601
|
-
});
|
|
31295
|
+
// Moving parts read the clock themselves when drawn, so the scene only needs a new frame.
|
|
31296
|
+
if (this.rootSeries.length || this.rootAttitude.length || this.animatedIds.size) {
|
|
31297
|
+
this.viewer.scene.requestRender();
|
|
29602
31298
|
}
|
|
29603
31299
|
});
|
|
29604
31300
|
this.viewerDateTimeChangeRemoval = () => {
|
|
@@ -29607,6 +31303,10 @@
|
|
|
29607
31303
|
(_a = this.historicGatherer) === null || _a === void 0 ? void 0 : _a.Dispose();
|
|
29608
31304
|
this.historicGatherer = null;
|
|
29609
31305
|
this.historicAnimation = null;
|
|
31306
|
+
this.regather = null;
|
|
31307
|
+
this.rootSeries = [];
|
|
31308
|
+
this.rootAttitude = [];
|
|
31309
|
+
this.pose = null;
|
|
29610
31310
|
};
|
|
29611
31311
|
}
|
|
29612
31312
|
/*
|
|
@@ -29614,7 +31314,7 @@
|
|
|
29614
31314
|
*/
|
|
29615
31315
|
applyRootTrack() {
|
|
29616
31316
|
var _a;
|
|
29617
|
-
if (!this.item.historicDrawTrack || !this.historicAnimation || this.
|
|
31317
|
+
if (!this.item.historicDrawTrack || !this.historicAnimation || this.trail) {
|
|
29618
31318
|
return;
|
|
29619
31319
|
}
|
|
29620
31320
|
const trackStyle = exports.EntityRenderEngine.GetTrackStyle({
|
|
@@ -29624,41 +31324,35 @@
|
|
|
29624
31324
|
if (!trackStyle) {
|
|
29625
31325
|
return;
|
|
29626
31326
|
}
|
|
29627
|
-
this.
|
|
29628
|
-
id: BModels.ObjectUtils.UId(15),
|
|
29629
|
-
polyline: {
|
|
29630
|
-
positions: new Cesium.CallbackProperty(() => { var _a, _b; return (_b = (_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.GetSeries()) !== null && _b !== void 0 ? _b : []; }, false),
|
|
29631
|
-
width: trackStyle.width,
|
|
29632
|
-
material: trackStyle.color,
|
|
29633
|
-
clampToGround: exports.EntityRenderEngine.GetHeightRefPolyline(Manager.GetRecordHeightRef(this.item))
|
|
29634
|
-
== Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
29635
|
-
zIndex: 0,
|
|
29636
|
-
classificationType: Cesium.ClassificationType.BOTH
|
|
29637
|
-
}
|
|
29638
|
-
});
|
|
29639
|
-
this.trackEntity._noEdit = true;
|
|
29640
|
-
this.trackEntity._noSelect = true;
|
|
29641
|
-
exports.CesiumEntityStyler.SetDefaultColor({
|
|
29642
|
-
color: trackStyle.color,
|
|
29643
|
-
entity: this.trackEntity,
|
|
31327
|
+
this.trail = new HistoricTrail.Trail({
|
|
29644
31328
|
viewer: this.viewer,
|
|
29645
|
-
|
|
29646
|
-
|
|
31329
|
+
color: trackStyle.color,
|
|
31330
|
+
width: trackStyle.width,
|
|
31331
|
+
clampToGround: exports.EntityRenderEngine.GetHeightRefPolyline(Manager.GetRecordHeightRef(this.item))
|
|
31332
|
+
== Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
31333
|
+
getSeries: () => { var _a, _b; return (_b = (_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.GetSeries()) !== null && _b !== void 0 ? _b : []; },
|
|
31334
|
+
trailSeconds: HistoricTrail.GetTrailSeconds(this.item),
|
|
31335
|
+
// Where the root is drawn, so the trail ends on the model; nothing before the first record held.
|
|
31336
|
+
positionAt: (timeMs) => (this.rootSeries.length && timeMs >= this.rootSeries[0].timeMs ? this.rootPositionAt(timeMs) : null)
|
|
29647
31337
|
});
|
|
29648
31338
|
}
|
|
29649
31339
|
Dispose() {
|
|
29650
|
-
var _a;
|
|
31340
|
+
var _a, _b, _c;
|
|
29651
31341
|
if (this.disposed) {
|
|
29652
31342
|
return;
|
|
29653
31343
|
}
|
|
29654
31344
|
this.disposed = true;
|
|
29655
31345
|
(_a = this.viewerDateTimeChangeRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
29656
31346
|
this.viewerDateTimeChangeRemoval = null;
|
|
29657
|
-
|
|
29658
|
-
|
|
29659
|
-
|
|
29660
|
-
|
|
31347
|
+
(_b = this.simulationRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
31348
|
+
this.simulationRemoval = null;
|
|
31349
|
+
this.apiEntities.clear();
|
|
31350
|
+
(_c = this.trail) === null || _c === void 0 ? void 0 : _c.Dispose();
|
|
31351
|
+
this.trail = null;
|
|
29661
31352
|
this.children.clear();
|
|
31353
|
+
this.localPositions.clear();
|
|
31354
|
+
this.jointSeries.clear();
|
|
31355
|
+
this.animatedIds.clear();
|
|
29662
31356
|
this.visualsManager.RemoveRegos({
|
|
29663
31357
|
menuItemId: this.item.id
|
|
29664
31358
|
});
|
|
@@ -29881,6 +31575,149 @@
|
|
|
29881
31575
|
AssemblyRenderManager.Manager = Manager;
|
|
29882
31576
|
})(exports.AssemblyRenderManager || (exports.AssemblyRenderManager = {}));
|
|
29883
31577
|
|
|
31578
|
+
(function (MenuItemStyles) {
|
|
31579
|
+
// Tileset items whose render manager applies styleId through a Styler.
|
|
31580
|
+
const TILESET_TYPES = [
|
|
31581
|
+
BModels.MenuItem.EType.CadTileset,
|
|
31582
|
+
BModels.MenuItem.EType.ArbTileset,
|
|
31583
|
+
BModels.MenuItem.EType.IonTileset,
|
|
31584
|
+
BModels.MenuItem.EType.EntityTileset
|
|
31585
|
+
];
|
|
31586
|
+
// Items whose style lives on their zoom control rows.
|
|
31587
|
+
const ZOOM_CONTROL_TYPES = [
|
|
31588
|
+
BModels.MenuItem.EType.Entities,
|
|
31589
|
+
BModels.MenuItem.EType.Entity,
|
|
31590
|
+
BModels.MenuItem.EType.EntitiesIds,
|
|
31591
|
+
BModels.MenuItem.EType.EntitiesLoaded,
|
|
31592
|
+
BModels.MenuItem.EType.DataLab
|
|
31593
|
+
];
|
|
31594
|
+
/**
|
|
31595
|
+
* Returns the ordered styles a user can swap between for the item, or an empty array when it offers no choice.
|
|
31596
|
+
*/
|
|
31597
|
+
function GetStyleIds(item) {
|
|
31598
|
+
var _a;
|
|
31599
|
+
if (isStyledTileset(item)) {
|
|
31600
|
+
return cleanIds(item.styleIds);
|
|
31601
|
+
}
|
|
31602
|
+
if (ZOOM_CONTROL_TYPES.includes(item === null || item === void 0 ? void 0 : item.Type)) {
|
|
31603
|
+
return cleanIds((_a = getVisibleRow(item.CameraZoomSettings)) === null || _a === void 0 ? void 0 : _a.StyleIDs);
|
|
31604
|
+
}
|
|
31605
|
+
return [];
|
|
31606
|
+
}
|
|
31607
|
+
MenuItemStyles.GetStyleIds = GetStyleIds;
|
|
31608
|
+
/**
|
|
31609
|
+
* Returns the style the item currently renders with, from styleId or its one non-hidden zoom row.
|
|
31610
|
+
*/
|
|
31611
|
+
function GetStyleId(item) {
|
|
31612
|
+
var _a;
|
|
31613
|
+
if (TILESET_TYPES.includes(item === null || item === void 0 ? void 0 : item.Type)) {
|
|
31614
|
+
return item.styleId;
|
|
31615
|
+
}
|
|
31616
|
+
if (ZOOM_CONTROL_TYPES.includes(item === null || item === void 0 ? void 0 : item.Type)) {
|
|
31617
|
+
return (_a = getVisibleRow(item.CameraZoomSettings)) === null || _a === void 0 ? void 0 : _a.StyleID;
|
|
31618
|
+
}
|
|
31619
|
+
return undefined;
|
|
31620
|
+
}
|
|
31621
|
+
MenuItemStyles.GetStyleId = GetStyleId;
|
|
31622
|
+
/**
|
|
31623
|
+
* Returns a copy of the item rendering with the given style, or null when that style is not one of its options.
|
|
31624
|
+
*/
|
|
31625
|
+
function WithStyleId(item, styleId) {
|
|
31626
|
+
const styleIds = GetStyleIds(item);
|
|
31627
|
+
const picked = styleIds.find(x => isSameId(x, styleId));
|
|
31628
|
+
if (picked == null) {
|
|
31629
|
+
return null;
|
|
31630
|
+
}
|
|
31631
|
+
if (isStyledTileset(item)) {
|
|
31632
|
+
return { ...item, styleId: picked };
|
|
31633
|
+
}
|
|
31634
|
+
const zItem = item;
|
|
31635
|
+
const visible = getVisibleRow(zItem.CameraZoomSettings);
|
|
31636
|
+
return {
|
|
31637
|
+
...zItem,
|
|
31638
|
+
CameraZoomSettings: zItem.CameraZoomSettings.map(row => {
|
|
31639
|
+
if (row !== visible) {
|
|
31640
|
+
return row;
|
|
31641
|
+
}
|
|
31642
|
+
// An inline style would win over the picked ID.
|
|
31643
|
+
const next = { ...row, StyleID: picked };
|
|
31644
|
+
delete next.Style;
|
|
31645
|
+
return next;
|
|
31646
|
+
})
|
|
31647
|
+
};
|
|
31648
|
+
}
|
|
31649
|
+
MenuItemStyles.WithStyleId = WithStyleId;
|
|
31650
|
+
/**
|
|
31651
|
+
* Returns the item on the first of its styles unless it already uses one, or the same object when it has none.
|
|
31652
|
+
*/
|
|
31653
|
+
function Resolve(item) {
|
|
31654
|
+
var _a;
|
|
31655
|
+
const styleIds = GetStyleIds(item);
|
|
31656
|
+
if (!styleIds.length) {
|
|
31657
|
+
return item;
|
|
31658
|
+
}
|
|
31659
|
+
const current = GetStyleId(item);
|
|
31660
|
+
if (current != null && styleIds.some(x => isSameId(x, current))) {
|
|
31661
|
+
return item;
|
|
31662
|
+
}
|
|
31663
|
+
return (_a = WithStyleId(item, styleIds[0])) !== null && _a !== void 0 ? _a : item;
|
|
31664
|
+
}
|
|
31665
|
+
MenuItemStyles.Resolve = Resolve;
|
|
31666
|
+
/**
|
|
31667
|
+
* Returns a copy on the style a bookmark alternation picked, or the item itself when that is not an option.
|
|
31668
|
+
*/
|
|
31669
|
+
function ApplyAlternation(item, alternation) {
|
|
31670
|
+
var _a, _b, _c;
|
|
31671
|
+
// Alternations are partial items and may carry no Type, so the pick is read from whichever field is present.
|
|
31672
|
+
const alt = alternation;
|
|
31673
|
+
const picked = (_a = alt === null || alt === void 0 ? void 0 : alt.styleId) !== null && _a !== void 0 ? _a : (_b = getVisibleRow(alt === null || alt === void 0 ? void 0 : alt.CameraZoomSettings)) === null || _b === void 0 ? void 0 : _b.StyleID;
|
|
31674
|
+
if (picked == null) {
|
|
31675
|
+
return item;
|
|
31676
|
+
}
|
|
31677
|
+
return (_c = WithStyleId(item, picked)) !== null && _c !== void 0 ? _c : item;
|
|
31678
|
+
}
|
|
31679
|
+
MenuItemStyles.ApplyAlternation = ApplyAlternation;
|
|
31680
|
+
/**
|
|
31681
|
+
* Returns true when the two items differ by nothing but which of their styles is picked.
|
|
31682
|
+
*/
|
|
31683
|
+
function IsStyleChangeOnly(from, to) {
|
|
31684
|
+
if (!from || !to || from.Type !== to.Type) {
|
|
31685
|
+
return false;
|
|
31686
|
+
}
|
|
31687
|
+
const toStyleId = GetStyleId(to);
|
|
31688
|
+
if (toStyleId == null || isSameId(GetStyleId(from), toStyleId)) {
|
|
31689
|
+
return false;
|
|
31690
|
+
}
|
|
31691
|
+
const moved = WithStyleId(from, toStyleId);
|
|
31692
|
+
// A false mismatch only costs the in-place swap, so key order is not normalized.
|
|
31693
|
+
return Boolean(moved) && JSON.stringify(moved) === JSON.stringify(to);
|
|
31694
|
+
}
|
|
31695
|
+
MenuItemStyles.IsStyleChangeOnly = IsStyleChangeOnly;
|
|
31696
|
+
function isStyledTileset(item) {
|
|
31697
|
+
if (!TILESET_TYPES.includes(item === null || item === void 0 ? void 0 : item.Type)) {
|
|
31698
|
+
return false;
|
|
31699
|
+
}
|
|
31700
|
+
// These two only run a Styler when asked to.
|
|
31701
|
+
if (item.Type === BModels.MenuItem.EType.ArbTileset || item.Type === BModels.MenuItem.EType.EntityTileset) {
|
|
31702
|
+
return Boolean(item.ApplyStyles);
|
|
31703
|
+
}
|
|
31704
|
+
return true;
|
|
31705
|
+
}
|
|
31706
|
+
function getVisibleRow(rows) {
|
|
31707
|
+
const visible = (rows !== null && rows !== void 0 ? rows : []).filter(x => x && x.DisplayType !== BModels.ZoomControl.EDisplayType.Hidden);
|
|
31708
|
+
return visible.length === 1 ? visible[0] : null;
|
|
31709
|
+
}
|
|
31710
|
+
function cleanIds(ids) {
|
|
31711
|
+
return (ids !== null && ids !== void 0 ? ids : []).filter(x => x != null && x !== "");
|
|
31712
|
+
}
|
|
31713
|
+
/*
|
|
31714
|
+
* Compares style references, which can be an ID typed as a string or a number.
|
|
31715
|
+
*/
|
|
31716
|
+
function isSameId(a, b) {
|
|
31717
|
+
return a != null && b != null && String(a) === String(b);
|
|
31718
|
+
}
|
|
31719
|
+
})(exports.MenuItemStyles || (exports.MenuItemStyles = {}));
|
|
31720
|
+
|
|
29884
31721
|
/**
|
|
29885
31722
|
* Util to batch Tileset and Root Entity coord requests between Menu Items.
|
|
29886
31723
|
* This avoids per-menu-item requests and allows for them to request together if enabled within N ms of each other.
|
|
@@ -30112,12 +31949,17 @@
|
|
|
30112
31949
|
this.OnSeriesUpdated.Trigger({ itemId, segments: [] });
|
|
30113
31950
|
}
|
|
30114
31951
|
}
|
|
31952
|
+
get Simulation() {
|
|
31953
|
+
return this.simulation;
|
|
31954
|
+
}
|
|
30115
31955
|
get Monitor() {
|
|
30116
31956
|
return this.sharedMonitor;
|
|
30117
31957
|
}
|
|
30118
31958
|
constructor(params) {
|
|
30119
31959
|
this.items = [];
|
|
30120
31960
|
this.pendingHandoffPool = [];
|
|
31961
|
+
// The settings bookmark alternations overwrite on a view's items, as that view authored them.
|
|
31962
|
+
this.authoredAlternations = new WeakMap();
|
|
30121
31963
|
this.onUpdate = null;
|
|
30122
31964
|
// Segments discovered so far per menu item ID.
|
|
30123
31965
|
this.seriesSegments = new Map();
|
|
@@ -30137,6 +31979,7 @@
|
|
|
30137
31979
|
this.visualsRegister = visualsRegister;
|
|
30138
31980
|
this.sharedGetters = new exports.SharedGetters.Cache();
|
|
30139
31981
|
this.sharedHistoric = new SharedHistoricGetters.Cache();
|
|
31982
|
+
this.simulation = exports.EntitySimulation.Get(this.viewer);
|
|
30140
31983
|
this.sharedMonitor = new exports.CesiumViewMonitor.Monitor(this.viewer);
|
|
30141
31984
|
this.tilesetInitQueue = new InitQueueTileset(this.getters);
|
|
30142
31985
|
}
|
|
@@ -30172,7 +32015,7 @@
|
|
|
30172
32015
|
* @returns
|
|
30173
32016
|
*/
|
|
30174
32017
|
RenderItem(params) {
|
|
30175
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
32018
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
30176
32019
|
if (this.viewer.isDestroyed()) {
|
|
30177
32020
|
return null;
|
|
30178
32021
|
}
|
|
@@ -30196,13 +32039,21 @@
|
|
|
30196
32039
|
if (params.modelSpace == null) {
|
|
30197
32040
|
params.modelSpace = false;
|
|
30198
32041
|
}
|
|
32042
|
+
// An item with a style set renders its first style unless the caller already picked one of them.
|
|
32043
|
+
params = { ...params, item: exports.MenuItemStyles.Resolve(params.item) };
|
|
30199
32044
|
let rItem = this.items.find(x => x.id == params.item.id);
|
|
30200
32045
|
let create = true;
|
|
30201
32046
|
// Item already exists so we'll check if we should re-create it.
|
|
30202
32047
|
if (rItem) {
|
|
32048
|
+
// Only the picked style changed, so what is drawn gets restyled rather than rebuilt.
|
|
32049
|
+
if (exports.MenuItemStyles.IsStyleChangeOnly(rItem.item, params.item) && this.isStyleSwapCapable(rItem.renderManager)) {
|
|
32050
|
+
rItem.renderManager.SwapStyle(params.item);
|
|
32051
|
+
rItem.item = params.item;
|
|
32052
|
+
create = false;
|
|
32053
|
+
}
|
|
30203
32054
|
// This means we're updating an entities menu item re-using the same id.
|
|
30204
32055
|
// Eg: a bookmark swap that keeps the same item but changes tags, style, or zoom settings.
|
|
30205
|
-
if (rItem.type == BModels.MenuItem.EType.Entities && params.item.Type == BModels.MenuItem.EType.Entities) {
|
|
32056
|
+
else if (rItem.type == BModels.MenuItem.EType.Entities && params.item.Type == BModels.MenuItem.EType.Entities) {
|
|
30206
32057
|
rItem.renderManager.Init({
|
|
30207
32058
|
item: params.item,
|
|
30208
32059
|
});
|
|
@@ -30350,7 +32201,8 @@
|
|
|
30350
32201
|
monitor: this.sharedMonitor,
|
|
30351
32202
|
item: params.item,
|
|
30352
32203
|
sharedGetters: this.sharedGetters,
|
|
30353
|
-
onSeriesDiscovered: (segment) => this.RecordSeriesSegment(rItem.id, segment)
|
|
32204
|
+
onSeriesDiscovered: (segment) => this.RecordSeriesSegment(rItem.id, segment),
|
|
32205
|
+
simulation: this.simulation
|
|
30354
32206
|
});
|
|
30355
32207
|
break;
|
|
30356
32208
|
case BModels.MenuItem.EType.EntitiesLoaded:
|
|
@@ -30359,7 +32211,8 @@
|
|
|
30359
32211
|
register: this.visualsRegister,
|
|
30360
32212
|
apiGetter: params.apiGetter,
|
|
30361
32213
|
monitor: this.sharedMonitor,
|
|
30362
|
-
item: params.item
|
|
32214
|
+
item: params.item,
|
|
32215
|
+
simulation: this.simulation
|
|
30363
32216
|
});
|
|
30364
32217
|
break;
|
|
30365
32218
|
case BModels.MenuItem.EType.EntitiesIds:
|
|
@@ -30369,7 +32222,8 @@
|
|
|
30369
32222
|
apiGetter: params.apiGetter,
|
|
30370
32223
|
monitor: this.sharedMonitor,
|
|
30371
32224
|
item: params.item,
|
|
30372
|
-
sharedHistoric: this.sharedHistoric
|
|
32225
|
+
sharedHistoric: this.sharedHistoric,
|
|
32226
|
+
simulation: this.simulation
|
|
30373
32227
|
});
|
|
30374
32228
|
break;
|
|
30375
32229
|
case BModels.MenuItem.EType.Entity:
|
|
@@ -30378,7 +32232,8 @@
|
|
|
30378
32232
|
register: this.visualsRegister,
|
|
30379
32233
|
apiGetter: params.apiGetter,
|
|
30380
32234
|
monitor: this.sharedMonitor,
|
|
30381
|
-
item: params.item
|
|
32235
|
+
item: params.item,
|
|
32236
|
+
simulation: this.simulation
|
|
30382
32237
|
});
|
|
30383
32238
|
break;
|
|
30384
32239
|
case BModels.MenuItem.EType.CadTileset:
|
|
@@ -30388,7 +32243,8 @@
|
|
|
30388
32243
|
getters: this.getters,
|
|
30389
32244
|
item: params.item,
|
|
30390
32245
|
modelSpace: params.modelSpace,
|
|
30391
|
-
initQueue: this.tilesetInitQueue
|
|
32246
|
+
initQueue: this.tilesetInitQueue,
|
|
32247
|
+
simulation: this.simulation
|
|
30392
32248
|
});
|
|
30393
32249
|
break;
|
|
30394
32250
|
case BModels.MenuItem.EType.Assembly:
|
|
@@ -30398,6 +32254,7 @@
|
|
|
30398
32254
|
getters: params.getters,
|
|
30399
32255
|
item: params.item,
|
|
30400
32256
|
modelSpace: params.modelSpace,
|
|
32257
|
+
simulation: this.simulation
|
|
30401
32258
|
});
|
|
30402
32259
|
break;
|
|
30403
32260
|
case BModels.MenuItem.EType.Osm:
|
|
@@ -30425,7 +32282,8 @@
|
|
|
30425
32282
|
getters: this.getters,
|
|
30426
32283
|
monitor: this.sharedMonitor,
|
|
30427
32284
|
item: params.item,
|
|
30428
|
-
initQueue: this.tilesetInitQueue
|
|
32285
|
+
initQueue: this.tilesetInitQueue,
|
|
32286
|
+
simulation: this.simulation
|
|
30429
32287
|
});
|
|
30430
32288
|
break;
|
|
30431
32289
|
case BModels.MenuItem.EType.Kml:
|
|
@@ -30449,7 +32307,8 @@
|
|
|
30449
32307
|
getters: params.getters,
|
|
30450
32308
|
item: params.item,
|
|
30451
32309
|
viewer: this.viewer,
|
|
30452
|
-
register: this.visualsRegister
|
|
32310
|
+
register: this.visualsRegister,
|
|
32311
|
+
simulation: this.simulation
|
|
30453
32312
|
});
|
|
30454
32313
|
break;
|
|
30455
32314
|
// Deprecated to support a few demos until new one is phased in.
|
|
@@ -30459,7 +32318,8 @@
|
|
|
30459
32318
|
apiGetter: params.apiGetter,
|
|
30460
32319
|
item: params.item,
|
|
30461
32320
|
register: this.visualsRegister,
|
|
30462
|
-
viewer: this.viewer
|
|
32321
|
+
viewer: this.viewer,
|
|
32322
|
+
simulation: this.simulation
|
|
30463
32323
|
});
|
|
30464
32324
|
break;
|
|
30465
32325
|
case BModels.MenuItem.EType.Relationships:
|
|
@@ -30467,7 +32327,8 @@
|
|
|
30467
32327
|
apiGetter: params.apiGetter,
|
|
30468
32328
|
item: params.item,
|
|
30469
32329
|
register: this.visualsRegister,
|
|
30470
|
-
viewer: this.viewer
|
|
32330
|
+
viewer: this.viewer,
|
|
32331
|
+
simulation: this.simulation
|
|
30471
32332
|
});
|
|
30472
32333
|
break;
|
|
30473
32334
|
case BModels.MenuItem.EType.GooglePhotoTileset:
|
|
@@ -30499,7 +32360,8 @@
|
|
|
30499
32360
|
item: params.item,
|
|
30500
32361
|
apiGetter: params.apiGetter,
|
|
30501
32362
|
monitor: this.sharedMonitor,
|
|
30502
|
-
visualsRegister: this.visualsRegister
|
|
32363
|
+
visualsRegister: this.visualsRegister,
|
|
32364
|
+
simulation: this.simulation
|
|
30503
32365
|
});
|
|
30504
32366
|
break;
|
|
30505
32367
|
// Any "none" type can be ignored. These are just containers for other items.
|
|
@@ -30526,7 +32388,17 @@
|
|
|
30526
32388
|
// We no longer support folder items being both a folder and an action.
|
|
30527
32389
|
// Now an item must have no action to be a folder.
|
|
30528
32390
|
const isFolder = !params.item.Type || params.item.Type == BModels.MenuItem.EType.None;
|
|
30529
|
-
|
|
32391
|
+
const isRadioFolder = isFolder && Boolean(params.item.childrenAsRadios);
|
|
32392
|
+
if (((_f = params.item.Children) === null || _f === void 0 ? void 0 : _f.length) && params.recursive != false && isRadioFolder) {
|
|
32393
|
+
const picked = this.pickRadioChild(params.item.Children, params.preferredIds);
|
|
32394
|
+
const others = params.item.Children.filter(x => x !== picked && this.items.some(y => y.id === x.id));
|
|
32395
|
+
const childId = this.renderInPlaceOf(others.map(x => x.id), () => this.RenderItem({
|
|
32396
|
+
...params,
|
|
32397
|
+
item: picked
|
|
32398
|
+
}));
|
|
32399
|
+
rItem.childIds = childId ? [childId] : [];
|
|
32400
|
+
}
|
|
32401
|
+
else if (params.item.Children && params.recursive != false && isFolder) {
|
|
30530
32402
|
for (let i = 0; i < params.item.Children.length; i++) {
|
|
30531
32403
|
const childId = this.RenderItem({
|
|
30532
32404
|
...params,
|
|
@@ -30535,8 +32407,8 @@
|
|
|
30535
32407
|
rItem.childIds.push(childId);
|
|
30536
32408
|
}
|
|
30537
32409
|
}
|
|
30538
|
-
if (rItem.renderManager && !((
|
|
30539
|
-
(
|
|
32410
|
+
if (rItem.renderManager && !((_g = rItem.renderManager) === null || _g === void 0 ? void 0 : _g.Disposed)) {
|
|
32411
|
+
(_h = this.onUpdate) === null || _h === void 0 ? void 0 : _h.Trigger({ isEnabling: true, itemId: rItem.id });
|
|
30540
32412
|
}
|
|
30541
32413
|
return rItem.id;
|
|
30542
32414
|
}
|
|
@@ -30585,9 +32457,74 @@
|
|
|
30585
32457
|
(_b = this.onUpdate) === null || _b === void 0 ? void 0 : _b.Trigger({ isEnabling: false, itemId: item.id });
|
|
30586
32458
|
}
|
|
30587
32459
|
}
|
|
32460
|
+
/**
|
|
32461
|
+
* Replaces enabled menu items with another, which reuses their graphics where both draw the same data.
|
|
32462
|
+
*/
|
|
32463
|
+
SwapItem(params) {
|
|
32464
|
+
const { fromIds, item, modelSpace } = params;
|
|
32465
|
+
const parents = this.items.filter(x => x.childIds.some(id => fromIds.includes(id)));
|
|
32466
|
+
const id = this.renderInPlaceOf(fromIds, () => this.RenderItem({
|
|
32467
|
+
item,
|
|
32468
|
+
modelSpace
|
|
32469
|
+
}));
|
|
32470
|
+
// Keeps a radio folder's removal reaching the child that replaced its old one.
|
|
32471
|
+
for (const parent of parents) {
|
|
32472
|
+
const kept = parent.childIds.filter(x => !fromIds.includes(x));
|
|
32473
|
+
parent.childIds = id && !kept.includes(id) ? kept.concat(id) : kept;
|
|
32474
|
+
}
|
|
32475
|
+
return id;
|
|
32476
|
+
}
|
|
32477
|
+
/**
|
|
32478
|
+
* Restyles an enabled menu item in place with another of its own styles, returning false when it cannot.
|
|
32479
|
+
*/
|
|
32480
|
+
SetItemStyle(params) {
|
|
32481
|
+
var _a;
|
|
32482
|
+
const { menuItemId, styleId } = params;
|
|
32483
|
+
const rItem = this.items.find(x => x.id === menuItemId);
|
|
32484
|
+
if (!rItem || !this.isStyleSwapCapable(rItem.renderManager) || rItem.renderManager.Disposed) {
|
|
32485
|
+
return false;
|
|
32486
|
+
}
|
|
32487
|
+
const next = exports.MenuItemStyles.WithStyleId(rItem.item, styleId);
|
|
32488
|
+
if (!next) {
|
|
32489
|
+
return false;
|
|
32490
|
+
}
|
|
32491
|
+
rItem.renderManager.SwapStyle(next);
|
|
32492
|
+
rItem.item = next;
|
|
32493
|
+
(_a = this.onUpdate) === null || _a === void 0 ? void 0 : _a.Trigger({ isEnabling: true, itemId: rItem.id });
|
|
32494
|
+
return true;
|
|
32495
|
+
}
|
|
32496
|
+
/*
|
|
32497
|
+
* Picks the child the caller asked for, else the one already enabled, else the first.
|
|
32498
|
+
*/
|
|
32499
|
+
pickRadioChild(children, preferredIds) {
|
|
32500
|
+
var _a, _b;
|
|
32501
|
+
return ((_b = (_a = children.find(x => preferredIds === null || preferredIds === void 0 ? void 0 : preferredIds.includes(x.id))) !== null && _a !== void 0 ? _a : children.find(x => this.items.some(y => y.id === x.id))) !== null && _b !== void 0 ? _b : children[0]);
|
|
32502
|
+
}
|
|
32503
|
+
/*
|
|
32504
|
+
* Removes the items so the render can claim their graphics, then disposes whatever it left unclaimed.
|
|
32505
|
+
*/
|
|
32506
|
+
renderInPlaceOf(removeIds, render) {
|
|
32507
|
+
const pooledBefore = new Set(this.pendingHandoffPool);
|
|
32508
|
+
for (const id of removeIds) {
|
|
32509
|
+
this.RemoveItemById({
|
|
32510
|
+
menuItemId: id,
|
|
32511
|
+
allowHandoff: true
|
|
32512
|
+
});
|
|
32513
|
+
}
|
|
32514
|
+
const pooled = this.pendingHandoffPool.filter(x => !pooledBefore.has(x));
|
|
32515
|
+
try {
|
|
32516
|
+
return render();
|
|
32517
|
+
}
|
|
32518
|
+
finally {
|
|
32519
|
+
this.disposePooled(x => pooled.includes(x));
|
|
32520
|
+
}
|
|
32521
|
+
}
|
|
30588
32522
|
isHandoffCapable(renderManager) {
|
|
30589
32523
|
return Boolean(renderManager) && typeof renderManager.PrepareHandoff === "function";
|
|
30590
32524
|
}
|
|
32525
|
+
isStyleSwapCapable(renderManager) {
|
|
32526
|
+
return Boolean(renderManager) && typeof renderManager.SwapStyle === "function";
|
|
32527
|
+
}
|
|
30591
32528
|
// Resolves the hand-off key a menu item's data would have.
|
|
30592
32529
|
computeHandoffKey(item, modelSpace) {
|
|
30593
32530
|
if (item.Type === BModels.MenuItem.EType.CadTileset) {
|
|
@@ -30663,12 +32600,15 @@
|
|
|
30663
32600
|
}
|
|
30664
32601
|
// Disposes everything left unclaimed in the pending-hand-off pool.
|
|
30665
32602
|
FlushPendingHandoffs() {
|
|
32603
|
+
this.disposePooled(() => true);
|
|
32604
|
+
}
|
|
32605
|
+
disposePooled(match) {
|
|
30666
32606
|
var _a;
|
|
30667
32607
|
if (!this.pendingHandoffPool.length) {
|
|
30668
32608
|
return;
|
|
30669
32609
|
}
|
|
30670
|
-
const pool = this.pendingHandoffPool;
|
|
30671
|
-
this.pendingHandoffPool =
|
|
32610
|
+
const pool = this.pendingHandoffPool.filter(match);
|
|
32611
|
+
this.pendingHandoffPool = this.pendingHandoffPool.filter(x => !match(x));
|
|
30672
32612
|
for (const item of pool) {
|
|
30673
32613
|
try {
|
|
30674
32614
|
(_a = item.renderManager) === null || _a === void 0 ? void 0 : _a.Dispose();
|
|
@@ -30679,6 +32619,26 @@
|
|
|
30679
32619
|
this.ClearSeriesSegments(item.id);
|
|
30680
32620
|
}
|
|
30681
32621
|
}
|
|
32622
|
+
/**
|
|
32623
|
+
* Returns the tags and attenuation the item's view authored, before any bookmark wrote over them.
|
|
32624
|
+
*/
|
|
32625
|
+
GetAuthoredAlternation(item) {
|
|
32626
|
+
var _a;
|
|
32627
|
+
let authored = this.authoredAlternations.get(item);
|
|
32628
|
+
if (!authored) {
|
|
32629
|
+
const eItem = item;
|
|
32630
|
+
const tItem = item;
|
|
32631
|
+
authored = JSON.parse(JSON.stringify({
|
|
32632
|
+
id: item.id,
|
|
32633
|
+
Type: item.Type,
|
|
32634
|
+
BruceEntity: { SelectedExpandLayers: (_a = eItem.BruceEntity) === null || _a === void 0 ? void 0 : _a.SelectedExpandLayers },
|
|
32635
|
+
attenuation: tItem.attenuation,
|
|
32636
|
+
attenuationMax: tItem.attenuationMax
|
|
32637
|
+
}));
|
|
32638
|
+
this.authoredAlternations.set(item, authored);
|
|
32639
|
+
}
|
|
32640
|
+
return authored;
|
|
32641
|
+
}
|
|
30682
32642
|
GetEnabledItemIds() {
|
|
30683
32643
|
return this.items.map(x => x.id);
|
|
30684
32644
|
}
|
|
@@ -30712,6 +32672,63 @@
|
|
|
30712
32672
|
}
|
|
30713
32673
|
}
|
|
30714
32674
|
}
|
|
32675
|
+
/**
|
|
32676
|
+
* Draws Entities from data given here as well as, or instead of, the API's, until ClearSimulation is called.
|
|
32677
|
+
* @param params.set the simulation this belongs to, so it can be cleared apart from others. Default "default".
|
|
32678
|
+
* @param params.entities stand-ins that replace each Entity's record; API data for them is ignored.
|
|
32679
|
+
* @param params.patches partial Entities laid over each Entity; live API data shows where a patch is silent.
|
|
32680
|
+
* @param params.records historic records naming entityId, dateTime and only the data they change.
|
|
32681
|
+
* @param params.menuItemIds the items to redraw. By default every item already drawing one of the Entities.
|
|
32682
|
+
*/
|
|
32683
|
+
async Simulate(params) {
|
|
32684
|
+
const { set, entities, patches, records, menuItemIds } = params;
|
|
32685
|
+
this.simulation.SetEntities(entities, set);
|
|
32686
|
+
this.simulation.SetPatches(patches, set);
|
|
32687
|
+
this.simulation.SetRecords(records, set);
|
|
32688
|
+
const entityIds = [
|
|
32689
|
+
...(entities || []).map(x => { var _a; return (_a = x === null || x === void 0 ? void 0 : x.Bruce) === null || _a === void 0 ? void 0 : _a.ID; }),
|
|
32690
|
+
...(patches || []).map(x => { var _a; return (_a = x === null || x === void 0 ? void 0 : x.Bruce) === null || _a === void 0 ? void 0 : _a.ID; }),
|
|
32691
|
+
...(records || []).map(x => x === null || x === void 0 ? void 0 : x.entityId)
|
|
32692
|
+
];
|
|
32693
|
+
await this.reRenderSimulated(entityIds, menuItemIds);
|
|
32694
|
+
}
|
|
32695
|
+
/**
|
|
32696
|
+
* Stops simulating these Entities, or every Entity when none are named, and redraws them.
|
|
32697
|
+
* @param params.set the simulation to clear. By default every one.
|
|
32698
|
+
* @param params.entities clear the stand-ins and patches. Default true.
|
|
32699
|
+
* @param params.records clear the historic records. Default true.
|
|
32700
|
+
*/
|
|
32701
|
+
async ClearSimulation(params) {
|
|
32702
|
+
var _a;
|
|
32703
|
+
const entityIds = (_a = params === null || params === void 0 ? void 0 : params.entityIds) !== null && _a !== void 0 ? _a : [
|
|
32704
|
+
...this.simulation.GetEntityIds(),
|
|
32705
|
+
...this.simulation.GetRecordEntityIds()
|
|
32706
|
+
];
|
|
32707
|
+
this.simulation.Clear({ set: params === null || params === void 0 ? void 0 : params.set, entityIds, entities: params === null || params === void 0 ? void 0 : params.entities, records: params === null || params === void 0 ? void 0 : params.records });
|
|
32708
|
+
await this.reRenderSimulated(entityIds, params === null || params === void 0 ? void 0 : params.menuItemIds);
|
|
32709
|
+
}
|
|
32710
|
+
/*
|
|
32711
|
+
* Redraws simulated Entities only in the items holding a visual for them, unless the caller names the items.
|
|
32712
|
+
*/
|
|
32713
|
+
async reRenderSimulated(entityIds, menuItemIds) {
|
|
32714
|
+
const ids = Array.from(new Set(entityIds.filter(x => !!x)));
|
|
32715
|
+
if (!ids.length) {
|
|
32716
|
+
return;
|
|
32717
|
+
}
|
|
32718
|
+
const items = (menuItemIds === null || menuItemIds === void 0 ? void 0 : menuItemIds.length) ? this.items.filter(x => menuItemIds.includes(x.id)) : this.items;
|
|
32719
|
+
for (const item of items) {
|
|
32720
|
+
// Some managers follow the store themselves, and redrawing them here would only repeat that.
|
|
32721
|
+
if (!item.renderManager || item.renderManager.FollowsSimulation) {
|
|
32722
|
+
continue;
|
|
32723
|
+
}
|
|
32724
|
+
const drawn = (menuItemIds === null || menuItemIds === void 0 ? void 0 : menuItemIds.length)
|
|
32725
|
+
? ids
|
|
32726
|
+
: ids.filter(id => this.visualsRegister.GetRego({ entityId: id, menuItemId: item.id }));
|
|
32727
|
+
if (drawn.length) {
|
|
32728
|
+
await item.renderManager.ReRender({ entityIds: drawn, force: true });
|
|
32729
|
+
}
|
|
32730
|
+
}
|
|
32731
|
+
}
|
|
30715
32732
|
}
|
|
30716
32733
|
MenuItemManager.Manager = Manager;
|
|
30717
32734
|
})(exports.MenuItemManager || (exports.MenuItemManager = {}));
|
|
@@ -31685,6 +33702,7 @@
|
|
|
31685
33702
|
})(exports.EMenuItemState || (exports.EMenuItemState = {}));
|
|
31686
33703
|
// Icons are inline so the library stays dependency free.
|
|
31687
33704
|
const ICON_CHECK = `<svg viewBox="0 0 11 8" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 4L4 7L10 1" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
33705
|
+
const ICON_RADIO = `<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" r="3.5" fill="white"/></svg>`;
|
|
31688
33706
|
const ICON_PARTIAL_CHECK = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 12H16" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
31689
33707
|
const ICON_CHEV_DOWN = `<svg viewBox="0 0 16 9" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15 1L8 8L1 1" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
31690
33708
|
const ICON_CHEV_RIGHT = `<svg viewBox="0 0 10 17" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.5 1.5L8.5 8.5L1.5 15.5" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
|
@@ -31888,6 +33906,10 @@
|
|
|
31888
33906
|
margin-right: 8px;
|
|
31889
33907
|
}
|
|
31890
33908
|
|
|
33909
|
+
.NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowCheckbox[is-radio="true"] {
|
|
33910
|
+
border-radius: 50%;
|
|
33911
|
+
}
|
|
33912
|
+
|
|
31891
33913
|
.NextspaceMenuItemRow >.NextspaceMenuItemRowItem >.NextspaceMenuItemRowToggle {
|
|
31892
33914
|
margin-right: 3px;
|
|
31893
33915
|
}
|
|
@@ -32138,13 +34160,15 @@
|
|
|
32138
34160
|
}
|
|
32139
34161
|
return this._waitedForView ? "No view is loaded." : "Loading..";
|
|
32140
34162
|
}
|
|
32141
|
-
_renderRow(item, depth, parent) {
|
|
34163
|
+
_renderRow(item, depth, parent, radioParent) {
|
|
32142
34164
|
var _a;
|
|
32143
34165
|
if (!(item === null || item === void 0 ? void 0 : item.id)) {
|
|
32144
34166
|
return;
|
|
32145
34167
|
}
|
|
32146
34168
|
const isFolder = !item.Type || item.Type === BModels.MenuItem.EType.None;
|
|
32147
|
-
const
|
|
34169
|
+
const isRadioFolder = isFolder && Boolean(item.childrenAsRadios);
|
|
34170
|
+
// Radios are the folder's whole point, so they show even when the folder also hides its children.
|
|
34171
|
+
const children = item.hideChildren && !isRadioFolder ? [] : ((_a = item.Children) !== null && _a !== void 0 ? _a : []);
|
|
32148
34172
|
const hasChildren = children.length > 0;
|
|
32149
34173
|
const row = document.createElement("div");
|
|
32150
34174
|
row.className = "NextspaceMenuItemRow";
|
|
@@ -32176,8 +34200,9 @@
|
|
|
32176
34200
|
}
|
|
32177
34201
|
const checkbox = document.createElement("div");
|
|
32178
34202
|
checkbox.className = "NextspaceMenuItemRowCheckbox";
|
|
34203
|
+
checkbox.setAttribute("is-radio", radioParent ? "true" : "false");
|
|
32179
34204
|
checkbox.onclick = () => {
|
|
32180
|
-
this._toggleItem(item);
|
|
34205
|
+
this._toggleItem(item, radioParent);
|
|
32181
34206
|
};
|
|
32182
34207
|
itemElement.appendChild(checkbox);
|
|
32183
34208
|
const title = document.createElement("div");
|
|
@@ -32227,10 +34252,11 @@
|
|
|
32227
34252
|
itemElement,
|
|
32228
34253
|
checkboxElement: checkbox,
|
|
32229
34254
|
countElement: count,
|
|
32230
|
-
childrenElement
|
|
34255
|
+
childrenElement,
|
|
34256
|
+
radioParent
|
|
32231
34257
|
});
|
|
32232
34258
|
for (const child of children) {
|
|
32233
|
-
this._renderRow(child, depth + 1, childrenElement);
|
|
34259
|
+
this._renderRow(child, depth + 1, childrenElement, isRadioFolder ? item : undefined);
|
|
32234
34260
|
}
|
|
32235
34261
|
}
|
|
32236
34262
|
_getOpen(itemId, depth) {
|
|
@@ -32265,7 +34291,10 @@
|
|
|
32265
34291
|
for (const row of Array.from(this._rows.values())) {
|
|
32266
34292
|
const state = this._resolveState(row.item, enabledIds);
|
|
32267
34293
|
row.itemElement.setAttribute("is-enabled", state === exports.EMenuItemState.Disabled ? "false" : "true");
|
|
32268
|
-
if (state
|
|
34294
|
+
if (row.radioParent && state !== exports.EMenuItemState.Disabled) {
|
|
34295
|
+
row.checkboxElement.innerHTML = ICON_RADIO;
|
|
34296
|
+
}
|
|
34297
|
+
else if (state === exports.EMenuItemState.Enabled) {
|
|
32269
34298
|
row.checkboxElement.innerHTML = ICON_CHECK;
|
|
32270
34299
|
}
|
|
32271
34300
|
else if (state === exports.EMenuItemState.ChildEnabled) {
|
|
@@ -32280,17 +34309,33 @@
|
|
|
32280
34309
|
* Works out a single item's state, rolling up children so a folder can report a partial state.
|
|
32281
34310
|
*/
|
|
32282
34311
|
_resolveState(item, enabledIds) {
|
|
32283
|
-
var _a;
|
|
34312
|
+
var _a, _b;
|
|
32284
34313
|
const isFolder = !item.Type || item.Type === BModels.MenuItem.EType.None;
|
|
32285
34314
|
if (!isFolder) {
|
|
32286
34315
|
return enabledIds.has(item.id) ? exports.EMenuItemState.Enabled : exports.EMenuItemState.Disabled;
|
|
32287
34316
|
}
|
|
34317
|
+
// Only one radio is ever enabled, so the folder is as enabled as that one.
|
|
34318
|
+
if (item.childrenAsRadios && ((_a = item.Children) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
34319
|
+
const states = item.Children.map(x => this._resolveState(x, enabledIds));
|
|
34320
|
+
if (states.includes(exports.EMenuItemState.Enabled)) {
|
|
34321
|
+
return exports.EMenuItemState.Enabled;
|
|
34322
|
+
}
|
|
34323
|
+
return states.includes(exports.EMenuItemState.ChildEnabled) ? exports.EMenuItemState.ChildEnabled : exports.EMenuItemState.Disabled;
|
|
34324
|
+
}
|
|
32288
34325
|
// Folders derive from the leaves below them rather than their own enabled flag.
|
|
32289
34326
|
let actionCount = 0;
|
|
32290
34327
|
let enabledActionCount = 0;
|
|
32291
34328
|
const traverse = (current) => {
|
|
32292
|
-
var _a;
|
|
34329
|
+
var _a, _b;
|
|
32293
34330
|
const currentIsFolder = !current.Type || current.Type === BModels.MenuItem.EType.None;
|
|
34331
|
+
// A radio folder counts as one choice rather than as each of its radios.
|
|
34332
|
+
if (currentIsFolder && current.childrenAsRadios && ((_a = current.Children) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
34333
|
+
actionCount += 1;
|
|
34334
|
+
if (this._resolveState(current, enabledIds) === exports.EMenuItemState.Enabled) {
|
|
34335
|
+
enabledActionCount += 1;
|
|
34336
|
+
}
|
|
34337
|
+
return;
|
|
34338
|
+
}
|
|
32294
34339
|
if (!currentIsFolder) {
|
|
32295
34340
|
actionCount += 1;
|
|
32296
34341
|
if (enabledIds.has(current.id)) {
|
|
@@ -32298,11 +34343,11 @@
|
|
|
32298
34343
|
}
|
|
32299
34344
|
return;
|
|
32300
34345
|
}
|
|
32301
|
-
if ((
|
|
34346
|
+
if ((_b = current.Children) === null || _b === void 0 ? void 0 : _b.length) {
|
|
32302
34347
|
current.Children.forEach(traverse);
|
|
32303
34348
|
}
|
|
32304
34349
|
};
|
|
32305
|
-
(
|
|
34350
|
+
(_b = item.Children) === null || _b === void 0 ? void 0 : _b.forEach(traverse);
|
|
32306
34351
|
if (actionCount <= 0) {
|
|
32307
34352
|
return enabledIds.has(item.id) ? exports.EMenuItemState.Enabled : exports.EMenuItemState.Disabled;
|
|
32308
34353
|
}
|
|
@@ -32328,7 +34373,7 @@
|
|
|
32328
34373
|
row.countElement.textContent = count.toLocaleString();
|
|
32329
34374
|
}
|
|
32330
34375
|
}
|
|
32331
|
-
_toggleItem(item) {
|
|
34376
|
+
_toggleItem(item, radioParent) {
|
|
32332
34377
|
var _a;
|
|
32333
34378
|
const manager = (_a = this._widget) === null || _a === void 0 ? void 0 : _a._getManager();
|
|
32334
34379
|
if (!manager) {
|
|
@@ -32336,7 +34381,21 @@
|
|
|
32336
34381
|
}
|
|
32337
34382
|
const enabledIds = new Set(manager.GetEnabledItemIds());
|
|
32338
34383
|
const state = this._resolveState(item, enabledIds);
|
|
32339
|
-
|
|
34384
|
+
// A radio stays picked until another one is, the folder's own checkbox turns them all off.
|
|
34385
|
+
if (radioParent && state === exports.EMenuItemState.Enabled) {
|
|
34386
|
+
return;
|
|
34387
|
+
}
|
|
34388
|
+
let siblingIds = [];
|
|
34389
|
+
if (radioParent && state === exports.EMenuItemState.Disabled) {
|
|
34390
|
+
siblingIds = radioParent.Children.filter(x => x !== item).flatMap(x => this._getEnabledIdsUnder(x, enabledIds));
|
|
34391
|
+
}
|
|
34392
|
+
if (siblingIds.length) {
|
|
34393
|
+
manager.SwapItem({
|
|
34394
|
+
fromIds: siblingIds,
|
|
34395
|
+
item
|
|
34396
|
+
});
|
|
34397
|
+
}
|
|
34398
|
+
else if (state === exports.EMenuItemState.Enabled) {
|
|
32340
34399
|
this._disableItem(item);
|
|
32341
34400
|
}
|
|
32342
34401
|
else {
|
|
@@ -32346,6 +34405,16 @@
|
|
|
32346
34405
|
}
|
|
32347
34406
|
this._stateQueue.Call(true);
|
|
32348
34407
|
}
|
|
34408
|
+
/*
|
|
34409
|
+
* Returns the highest enabled ids at or below the item, since removing one removes everything under it.
|
|
34410
|
+
*/
|
|
34411
|
+
_getEnabledIdsUnder(item, enabledIds) {
|
|
34412
|
+
var _a;
|
|
34413
|
+
if (enabledIds.has(item.id)) {
|
|
34414
|
+
return [item.id];
|
|
34415
|
+
}
|
|
34416
|
+
return ((_a = item.Children) !== null && _a !== void 0 ? _a : []).flatMap(x => this._getEnabledIdsUnder(x, enabledIds));
|
|
34417
|
+
}
|
|
32349
34418
|
_disableItem(item) {
|
|
32350
34419
|
var _a, _b;
|
|
32351
34420
|
const manager = (_a = this._widget) === null || _a === void 0 ? void 0 : _a._getManager();
|
|
@@ -33874,33 +35943,50 @@
|
|
|
33874
35943
|
}
|
|
33875
35944
|
const renderedItemIds = [];
|
|
33876
35945
|
if ((menuItems === null || menuItems === void 0 ? void 0 : menuItems.length) && (enabledIds === null || enabledIds === void 0 ? void 0 : enabledIds.length)) {
|
|
33877
|
-
const
|
|
35946
|
+
const alternateItems = (item) => {
|
|
35947
|
+
var _a, _b, _c, _d;
|
|
35948
|
+
// The project view menu item contains the instruction to enable tags, the bookmark specifies which ones.
|
|
35949
|
+
if (item.Type == BModels.MenuItem.EType.Entities && ((_a = item.BruceEntity) === null || _a === void 0 ? void 0 : _a.ExpandLayers)) {
|
|
35950
|
+
const eItem = item;
|
|
35951
|
+
// A setting the bookmark leaves out gets the view's own value back, not the last bookmark's.
|
|
35952
|
+
const authored = manager.GetAuthoredAlternation(item);
|
|
35953
|
+
const eItemAlt = alternations[item.id];
|
|
35954
|
+
const tags = (_b = eItemAlt === null || eItemAlt === void 0 ? void 0 : eItemAlt.BruceEntity) === null || _b === void 0 ? void 0 : _b.SelectedExpandLayers;
|
|
35955
|
+
eItem.BruceEntity = {
|
|
35956
|
+
...eItem.BruceEntity,
|
|
35957
|
+
SelectedExpandLayers: tags !== undefined ? tags : (_c = authored.BruceEntity) === null || _c === void 0 ? void 0 : _c.SelectedExpandLayers,
|
|
35958
|
+
};
|
|
35959
|
+
}
|
|
35960
|
+
else if (item.Type == BModels.MenuItem.EType.EntityTileset) {
|
|
35961
|
+
const tItem = item;
|
|
35962
|
+
const authored = manager.GetAuthoredAlternation(item);
|
|
35963
|
+
const tItemAlt = alternations[item.id];
|
|
35964
|
+
const hasAttenuation = (tItemAlt === null || tItemAlt === void 0 ? void 0 : tItemAlt.attenuation) !== undefined || (tItemAlt === null || tItemAlt === void 0 ? void 0 : tItemAlt.attenuationMax) !== undefined;
|
|
35965
|
+
const source = hasAttenuation ? tItemAlt : authored;
|
|
35966
|
+
tItem.attenuation = source.attenuation;
|
|
35967
|
+
tItem.attenuationMax = source.attenuationMax;
|
|
35968
|
+
}
|
|
35969
|
+
(_d = item.Children) === null || _d === void 0 ? void 0 : _d.forEach(alternateItems);
|
|
35970
|
+
};
|
|
35971
|
+
/*
|
|
35972
|
+
* Lays each picked style over a copy, so it never stays on the view's item for a later bookmark.
|
|
35973
|
+
*/
|
|
35974
|
+
const styleItems = (item) => {
|
|
33878
35975
|
var _a;
|
|
33879
|
-
|
|
33880
|
-
|
|
33881
|
-
|
|
33882
|
-
|
|
33883
|
-
const eItem = item;
|
|
33884
|
-
if (eItem.BruceEntity.ExpandLayers) {
|
|
33885
|
-
const eItemAlt = alternations[item.id];
|
|
33886
|
-
eItem.BruceEntity = {
|
|
33887
|
-
...eItem.BruceEntity,
|
|
33888
|
-
SelectedExpandLayers: (_a = eItemAlt.BruceEntity) === null || _a === void 0 ? void 0 : _a.SelectedExpandLayers,
|
|
33889
|
-
};
|
|
33890
|
-
}
|
|
33891
|
-
}
|
|
33892
|
-
else if (item.Type == BModels.MenuItem.EType.EntityTileset) {
|
|
33893
|
-
const tItem = item;
|
|
33894
|
-
const tItemAlt = alternations[item.id];
|
|
33895
|
-
tItem.attenuation = tItemAlt.attenuation;
|
|
33896
|
-
tItem.attenuationMax = tItemAlt.attenuationMax;
|
|
33897
|
-
}
|
|
35976
|
+
let next = alternations[item.id] ? exports.MenuItemStyles.ApplyAlternation(item, alternations[item.id]) : item;
|
|
35977
|
+
const children = (_a = item.Children) === null || _a === void 0 ? void 0 : _a.map(styleItems);
|
|
35978
|
+
if (children === null || children === void 0 ? void 0 : children.some((child, i) => child !== item.Children[i])) {
|
|
35979
|
+
next = { ...next, Children: children };
|
|
33898
35980
|
}
|
|
35981
|
+
return next;
|
|
35982
|
+
};
|
|
35983
|
+
const traverseItems = async (item) => {
|
|
33899
35984
|
if (enabledIds.includes(item.id)) {
|
|
33900
35985
|
const itemId = await manager.RenderItem({
|
|
33901
35986
|
item: item,
|
|
33902
35987
|
getters: getters,
|
|
33903
|
-
modelSpace: contentType === BModels.ProjectViewBookmark.EContentType.WEB_3D_MODEL_SPACE
|
|
35988
|
+
modelSpace: contentType === BModels.ProjectViewBookmark.EContentType.WEB_3D_MODEL_SPACE,
|
|
35989
|
+
preferredIds: enabledIds
|
|
33904
35990
|
});
|
|
33905
35991
|
renderedItemIds.push(itemId);
|
|
33906
35992
|
}
|
|
@@ -33910,8 +35996,11 @@
|
|
|
33910
35996
|
}
|
|
33911
35997
|
}
|
|
33912
35998
|
};
|
|
33913
|
-
|
|
33914
|
-
|
|
35999
|
+
// Tag and attenuation alternations write into the view's items, since Navigator's tag tree reads them back.
|
|
36000
|
+
menuItems.forEach(alternateItems);
|
|
36001
|
+
const styled = menuItems.map(styleItems);
|
|
36002
|
+
for (let i = 0; i < styled.length; i++) {
|
|
36003
|
+
await traverseItems(styled[i]);
|
|
33915
36004
|
}
|
|
33916
36005
|
}
|
|
33917
36006
|
return {
|
|
@@ -39248,6 +41337,7 @@
|
|
|
39248
41337
|
}
|
|
39249
41338
|
class WidgetInfoView extends exports.Widget.AWidget {
|
|
39250
41339
|
constructor(params) {
|
|
41340
|
+
var _a;
|
|
39251
41341
|
super(params);
|
|
39252
41342
|
this.STYLESHEET_ID = "nextspace-info-view-stylesheet";
|
|
39253
41343
|
this._generateStyles();
|
|
@@ -39257,10 +41347,19 @@
|
|
|
39257
41347
|
this._updateInfoView();
|
|
39258
41348
|
}
|
|
39259
41349
|
});
|
|
41350
|
+
// The selected Entity is read once per selection, so a change to its simulation reads it again.
|
|
41351
|
+
this._simulationRemoval = (_a = this._manager.Simulation) === null || _a === void 0 ? void 0 : _a.OnChanged.Subscribe((change) => {
|
|
41352
|
+
if (this._lastSelectedId && change.entityIds.includes(this._lastSelectedId)) {
|
|
41353
|
+
this._lastSelectedId = null;
|
|
41354
|
+
this._updateInfoView();
|
|
41355
|
+
}
|
|
41356
|
+
});
|
|
39260
41357
|
}
|
|
39261
41358
|
Dispose() {
|
|
41359
|
+
var _a;
|
|
39262
41360
|
super.Dispose();
|
|
39263
41361
|
this._updateRemoval();
|
|
41362
|
+
(_a = this._simulationRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
39264
41363
|
}
|
|
39265
41364
|
_generateStyles() {
|
|
39266
41365
|
if (document.getElementById(this.STYLESHEET_ID)) {
|
|
@@ -39722,7 +41821,7 @@
|
|
|
39722
41821
|
}
|
|
39723
41822
|
}
|
|
39724
41823
|
async _updateInfoView() {
|
|
39725
|
-
var
|
|
41824
|
+
var _a, _c, _d, _e, _f;
|
|
39726
41825
|
const selectedIds = this._manager.VisualsRegister.GetSelected();
|
|
39727
41826
|
if (selectedIds.length <= 0) {
|
|
39728
41827
|
this._element.style.display = "none";
|
|
@@ -39744,17 +41843,20 @@
|
|
|
39744
41843
|
this._summary.innerHTML = "";
|
|
39745
41844
|
this._imageContainer.style.display = "none";
|
|
39746
41845
|
const api = this._apiGetters.GetBruceApi();
|
|
39747
|
-
|
|
41846
|
+
// A simulated Entity is shown as simulated: a stand-in as is, a patch over what the API has.
|
|
41847
|
+
const simulation = this._manager.Simulation;
|
|
41848
|
+
let entity = (_a = simulation === null || simulation === void 0 ? void 0 : simulation.GetEntity(firstId)) !== null && _a !== void 0 ? _a : (await BModels.Entity.Get({
|
|
39748
41849
|
entityId: firstId,
|
|
39749
41850
|
api: api,
|
|
39750
41851
|
migrated: true,
|
|
39751
41852
|
expandLocation: DISPLAY_ASSEMBLY_INFO
|
|
39752
|
-
});
|
|
41853
|
+
})).entity;
|
|
41854
|
+
entity = entity && simulation ? simulation.Resolve(firstId, entity) : entity;
|
|
39753
41855
|
if (!entity) {
|
|
39754
41856
|
throw (new Error("Could not get entity."));
|
|
39755
41857
|
}
|
|
39756
41858
|
const { entityType } = await BModels.EntityType.Get({
|
|
39757
|
-
entityTypeId: (
|
|
41859
|
+
entityTypeId: (_c = entity.Bruce) === null || _c === void 0 ? void 0 : _c["EntityType.ID"],
|
|
39758
41860
|
api: api
|
|
39759
41861
|
});
|
|
39760
41862
|
let name = BModels.Entity.CalculateName({
|
|
@@ -39777,7 +41879,7 @@
|
|
|
39777
41879
|
const defaultImage = images.length ? images[0] : null;
|
|
39778
41880
|
if (defaultImage) {
|
|
39779
41881
|
this._imageContainer.style.display = "flex";
|
|
39780
|
-
const url = (
|
|
41882
|
+
const url = (_d = defaultImage.URL) !== null && _d !== void 0 ? _d : BModels.ClientFile.GetUrl({
|
|
39781
41883
|
fileId: defaultImage["ClientFile.ID"],
|
|
39782
41884
|
api: api,
|
|
39783
41885
|
viaCdn: true
|
|
@@ -39790,7 +41892,7 @@
|
|
|
39790
41892
|
this._summary.appendChild(detailsTitle);
|
|
39791
41893
|
// TODO: Selection for what mode instead of always doing "all".
|
|
39792
41894
|
const attributes = gatherAttributes(EMode.ShowAll, entity, entityType);
|
|
39793
|
-
const groups = groupAttributes(attributes, (
|
|
41895
|
+
const groups = groupAttributes(attributes, (_f = (_e = entityType.DataSchema) === null || _e === void 0 ? void 0 : _e.Structure) !== null && _f !== void 0 ? _f : []);
|
|
39794
41896
|
for (const group of groups) {
|
|
39795
41897
|
this._generateAttrGroup(entityType, entity, group);
|
|
39796
41898
|
}
|
|
@@ -42384,7 +44486,7 @@
|
|
|
42384
44486
|
* @param params
|
|
42385
44487
|
*/
|
|
42386
44488
|
async function GetLocation(params) {
|
|
42387
|
-
var _a, _b, _c, _d;
|
|
44489
|
+
var _a, _b, _c, _d, _e;
|
|
42388
44490
|
let { api, viewer, samples, visualRegister, minimumAlt, paddingAlt } = params;
|
|
42389
44491
|
if (!paddingAlt) {
|
|
42390
44492
|
paddingAlt = 0;
|
|
@@ -42932,6 +45034,13 @@
|
|
|
42932
45034
|
recordSamples.push(sample);
|
|
42933
45035
|
}
|
|
42934
45036
|
}
|
|
45037
|
+
// A simulated Entity is where its blob says, never where the API has it.
|
|
45038
|
+
const simulation = exports.EntitySimulation.Get(viewer);
|
|
45039
|
+
for (const sample of recordSamples) {
|
|
45040
|
+
if (!sample.entity && sample.entityId) {
|
|
45041
|
+
sample.entity = (_e = simulation === null || simulation === void 0 ? void 0 : simulation.GetEntity(sample.entityId)) !== null && _e !== void 0 ? _e : sample.entity;
|
|
45042
|
+
}
|
|
45043
|
+
}
|
|
42935
45044
|
// Bulk requesting Entity records.
|
|
42936
45045
|
try {
|
|
42937
45046
|
const toSearchIds = recordSamples.filter(x => !x.entity && x.entityId).map(x => x.entityId);
|
|
@@ -42952,7 +45061,8 @@
|
|
|
42952
45061
|
for (let i = 0; i < recordSamples.length; i++) {
|
|
42953
45062
|
const sample = recordSamples[i];
|
|
42954
45063
|
if (!sample.entity && sample.entityId) {
|
|
42955
|
-
|
|
45064
|
+
const read = entitiesMap.get(sample.entityId);
|
|
45065
|
+
sample.entity = read && simulation ? simulation.Overlay(read) : read;
|
|
42956
45066
|
}
|
|
42957
45067
|
}
|
|
42958
45068
|
}
|
|
@@ -42966,6 +45076,11 @@
|
|
|
42966
45076
|
// We have to detect whatever is an Assembly Entity and expand it.
|
|
42967
45077
|
try {
|
|
42968
45078
|
const needsExpansion = recordSamples.filter(x => {
|
|
45079
|
+
var _a;
|
|
45080
|
+
// Expanding reads the API's record, which would replace the stand-in or undo the patch.
|
|
45081
|
+
if (simulation === null || simulation === void 0 ? void 0 : simulation.HasBlob((_a = x.entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID)) {
|
|
45082
|
+
return false;
|
|
45083
|
+
}
|
|
42969
45084
|
const assemblyPos = BModels.Entity.GetValue({
|
|
42970
45085
|
entity: x.entity,
|
|
42971
45086
|
path: ["Bruce", "AssemblyPosition"]
|
|
@@ -43324,6 +45439,21 @@
|
|
|
43324
45439
|
return Cesium.Quaternion.multiply(combined, _assemblyAxisShift, new Cesium.Quaternion());
|
|
43325
45440
|
}
|
|
43326
45441
|
EntityUtils.GetAssemblyOrientation = GetAssemblyOrientation;
|
|
45442
|
+
/**
|
|
45443
|
+
* Returns the orientation a part's model is drawn with, for its world matrix within the root's frame.
|
|
45444
|
+
* @param rootFrame the root's frame in the world, eg. from Transforms.headingPitchRollToFixedFrame.
|
|
45445
|
+
* @param world the part's matrix within the root's frame.
|
|
45446
|
+
*/
|
|
45447
|
+
function GetAssemblyOrientationInFrame(rootFrame, world) {
|
|
45448
|
+
if (!rootFrame || !world) {
|
|
45449
|
+
return null;
|
|
45450
|
+
}
|
|
45451
|
+
const combined = Cesium.Matrix4.multiply(rootFrame, world, new Cesium.Matrix4());
|
|
45452
|
+
const rotation = Cesium.Matrix4.getRotation(combined, new Cesium.Matrix3());
|
|
45453
|
+
const q = Cesium.Quaternion.fromRotationMatrix(rotation);
|
|
45454
|
+
return Cesium.Quaternion.multiply(q, _assemblyAxisShift, new Cesium.Quaternion());
|
|
45455
|
+
}
|
|
45456
|
+
EntityUtils.GetAssemblyOrientationInFrame = GetAssemblyOrientationInFrame;
|
|
43327
45457
|
/**
|
|
43328
45458
|
* Returns the position of the entity.
|
|
43329
45459
|
* This is an async variant that checks for related assemblies.
|
|
@@ -43333,6 +45463,18 @@
|
|
|
43333
45463
|
*/
|
|
43334
45464
|
async function GetPosAsync(params) {
|
|
43335
45465
|
let { viewer, entityId, entity, visualRegister, returnHeightRef, recordHeightRef, api } = params;
|
|
45466
|
+
// A simulated Entity is where its stand-in says, or where its patch puts the API's record.
|
|
45467
|
+
const simulation = exports.EntitySimulation.Get(viewer);
|
|
45468
|
+
entity = entity !== null && entity !== void 0 ? entity : simulation === null || simulation === void 0 ? void 0 : simulation.GetEntity(entityId);
|
|
45469
|
+
if (!entity && entityId && (simulation === null || simulation === void 0 ? void 0 : simulation.HasBlob(entityId))) {
|
|
45470
|
+
try {
|
|
45471
|
+
const read = (await BModels.Entity.Get({ api, entityId, expandLocation: false, migrated: true })).entity;
|
|
45472
|
+
entity = read ? simulation.Overlay(read) : null;
|
|
45473
|
+
}
|
|
45474
|
+
catch (e) {
|
|
45475
|
+
console.error(e);
|
|
45476
|
+
}
|
|
45477
|
+
}
|
|
43336
45478
|
// We have issues where imported BRZ files have improper expandLocation=true info.
|
|
43337
45479
|
// As a result we'll double-request the data.
|
|
43338
45480
|
// If there is a location then we won't bother using expanded information.
|
|
@@ -53294,7 +55436,7 @@ void main() {
|
|
|
53294
55436
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
53295
55437
|
})(exports.StyleUtils || (exports.StyleUtils = {}));
|
|
53296
55438
|
|
|
53297
|
-
const VERSION = "7.6.
|
|
55439
|
+
const VERSION = "7.6.3";
|
|
53298
55440
|
/**
|
|
53299
55441
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
53300
55442
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|