bruce-cesium 7.6.1 → 7.6.2
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 +2031 -343
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +2024 -340
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +2 -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-manager.js +83 -10
- package/dist/lib/rendering/menu-item-manager.js.map +1 -1
- 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 +3 -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 +10 -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 +3 -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 +18 -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 +1 -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 +2 -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 +130 -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 +3 -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/widget-info-view.js +20 -7
- package/dist/lib/widgets/widget-info-view.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +2 -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 +33 -1
- 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 +2 -0
- package/dist/types/rendering/render-managers/entities/entities-ids-render-manager.d.ts +2 -0
- package/dist/types/rendering/render-managers/entities/entities-loaded-render-manager.d.ts +2 -0
- package/dist/types/rendering/render-managers/entities/entities-render-manager.d.ts +2 -0
- package/dist/types/rendering/render-managers/entities/entity-render-manager.d.ts +2 -0
- 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 +4 -0
- package/dist/types/rendering/render-managers/tilesets/tileset-arb-render-manager.d.ts +3 -0
- package/dist/types/rendering/render-managers/tilesets/tileset-cad-render-manager.d.ts +11 -1
- package/dist/types/rendering/render-managers/tilesets/tileset-entities-render-manager.d.ts +3 -0
- 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/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;
|
|
@@ -15767,6 +16399,14 @@
|
|
|
15767
16399
|
*/
|
|
15768
16400
|
this.renderAsIndividualsChain = Promise.resolve();
|
|
15769
16401
|
const { viewer, apiGetter, monitor, item, register: visualsManager, sharedGetters, onSeriesDiscovered } = params;
|
|
16402
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation, () => {
|
|
16403
|
+
// Read at the scene's time only when the item follows history, the same choice its reads make.
|
|
16404
|
+
const bruceEntity = this.item.BruceEntity;
|
|
16405
|
+
if (!(bruceEntity === null || bruceEntity === void 0 ? void 0 : bruceEntity.historic) && !(bruceEntity === null || bruceEntity === void 0 ? void 0 : bruceEntity.historicAttrKey)) {
|
|
16406
|
+
return null;
|
|
16407
|
+
}
|
|
16408
|
+
return { timeMs: Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime(), attrKey: bruceEntity.historicAttrKey };
|
|
16409
|
+
});
|
|
15770
16410
|
this.viewer = viewer;
|
|
15771
16411
|
this.sharedGetters = sharedGetters;
|
|
15772
16412
|
this.monitor = monitor;
|
|
@@ -15780,7 +16420,8 @@
|
|
|
15780
16420
|
getApi: () => this.apiGetter.getApi(),
|
|
15781
16421
|
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
15782
16422
|
// A second either side, to take in records sitting exactly on the boundary.
|
|
15783
|
-
paddingMs: 1000
|
|
16423
|
+
paddingMs: 1000,
|
|
16424
|
+
simulation: params.simulation
|
|
15784
16425
|
});
|
|
15785
16426
|
this.useGeojson = item.renderAsGeojson == true;
|
|
15786
16427
|
if (item.enableClustering) {
|
|
@@ -15961,8 +16602,9 @@
|
|
|
15961
16602
|
return;
|
|
15962
16603
|
}
|
|
15963
16604
|
this.updateAllowedTypeIDs(data.entityTypeSources, data.entities);
|
|
16605
|
+
// The getter answers from the API, so a simulated Entity in its answer is swapped for its blob.
|
|
15964
16606
|
if (isTagItem) {
|
|
15965
|
-
this.distributeForRender(data.entities.filter((entity) => {
|
|
16607
|
+
this.distributeForRender(this.reRenderState.withSimulated(data.entities.filter((entity) => {
|
|
15966
16608
|
let entityTags = entity.Bruce["Layer.ID"];
|
|
15967
16609
|
if (!entityTags) {
|
|
15968
16610
|
entityTags = [];
|
|
@@ -15970,10 +16612,10 @@
|
|
|
15970
16612
|
return entityTags.some((tag) => {
|
|
15971
16613
|
return tagsToRender.indexOf(tag) !== -1;
|
|
15972
16614
|
});
|
|
15973
|
-
}));
|
|
16615
|
+
})));
|
|
15974
16616
|
}
|
|
15975
16617
|
else {
|
|
15976
|
-
this.distributeForRender(data.entities);
|
|
16618
|
+
this.distributeForRender(this.reRenderState.withSimulated(data.entities));
|
|
15977
16619
|
}
|
|
15978
16620
|
});
|
|
15979
16621
|
// Cesium itself handles single-visibility ranges very well.
|
|
@@ -16013,6 +16655,10 @@
|
|
|
16013
16655
|
// Remove regos directly.
|
|
16014
16656
|
if (event.action === "D") {
|
|
16015
16657
|
for (const entityId of affectedIds) {
|
|
16658
|
+
// Deleted in the API, but drawn from its simulation until that is cleared.
|
|
16659
|
+
if (this.reRenderState.isSimulated(entityId)) {
|
|
16660
|
+
continue;
|
|
16661
|
+
}
|
|
16016
16662
|
this.visualsManager.RemoveRegos({
|
|
16017
16663
|
entityId,
|
|
16018
16664
|
menuItemId: this.item.id,
|
|
@@ -17136,7 +17782,6 @@
|
|
|
17136
17782
|
// Highly experimental flag to try improve rendering large sets of polygons and polylines.
|
|
17137
17783
|
// Many things are not supported when this is enabled.
|
|
17138
17784
|
this.useGeojson = false;
|
|
17139
|
-
this.reRenderState = new EntityReRenderMaintainState();
|
|
17140
17785
|
/**
|
|
17141
17786
|
* Our default path.
|
|
17142
17787
|
* We render each entity individually.
|
|
@@ -17146,6 +17791,7 @@
|
|
|
17146
17791
|
*/
|
|
17147
17792
|
this.renderAsIndividualsChain = Promise.resolve();
|
|
17148
17793
|
const { viewer, apiGetter, monitor, item, register: visualsManager } = params;
|
|
17794
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation);
|
|
17149
17795
|
this.viewer = viewer;
|
|
17150
17796
|
this.apiGetter = apiGetter;
|
|
17151
17797
|
this.monitor = monitor;
|
|
@@ -17268,7 +17914,8 @@
|
|
|
17268
17914
|
continue;
|
|
17269
17915
|
}
|
|
17270
17916
|
}
|
|
17271
|
-
|
|
17917
|
+
// The item carries its own Entities, so a simulated one among them is swapped for its blob.
|
|
17918
|
+
this.onGetterUpdate(this.reRenderState.withSimulated(entities));
|
|
17272
17919
|
});
|
|
17273
17920
|
this.getter.Start();
|
|
17274
17921
|
}
|
|
@@ -17910,8 +18557,15 @@
|
|
|
17910
18557
|
this.renderQueueActive = false;
|
|
17911
18558
|
this.renderQueue = [];
|
|
17912
18559
|
this.renderQueueForceFlags = [];
|
|
17913
|
-
this.reRenderState = new EntityReRenderMaintainState();
|
|
17914
18560
|
const { viewer, apiGetter, monitor, item, register: visualsManager } = params;
|
|
18561
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation, () => {
|
|
18562
|
+
// Read at the scene's time only when the item follows history, the same choice its reads make.
|
|
18563
|
+
const bruceEntity = this.item.BruceEntity;
|
|
18564
|
+
if (!(bruceEntity === null || bruceEntity === void 0 ? void 0 : bruceEntity.historic) && !(bruceEntity === null || bruceEntity === void 0 ? void 0 : bruceEntity.historicAttrKey)) {
|
|
18565
|
+
return null;
|
|
18566
|
+
}
|
|
18567
|
+
return { timeMs: Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime(), attrKey: bruceEntity.historicAttrKey };
|
|
18568
|
+
});
|
|
17915
18569
|
this.sharedHistoric = params.sharedHistoric;
|
|
17916
18570
|
this.viewer = viewer;
|
|
17917
18571
|
this.apiGetter = apiGetter;
|
|
@@ -17924,7 +18578,8 @@
|
|
|
17924
18578
|
getApi: () => this.apiGetter.getApi(),
|
|
17925
18579
|
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
17926
18580
|
// Padding either side of a requested range, for clock desync between us and the server.
|
|
17927
|
-
paddingMs: 15000
|
|
18581
|
+
paddingMs: 15000,
|
|
18582
|
+
simulation: params.simulation
|
|
17928
18583
|
});
|
|
17929
18584
|
if (this.item.enableClustering) {
|
|
17930
18585
|
this.clustering = new PointClustering(visualsManager, this.item.id, (_a = this.item) === null || _a === void 0 ? void 0 : _a.clustering);
|
|
@@ -18382,9 +19037,9 @@
|
|
|
18382
19037
|
this.getter = null;
|
|
18383
19038
|
this.getterSub = null;
|
|
18384
19039
|
this.disposed = false;
|
|
18385
|
-
this.reRenderState = new EntityReRenderMaintainState();
|
|
18386
19040
|
this.renderEntityChain = Promise.resolve();
|
|
18387
19041
|
const { viewer, apiGetter, monitor, item, register: visualsManager } = params;
|
|
19042
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation);
|
|
18388
19043
|
this.viewer = viewer;
|
|
18389
19044
|
this.apiGetter = apiGetter;
|
|
18390
19045
|
this.monitor = monitor;
|
|
@@ -18658,6 +19313,122 @@
|
|
|
18658
19313
|
];
|
|
18659
19314
|
})(CodeLogicExceptions || (CodeLogicExceptions = {}));
|
|
18660
19315
|
|
|
19316
|
+
/**
|
|
19317
|
+
* The line drawn through where a moving thing has been, from its history, as a whole path or a fading trail.
|
|
19318
|
+
*/
|
|
19319
|
+
var HistoricTrail;
|
|
19320
|
+
(function (HistoricTrail) {
|
|
19321
|
+
const BANDS = 12;
|
|
19322
|
+
const SAMPLES = 96;
|
|
19323
|
+
const WIDTH_FAR = 1;
|
|
19324
|
+
const ALPHA_FAR = 0.05;
|
|
19325
|
+
// Above 1, so width and alpha hold near the head and give way further back.
|
|
19326
|
+
const WIDTH_CURVE = 1.4;
|
|
19327
|
+
const ALPHA_CURVE = 1.25;
|
|
19328
|
+
// How strongly a line is drawn where it passes behind the globe, against its own alpha.
|
|
19329
|
+
const BEHIND_ALPHA = 0.35;
|
|
19330
|
+
/**
|
|
19331
|
+
* The trail length a menu item asks for in its historicTrackSeconds, or null for the whole path.
|
|
19332
|
+
*/
|
|
19333
|
+
function GetTrailSeconds(item) {
|
|
19334
|
+
const seconds = Number(item === null || item === void 0 ? void 0 : item.historicTrackSeconds);
|
|
19335
|
+
return seconds > 0 ? seconds : null;
|
|
19336
|
+
}
|
|
19337
|
+
HistoricTrail.GetTrailSeconds = GetTrailSeconds;
|
|
19338
|
+
class Trail {
|
|
19339
|
+
constructor(params) {
|
|
19340
|
+
this.entities = [];
|
|
19341
|
+
this.memoTime = null;
|
|
19342
|
+
this.memo = [];
|
|
19343
|
+
this.viewer = params.viewer;
|
|
19344
|
+
const trailing = params.trailSeconds > 0 && Boolean(params.positionAt);
|
|
19345
|
+
if (!trailing) {
|
|
19346
|
+
this.add(params, params.color, params.width, () => { var _a; return (_a = params.getSeries()) !== null && _a !== void 0 ? _a : []; });
|
|
19347
|
+
return;
|
|
19348
|
+
}
|
|
19349
|
+
for (let band = 0; band < BANDS; band++) {
|
|
19350
|
+
// 0 at the head, 1 at the far end.
|
|
19351
|
+
const age = band / (BANDS - 1);
|
|
19352
|
+
const width = params.width - (params.width - WIDTH_FAR) * Math.pow(age, WIDTH_CURVE);
|
|
19353
|
+
const alpha = params.color.alpha - (params.color.alpha - ALPHA_FAR) * Math.pow(age, ALPHA_CURVE);
|
|
19354
|
+
this.add(params, params.color.withAlpha(alpha), Math.max(WIDTH_FAR, width), (time) => {
|
|
19355
|
+
return this.slice(this.sample(params, time), band);
|
|
19356
|
+
});
|
|
19357
|
+
}
|
|
19358
|
+
}
|
|
19359
|
+
/*
|
|
19360
|
+
* One polyline of the trail, its positions read from the scene's time.
|
|
19361
|
+
*/
|
|
19362
|
+
add(params, color, width, positions) {
|
|
19363
|
+
const entity = this.viewer.entities.add({
|
|
19364
|
+
id: BModels.ObjectUtils.UId(15),
|
|
19365
|
+
polyline: {
|
|
19366
|
+
positions: new Cesium.CallbackProperty((time) => positions(time), false),
|
|
19367
|
+
width: width,
|
|
19368
|
+
material: color,
|
|
19369
|
+
clampToGround: params.clampToGround,
|
|
19370
|
+
// A path through the air follows no ellipsoid, so it is drawn as the straight runs it holds.
|
|
19371
|
+
arcType: params.clampToGround ? Cesium.ArcType.GEODESIC : Cesium.ArcType.NONE,
|
|
19372
|
+
// Drawn dimmer behind the globe rather than winking in and out against the terrain along the limb.
|
|
19373
|
+
depthFailMaterial: params.clampToGround ? undefined : color.withAlpha(color.alpha * BEHIND_ALPHA),
|
|
19374
|
+
zIndex: 0,
|
|
19375
|
+
classificationType: params.clampToGround ? Cesium.ClassificationType.BOTH : undefined
|
|
19376
|
+
}
|
|
19377
|
+
});
|
|
19378
|
+
entity._noEdit = true;
|
|
19379
|
+
entity._noSelect = true;
|
|
19380
|
+
exports.CesiumEntityStyler.SetDefaultColor({
|
|
19381
|
+
color: color,
|
|
19382
|
+
entity: entity,
|
|
19383
|
+
viewer: this.viewer,
|
|
19384
|
+
override: true,
|
|
19385
|
+
requestRender: false
|
|
19386
|
+
});
|
|
19387
|
+
this.entities.push(entity);
|
|
19388
|
+
}
|
|
19389
|
+
/*
|
|
19390
|
+
* The trail's positions at a time, newest last, kept for that time so every band reads the same set.
|
|
19391
|
+
*/
|
|
19392
|
+
sample(params, time) {
|
|
19393
|
+
var _a;
|
|
19394
|
+
if (this.memoTime && Cesium.JulianDate.equals(this.memoTime, time)) {
|
|
19395
|
+
return this.memo;
|
|
19396
|
+
}
|
|
19397
|
+
this.memoTime = Cesium.JulianDate.clone(time, (_a = this.memoTime) !== null && _a !== void 0 ? _a : new Cesium.JulianDate());
|
|
19398
|
+
const nowMs = Cesium.JulianDate.toDate(time).getTime();
|
|
19399
|
+
const spanMs = params.trailSeconds * 1000;
|
|
19400
|
+
const points = [];
|
|
19401
|
+
for (let i = 0; i <= SAMPLES; i++) {
|
|
19402
|
+
const pos3d = params.positionAt(nowMs - spanMs + spanMs * i / SAMPLES);
|
|
19403
|
+
if (pos3d) {
|
|
19404
|
+
points.push(pos3d);
|
|
19405
|
+
}
|
|
19406
|
+
}
|
|
19407
|
+
this.memo = points;
|
|
19408
|
+
return points;
|
|
19409
|
+
}
|
|
19410
|
+
/*
|
|
19411
|
+
* A band's run of the samples, counted back from the head, sharing its end point with the next band.
|
|
19412
|
+
*/
|
|
19413
|
+
slice(points, band) {
|
|
19414
|
+
if (points.length < 2) {
|
|
19415
|
+
return [];
|
|
19416
|
+
}
|
|
19417
|
+
const per = (points.length - 1) / BANDS;
|
|
19418
|
+
const end = points.length - 1 - Math.round(band * per);
|
|
19419
|
+
const start = points.length - 1 - Math.round((band + 1) * per);
|
|
19420
|
+
return start < end ? points.slice(Math.max(0, start), end + 1) : [];
|
|
19421
|
+
}
|
|
19422
|
+
Dispose() {
|
|
19423
|
+
for (const entity of this.entities) {
|
|
19424
|
+
RemoveCEntityFromScene(this.viewer, entity);
|
|
19425
|
+
}
|
|
19426
|
+
this.entities = [];
|
|
19427
|
+
}
|
|
19428
|
+
}
|
|
19429
|
+
HistoricTrail.Trail = Trail;
|
|
19430
|
+
})(HistoricTrail || (HistoricTrail = {}));
|
|
19431
|
+
|
|
18661
19432
|
class EntityGatherer {
|
|
18662
19433
|
get OnQueueProgress() {
|
|
18663
19434
|
if (!this._onQueueProgress) {
|
|
@@ -18665,7 +19436,11 @@
|
|
|
18665
19436
|
}
|
|
18666
19437
|
return this._onQueueProgress;
|
|
18667
19438
|
}
|
|
18668
|
-
|
|
19439
|
+
/**
|
|
19440
|
+
* @param simulation what callers simulate in place of API data, used where this gatherer has no override.
|
|
19441
|
+
*/
|
|
19442
|
+
constructor(api, viewer, emitEntities, simulation) {
|
|
19443
|
+
this.simulation = simulation;
|
|
18669
19444
|
this.disposed = false;
|
|
18670
19445
|
this.expandSources = false;
|
|
18671
19446
|
this.historic = null;
|
|
@@ -19242,15 +20017,19 @@
|
|
|
19242
20017
|
}
|
|
19243
20018
|
}
|
|
19244
20019
|
}
|
|
20020
|
+
// A historic read is as at the scene's time, and so is any simulated record laid over it.
|
|
20021
|
+
const rTimeMs = new Date(rTime).getTime();
|
|
20022
|
+
const atPoint = (entity) => this.historic && this.simulation ? this.simulation.ApplyAt(entity, rTimeMs) : entity;
|
|
19245
20023
|
for (const entityId of requestedBatch || []) {
|
|
20024
|
+
// A caller's own override is an unsaved edit, newer than any simulation, so it is used as is.
|
|
19246
20025
|
const override = this.entityDataOverrides.get(entityId);
|
|
19247
20026
|
if (override) {
|
|
19248
20027
|
resolvedEntities.push(override);
|
|
19249
20028
|
continue;
|
|
19250
20029
|
}
|
|
19251
|
-
const found = foundById.get(entityId);
|
|
20030
|
+
const found = this.simulation ? this.simulation.Resolve(entityId, foundById.get(entityId)) : foundById.get(entityId);
|
|
19252
20031
|
if (found) {
|
|
19253
|
-
resolvedEntities.push(found);
|
|
20032
|
+
resolvedEntities.push(atPoint(found));
|
|
19254
20033
|
continue;
|
|
19255
20034
|
}
|
|
19256
20035
|
resolvedEntities.push(this.createFallbackEntity(entityId));
|
|
@@ -19614,7 +20393,7 @@
|
|
|
19614
20393
|
this.styleTilesetFeatureFullData(feature, entity, eTags);
|
|
19615
20394
|
}
|
|
19616
20395
|
}
|
|
19617
|
-
});
|
|
20396
|
+
}, params.simulation);
|
|
19618
20397
|
// Only Entities Sets bake coordinates into their features, so for any other source this
|
|
19619
20398
|
// resolves nothing and the gather stays in insertion order.
|
|
19620
20399
|
this.entityGatherer.SetViewMonitor(this.monitor);
|
|
@@ -21138,6 +21917,9 @@
|
|
|
21138
21917
|
return this.modelTreeUpdate;
|
|
21139
21918
|
}
|
|
21140
21919
|
constructor(params) {
|
|
21920
|
+
this.simulationRemoval = null;
|
|
21921
|
+
// Where the tileset stands by its own record, so a cleared simulation puts it back without a refetch.
|
|
21922
|
+
this.restCoords = null;
|
|
21141
21923
|
this.disposed = false;
|
|
21142
21924
|
this.modelSpace = false;
|
|
21143
21925
|
this.cTileset = null;
|
|
@@ -21175,7 +21957,7 @@
|
|
|
21175
21957
|
this.historicAnimation = null;
|
|
21176
21958
|
this.historicGatherer = null;
|
|
21177
21959
|
// The trail through the root's own movement, which describes the whole assembly.
|
|
21178
|
-
this.
|
|
21960
|
+
this.trail = null;
|
|
21179
21961
|
this.historicPossesLoadingProm = null;
|
|
21180
21962
|
// Queue of loaded in features that we haven't processed yet.
|
|
21181
21963
|
this.featureQueue = [];
|
|
@@ -21189,6 +21971,7 @@
|
|
|
21189
21971
|
this.featurePropCache = new Map();
|
|
21190
21972
|
this.featurePropsChecked = 0;
|
|
21191
21973
|
const { viewer, register: visualsManager, getters, item, modelSpace, initQueue } = params;
|
|
21974
|
+
this.simulation = params.simulation;
|
|
21192
21975
|
this.viewer = viewer;
|
|
21193
21976
|
this.getters = getters;
|
|
21194
21977
|
this.item = item;
|
|
@@ -21353,7 +22136,7 @@
|
|
|
21353
22136
|
historicPoint: this.viewer.clock.currentTime.toString(),
|
|
21354
22137
|
api: api
|
|
21355
22138
|
});
|
|
21356
|
-
coords = coordsFromHistoricEntity(root);
|
|
22139
|
+
coords = coordsFromHistoricEntity(this.atClock(root));
|
|
21357
22140
|
}
|
|
21358
22141
|
catch (e) {
|
|
21359
22142
|
console.error(e);
|
|
@@ -21394,6 +22177,10 @@
|
|
|
21394
22177
|
this.doDispose();
|
|
21395
22178
|
return;
|
|
21396
22179
|
}
|
|
22180
|
+
this.restCoords = coords;
|
|
22181
|
+
if (this.simulatedRootCoords()) {
|
|
22182
|
+
this.applyCoords(tileset, this.simulatedRootCoords());
|
|
22183
|
+
}
|
|
21397
22184
|
this.viewer.scene.requestRender();
|
|
21398
22185
|
exports.TilesetRenderEngine.OnTilesetReady(this.cTileset).then(() => {
|
|
21399
22186
|
var _a, _b, _c;
|
|
@@ -21413,6 +22200,7 @@
|
|
|
21413
22200
|
}
|
|
21414
22201
|
this.onCTilesetLoad();
|
|
21415
22202
|
this.styler.Init({
|
|
22203
|
+
simulation: this.simulation,
|
|
21416
22204
|
viewer: this.viewer,
|
|
21417
22205
|
// Default API instead of the account one.
|
|
21418
22206
|
// Records are driven by the account loading it instead of the source account.
|
|
@@ -21428,6 +22216,7 @@
|
|
|
21428
22216
|
});
|
|
21429
22217
|
this.viewer.scene.requestRender();
|
|
21430
22218
|
// Monitor scene time changes and update the root Entity.
|
|
22219
|
+
this.followSimulation(tileset);
|
|
21431
22220
|
this.viewerDateTimeSub(tileset);
|
|
21432
22221
|
}
|
|
21433
22222
|
catch (e) {
|
|
@@ -21483,7 +22272,7 @@
|
|
|
21483
22272
|
*/
|
|
21484
22273
|
applyRootTrack() {
|
|
21485
22274
|
var _a;
|
|
21486
|
-
if (!this.item.historicDrawTrack || !this.historicAnimation || this.
|
|
22275
|
+
if (!this.item.historicDrawTrack || !this.historicAnimation || this.trail) {
|
|
21487
22276
|
return;
|
|
21488
22277
|
}
|
|
21489
22278
|
const trackStyle = exports.EntityRenderEngine.GetTrackStyle({
|
|
@@ -21493,26 +22282,14 @@
|
|
|
21493
22282
|
if (!trackStyle) {
|
|
21494
22283
|
return;
|
|
21495
22284
|
}
|
|
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,
|
|
22285
|
+
// The series has no position at an arbitrary time, so this draws the whole path rather than a trail.
|
|
22286
|
+
this.trail = new HistoricTrail.Trail({
|
|
21513
22287
|
viewer: this.viewer,
|
|
21514
|
-
|
|
21515
|
-
|
|
22288
|
+
color: trackStyle.color,
|
|
22289
|
+
width: trackStyle.width,
|
|
22290
|
+
clampToGround: exports.EntityRenderEngine.GetHeightRefPolyline(Manager.GetRecordHeightRef(this.item))
|
|
22291
|
+
== Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
22292
|
+
getSeries: () => { var _a, _b; return (_b = (_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.GetSeries()) !== null && _b !== void 0 ? _b : []; }
|
|
21516
22293
|
});
|
|
21517
22294
|
}
|
|
21518
22295
|
/**
|
|
@@ -21565,7 +22342,7 @@
|
|
|
21565
22342
|
}
|
|
21566
22343
|
// Returns null (fall back to a normal Dispose()) if the tileset hasn't finished loading yet.
|
|
21567
22344
|
PrepareHandoff() {
|
|
21568
|
-
var _a, _b, _c, _d;
|
|
22345
|
+
var _a, _b, _c, _d, _e;
|
|
21569
22346
|
if (this.disposed || !this.cTileset || this.cTileset.isDestroyed()) {
|
|
21570
22347
|
return null;
|
|
21571
22348
|
}
|
|
@@ -21583,9 +22360,11 @@
|
|
|
21583
22360
|
this.handoffSourceMenuItemId = null;
|
|
21584
22361
|
// Not transferred, the receiving manager sets up its own fresh copy if needed.
|
|
21585
22362
|
this.viewerDateTimeDispose();
|
|
21586
|
-
(_b = this.
|
|
21587
|
-
|
|
21588
|
-
(
|
|
22363
|
+
(_b = this.simulationRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
22364
|
+
this.simulationRemoval = null;
|
|
22365
|
+
(_c = this.styler) === null || _c === void 0 ? void 0 : _c.Dispose();
|
|
22366
|
+
(_d = this.tileLoadRemoval) === null || _d === void 0 ? void 0 : _d.call(this);
|
|
22367
|
+
(_e = this.tileUnloadRemoval) === null || _e === void 0 ? void 0 : _e.call(this);
|
|
21589
22368
|
this.tileLoadRemoval = null;
|
|
21590
22369
|
this.tileUnloadRemoval = null;
|
|
21591
22370
|
const payload = {
|
|
@@ -21606,7 +22385,7 @@
|
|
|
21606
22385
|
// Takes ownership of a PrepareHandoff() payload instead of loading via Init().
|
|
21607
22386
|
// Then re-parents every already-registered rego to this menu item and re-runs styling.
|
|
21608
22387
|
AdoptHandoff(payload) {
|
|
21609
|
-
var _a, _b, _c, _d;
|
|
22388
|
+
var _a, _b, _c, _d, _e;
|
|
21610
22389
|
this.cTileset = payload.cTileset;
|
|
21611
22390
|
this.tileset = payload.tileset;
|
|
21612
22391
|
this.rootId = payload.rootId;
|
|
@@ -21637,6 +22416,7 @@
|
|
|
21637
22416
|
// Same visuals, same registrations so just re-keyed onto this menu item.
|
|
21638
22417
|
this.onCTilesetLoad();
|
|
21639
22418
|
this.styler.Init({
|
|
22419
|
+
simulation: this.simulation,
|
|
21640
22420
|
viewer: this.viewer,
|
|
21641
22421
|
api: this.getters.GetBruceApi(),
|
|
21642
22422
|
cTileset: this.cTileset,
|
|
@@ -21670,7 +22450,9 @@
|
|
|
21670
22450
|
}
|
|
21671
22451
|
});
|
|
21672
22452
|
this.viewer.scene.requestRender();
|
|
21673
|
-
if (
|
|
22453
|
+
if (this.tileset) {
|
|
22454
|
+
this.restCoords = (_d = this.restCoords) !== null && _d !== void 0 ? _d : (_e = this.cTileset) === null || _e === void 0 ? void 0 : _e._bruceCoords;
|
|
22455
|
+
this.followSimulation(this.tileset);
|
|
21674
22456
|
this.viewerDateTimeSub(this.tileset);
|
|
21675
22457
|
}
|
|
21676
22458
|
}
|
|
@@ -22258,7 +23040,7 @@
|
|
|
22258
23040
|
this.doDispose();
|
|
22259
23041
|
}
|
|
22260
23042
|
doDispose() {
|
|
22261
|
-
var _a, _b, _c;
|
|
23043
|
+
var _a, _b, _c, _d;
|
|
22262
23044
|
if (this.featureQueueInterval) {
|
|
22263
23045
|
clearInterval(this.featureQueueInterval);
|
|
22264
23046
|
this.featureQueueInterval = null;
|
|
@@ -22293,6 +23075,8 @@
|
|
|
22293
23075
|
this.handoffSourceMenuItemId = null;
|
|
22294
23076
|
}
|
|
22295
23077
|
this.viewerDateTimeDispose();
|
|
23078
|
+
(_d = this.simulationRemoval) === null || _d === void 0 ? void 0 : _d.call(this);
|
|
23079
|
+
this.simulationRemoval = null;
|
|
22296
23080
|
}
|
|
22297
23081
|
async ReRender(params) {
|
|
22298
23082
|
let { entityIds, force, entities, maintain } = params;
|
|
@@ -22318,8 +23102,11 @@
|
|
|
22318
23102
|
* @param tileset
|
|
22319
23103
|
*/
|
|
22320
23104
|
viewerDateTimeSub(tileset) {
|
|
22321
|
-
var _a;
|
|
22322
|
-
|
|
23105
|
+
var _a, _b;
|
|
23106
|
+
// An item that is not historic still follows the root's simulated records, once there are some.
|
|
23107
|
+
const historic = Boolean((_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historic);
|
|
23108
|
+
const simulated = Boolean(this.rootId && ((_b = this.simulation) === null || _b === void 0 ? void 0 : _b.GetRecords(this.rootId).length));
|
|
23109
|
+
if ((!historic && !simulated) || this.historicGatherer || this.viewerDateTimeChangeRemoval) {
|
|
22323
23110
|
return;
|
|
22324
23111
|
}
|
|
22325
23112
|
const accountId = this.accountIdForRecords();
|
|
@@ -22348,6 +23135,8 @@
|
|
|
22348
23135
|
// Time padding in milliseconds (15 seconds).
|
|
22349
23136
|
// Helps account for desync between client and server.
|
|
22350
23137
|
paddingMs: 15000,
|
|
23138
|
+
simulation: this.simulation,
|
|
23139
|
+
simulatedOnly: !historic,
|
|
22351
23140
|
onRecords: (recordsByIds) => {
|
|
22352
23141
|
var _a;
|
|
22353
23142
|
const records = recordsByIds[this.rootId];
|
|
@@ -22375,6 +23164,7 @@
|
|
|
22375
23164
|
*/
|
|
22376
23165
|
const getInitialPosses = async () => {
|
|
22377
23166
|
this.historicPossesLoadingProm = new Promise(async (res) => {
|
|
23167
|
+
var _a;
|
|
22378
23168
|
try {
|
|
22379
23169
|
if (this.disposed) {
|
|
22380
23170
|
res(false);
|
|
@@ -22387,11 +23177,16 @@
|
|
|
22387
23177
|
return;
|
|
22388
23178
|
}
|
|
22389
23179
|
// Also request the current position in case its not in the range.
|
|
22390
|
-
|
|
23180
|
+
// A simulated root, or an item that is not historic, has no current record to ask the API for.
|
|
23181
|
+
if (!historic || ((_a = this.simulation) === null || _a === void 0 ? void 0 : _a.HasEntity(this.rootId))) {
|
|
23182
|
+
res(positions);
|
|
23183
|
+
return;
|
|
23184
|
+
}
|
|
23185
|
+
const entity = this.atClock((await BModels.Entity.Get({
|
|
22391
23186
|
entityId: this.rootId,
|
|
22392
23187
|
historicPoint: this.viewer.clock.currentTime.toString(),
|
|
22393
23188
|
api: api
|
|
22394
|
-
});
|
|
23189
|
+
})).entity);
|
|
22395
23190
|
if (this.disposed || !entity) {
|
|
22396
23191
|
res(false);
|
|
22397
23192
|
return;
|
|
@@ -22471,14 +23266,15 @@
|
|
|
22471
23266
|
}
|
|
22472
23267
|
});
|
|
22473
23268
|
this.viewerDateTimeChangeRemoval = () => {
|
|
23269
|
+
var _a, _b;
|
|
22474
23270
|
if (this.historicAnimation) {
|
|
22475
23271
|
this.historicAnimation.stop();
|
|
22476
23272
|
this.historicAnimation = null;
|
|
22477
23273
|
}
|
|
22478
|
-
|
|
22479
|
-
|
|
22480
|
-
|
|
22481
|
-
|
|
23274
|
+
(_a = this.historicGatherer) === null || _a === void 0 ? void 0 : _a.Dispose();
|
|
23275
|
+
this.historicGatherer = null;
|
|
23276
|
+
(_b = this.trail) === null || _b === void 0 ? void 0 : _b.Dispose();
|
|
23277
|
+
this.trail = null;
|
|
22482
23278
|
if (clockTickRemoval) {
|
|
22483
23279
|
clockTickRemoval();
|
|
22484
23280
|
clockTickRemoval = null;
|
|
@@ -22486,10 +23282,84 @@
|
|
|
22486
23282
|
};
|
|
22487
23283
|
});
|
|
22488
23284
|
}
|
|
22489
|
-
|
|
23285
|
+
/*
|
|
23286
|
+
* Keeps the tileset in line with what is simulated for its root Entity.
|
|
23287
|
+
*/
|
|
23288
|
+
followSimulation(tileset) {
|
|
23289
|
+
if (this.simulationRemoval || !this.simulation) {
|
|
23290
|
+
return;
|
|
23291
|
+
}
|
|
23292
|
+
this.simulationRemoval = this.simulation.OnChanged.Subscribe((change) => {
|
|
23293
|
+
var _a;
|
|
23294
|
+
if (this.disposed || !this.rootId || !change.entityIds.includes(this.rootId)) {
|
|
23295
|
+
return;
|
|
23296
|
+
}
|
|
23297
|
+
if (change.records) {
|
|
23298
|
+
this.regatherRoot(tileset);
|
|
23299
|
+
}
|
|
23300
|
+
// A simulated root is where the tileset stands outside its history; recorded positions still win.
|
|
23301
|
+
if (change.entities && !((_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.getDateRange().minDate)) {
|
|
23302
|
+
this.applyRootRest(tileset);
|
|
23303
|
+
}
|
|
23304
|
+
});
|
|
23305
|
+
}
|
|
23306
|
+
/*
|
|
23307
|
+
* Re-reads the root's history after its simulated records changed, following the clock if it was not.
|
|
23308
|
+
*/
|
|
23309
|
+
async regatherRoot(tileset) {
|
|
23310
|
+
var _a;
|
|
23311
|
+
if (!this.historicGatherer) {
|
|
23312
|
+
this.viewerDateTimeSub(tileset);
|
|
23313
|
+
return;
|
|
23314
|
+
}
|
|
23315
|
+
await this.historicPossesLoadingProm;
|
|
23316
|
+
const { recordsByIds } = await this.historicGatherer.Gather([{ Bruce: { ID: this.rootId } }]);
|
|
23317
|
+
if (this.disposed) {
|
|
23318
|
+
return;
|
|
23319
|
+
}
|
|
23320
|
+
const posses = Manager.HistoricPossesFor({ viewer: this.viewer, item: this.item, records: recordsByIds[this.rootId] || [] });
|
|
23321
|
+
(_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.replacePositions(posses);
|
|
23322
|
+
if (!posses.length) {
|
|
23323
|
+
this.applyRootRest(tileset);
|
|
23324
|
+
}
|
|
23325
|
+
}
|
|
23326
|
+
/*
|
|
23327
|
+
* The root as read at the scene's time, with any simulated record at that time laid over it.
|
|
23328
|
+
*/
|
|
23329
|
+
atClock(root) {
|
|
23330
|
+
return this.simulation && root
|
|
23331
|
+
? this.simulation.ApplyAt(root, Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime())
|
|
23332
|
+
: root;
|
|
23333
|
+
}
|
|
23334
|
+
/*
|
|
23335
|
+
* Stands the tileset where its root is outside history: the simulated root, else the root's own record.
|
|
23336
|
+
*/
|
|
23337
|
+
applyRootRest(tileset) {
|
|
22490
23338
|
var _a;
|
|
23339
|
+
this.applyCoords(tileset, (_a = this.simulatedRootCoords()) !== null && _a !== void 0 ? _a : this.restCoords);
|
|
23340
|
+
}
|
|
23341
|
+
/*
|
|
23342
|
+
* Where a simulated root puts the tileset, or null; a patch only places it when it names a whole location.
|
|
23343
|
+
*/
|
|
23344
|
+
simulatedRootCoords() {
|
|
23345
|
+
var _a, _b;
|
|
23346
|
+
const simulation = this.rootId ? this.simulation : null;
|
|
23347
|
+
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);
|
|
23348
|
+
const location = (_b = root === null || root === void 0 ? void 0 : root.Bruce) === null || _b === void 0 ? void 0 : _b.Location;
|
|
23349
|
+
if ((location === null || location === void 0 ? void 0 : location.latitude) == null || (location === null || location === void 0 ? void 0 : location.longitude) == null) {
|
|
23350
|
+
return null;
|
|
23351
|
+
}
|
|
23352
|
+
const pos3d = Cesium.Cartesian3.fromDegrees(+location.longitude, +location.latitude, EnsureNumber(location.altitude, 0));
|
|
23353
|
+
const transform = root.Bruce.Transform;
|
|
23354
|
+
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);
|
|
23355
|
+
}
|
|
23356
|
+
viewerDateTimeDispose() {
|
|
23357
|
+
var _a, _b;
|
|
22491
23358
|
(_a = this.viewerDateTimeChangeRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
22492
23359
|
this.viewerDateTimeChangeRemoval = null;
|
|
23360
|
+
// Made before the first positions land, so it can outlive a removal that was never set.
|
|
23361
|
+
(_b = this.historicGatherer) === null || _b === void 0 ? void 0 : _b.Dispose();
|
|
23362
|
+
this.historicGatherer = null;
|
|
22493
23363
|
}
|
|
22494
23364
|
/**
|
|
22495
23365
|
* Updates the Tileset with latest coordinates.
|
|
@@ -23630,11 +24500,11 @@
|
|
|
23630
24500
|
this.viewMonitorRemoval = null;
|
|
23631
24501
|
this.renderQueue = [];
|
|
23632
24502
|
this.renderQueueInterval = null;
|
|
23633
|
-
this.reRenderState = new EntityReRenderMaintainState();
|
|
23634
24503
|
this.zoomControl = [];
|
|
23635
24504
|
this.queryLoadId = 0;
|
|
23636
24505
|
this.renderDataLabEntitiesChain = Promise.resolve();
|
|
23637
24506
|
const { viewer, item, apiGetter, monitor, visualsRegister } = params;
|
|
24507
|
+
this.reRenderState = new EntityReRenderMaintainState(params.simulation);
|
|
23638
24508
|
this.viewer = viewer;
|
|
23639
24509
|
this.item = item;
|
|
23640
24510
|
this.apiGetter = apiGetter;
|
|
@@ -23731,7 +24601,8 @@
|
|
|
23731
24601
|
if (!((_a = data === null || data === void 0 ? void 0 : data.entities) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
23732
24602
|
return;
|
|
23733
24603
|
}
|
|
23734
|
-
|
|
24604
|
+
// The getter answers from the API, so a simulated Entity in its answer is swapped for its blob.
|
|
24605
|
+
this.distributeForRender(this.reRenderState.withSimulated(data.entities));
|
|
23735
24606
|
});
|
|
23736
24607
|
}
|
|
23737
24608
|
unsetGetter() {
|
|
@@ -25478,6 +26349,7 @@
|
|
|
25478
26349
|
this.featurePropCache = new Map();
|
|
25479
26350
|
this.featurePropsChecked = 0;
|
|
25480
26351
|
const { viewer, register: visualsManager, getters: apiGetter, item, initQueue, monitor } = params;
|
|
26352
|
+
this.simulation = params.simulation;
|
|
25481
26353
|
this.monitor = monitor;
|
|
25482
26354
|
this.viewer = viewer;
|
|
25483
26355
|
this.getters = apiGetter;
|
|
@@ -25578,6 +26450,7 @@
|
|
|
25578
26450
|
if (Manager.NeedsStyler(this.item)) {
|
|
25579
26451
|
const api = this.getters.GetBruceApi();
|
|
25580
26452
|
this.styler.Init({
|
|
26453
|
+
simulation: this.simulation,
|
|
25581
26454
|
viewer: this.viewer,
|
|
25582
26455
|
api: api,
|
|
25583
26456
|
cTileset: this.cTileset,
|
|
@@ -25935,6 +26808,7 @@
|
|
|
25935
26808
|
const needsStyler = Manager.NeedsStyler(this.item);
|
|
25936
26809
|
if (needsStyler) {
|
|
25937
26810
|
this.styler.Init({
|
|
26811
|
+
simulation: this.simulation,
|
|
25938
26812
|
viewer: this.viewer,
|
|
25939
26813
|
api: this.getters.GetBruceApi(),
|
|
25940
26814
|
cTileset: this.cTileset,
|
|
@@ -26619,6 +27493,7 @@
|
|
|
26619
27493
|
// LCC object if we're using XGrids to render LCC data.
|
|
26620
27494
|
this.lccObject = null;
|
|
26621
27495
|
this.viewer = params.viewer;
|
|
27496
|
+
this.simulation = params.simulation;
|
|
26622
27497
|
this.getters = params.getters;
|
|
26623
27498
|
this.visualsManager = params.register;
|
|
26624
27499
|
// We modify the object due to a lot of backwards compatibility.
|
|
@@ -26853,6 +27728,7 @@
|
|
|
26853
27728
|
this.item.Type == BModels.MenuItem.EType.IonTileset) {
|
|
26854
27729
|
const api = this.getters.GetBruceApi();
|
|
26855
27730
|
this.styler.Init({
|
|
27731
|
+
simulation: this.simulation,
|
|
26856
27732
|
viewer: this.viewer,
|
|
26857
27733
|
api: api,
|
|
26858
27734
|
cTileset: this.cTileset,
|
|
@@ -27193,14 +28069,32 @@
|
|
|
27193
28069
|
}
|
|
27194
28070
|
;
|
|
27195
28071
|
constructor(params) {
|
|
28072
|
+
var _a, _b;
|
|
27196
28073
|
// If true, this menu item is disposed and should not be used.
|
|
27197
28074
|
// Any rendering will be ignored.
|
|
27198
28075
|
this.disposed = false;
|
|
28076
|
+
this.simulationRemoval = null;
|
|
28077
|
+
this.FollowsSimulation = true;
|
|
27199
28078
|
const { apiGetter, item, register, viewer } = params;
|
|
27200
28079
|
this.apiGetter = apiGetter;
|
|
27201
28080
|
this.item = item;
|
|
27202
28081
|
this.register = register;
|
|
27203
28082
|
this.viewer = viewer;
|
|
28083
|
+
this.simulation = params.simulation;
|
|
28084
|
+
// Ends are not this item's own Entities, so it watches the store itself rather than wait to be asked.
|
|
28085
|
+
this.simulationRemoval = (_b = (_a = this.simulation) === null || _a === void 0 ? void 0 : _a.OnChanged.Subscribe((change) => {
|
|
28086
|
+
if (this.disposed) {
|
|
28087
|
+
return;
|
|
28088
|
+
}
|
|
28089
|
+
const relations = RelationRenderEngine.TakeRelationsTouching({
|
|
28090
|
+
visualRegister: this.register,
|
|
28091
|
+
menuItemId: this.item.id,
|
|
28092
|
+
entityIds: change.entityIds
|
|
28093
|
+
});
|
|
28094
|
+
if (relations.length) {
|
|
28095
|
+
this.onGetterUpdate(relations);
|
|
28096
|
+
}
|
|
28097
|
+
})) !== null && _b !== void 0 ? _b : null;
|
|
27204
28098
|
}
|
|
27205
28099
|
/**
|
|
27206
28100
|
* Starts rendering the menu item.
|
|
@@ -27269,10 +28163,13 @@
|
|
|
27269
28163
|
return items;
|
|
27270
28164
|
}
|
|
27271
28165
|
Dispose() {
|
|
28166
|
+
var _a;
|
|
27272
28167
|
if (this.disposed) {
|
|
27273
28168
|
return;
|
|
27274
28169
|
}
|
|
27275
28170
|
this.disposed = true;
|
|
28171
|
+
(_a = this.simulationRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
28172
|
+
this.simulationRemoval = null;
|
|
27276
28173
|
this.register.RemoveRegos({
|
|
27277
28174
|
menuItemId: this.item.id
|
|
27278
28175
|
});
|
|
@@ -27511,7 +28408,8 @@
|
|
|
27511
28408
|
menuItemId: this.item.id,
|
|
27512
28409
|
relations: relations,
|
|
27513
28410
|
viewer: this.viewer,
|
|
27514
|
-
visualRegister: this.register
|
|
28411
|
+
visualRegister: this.register,
|
|
28412
|
+
simulation: this.simulation
|
|
27515
28413
|
});
|
|
27516
28414
|
if (this.disposed) {
|
|
27517
28415
|
this.register.RemoveRegos({
|
|
@@ -27793,9 +28691,12 @@
|
|
|
27793
28691
|
}
|
|
27794
28692
|
;
|
|
27795
28693
|
constructor(params) {
|
|
28694
|
+
var _a, _b;
|
|
27796
28695
|
// If true, this menu item is disposed and should not be used.
|
|
27797
28696
|
// Any rendering will be ignored.
|
|
27798
28697
|
this.disposed = false;
|
|
28698
|
+
this.simulationRemoval = null;
|
|
28699
|
+
this.FollowsSimulation = true;
|
|
27799
28700
|
// Record of the currently drawn entity IDs.
|
|
27800
28701
|
// This is to avoid re-queueing already drawn entities when Init is called multiple times.
|
|
27801
28702
|
this.drawnIds = [];
|
|
@@ -27804,6 +28705,21 @@
|
|
|
27804
28705
|
this.item = item;
|
|
27805
28706
|
this.register = register;
|
|
27806
28707
|
this.viewer = viewer;
|
|
28708
|
+
this.simulation = params.simulation;
|
|
28709
|
+
// Ends are not this item's own Entities, so it watches the store itself rather than wait to be asked.
|
|
28710
|
+
this.simulationRemoval = (_b = (_a = this.simulation) === null || _a === void 0 ? void 0 : _a.OnChanged.Subscribe((change) => {
|
|
28711
|
+
if (this.disposed) {
|
|
28712
|
+
return;
|
|
28713
|
+
}
|
|
28714
|
+
const relations = RelationRenderEngine.TakeRelationsTouching({
|
|
28715
|
+
visualRegister: this.register,
|
|
28716
|
+
menuItemId: this.item.id,
|
|
28717
|
+
entityIds: change.entityIds
|
|
28718
|
+
});
|
|
28719
|
+
if (relations.length) {
|
|
28720
|
+
this.onGetterUpdate(relations);
|
|
28721
|
+
}
|
|
28722
|
+
})) !== null && _b !== void 0 ? _b : null;
|
|
27807
28723
|
}
|
|
27808
28724
|
/**
|
|
27809
28725
|
* Starts rendering the menu item.
|
|
@@ -27846,10 +28762,13 @@
|
|
|
27846
28762
|
this.drawnIds = [].concat(entityIds);
|
|
27847
28763
|
}
|
|
27848
28764
|
Dispose() {
|
|
28765
|
+
var _a;
|
|
27849
28766
|
if (this.disposed) {
|
|
27850
28767
|
return;
|
|
27851
28768
|
}
|
|
27852
28769
|
this.disposed = true;
|
|
28770
|
+
(_a = this.simulationRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
28771
|
+
this.simulationRemoval = null;
|
|
27853
28772
|
this.register.RemoveRegos({
|
|
27854
28773
|
menuItemId: this.item.id
|
|
27855
28774
|
});
|
|
@@ -28010,7 +28929,8 @@
|
|
|
28010
28929
|
menuItemId: this.item.id,
|
|
28011
28930
|
relations: relations,
|
|
28012
28931
|
viewer: this.viewer,
|
|
28013
|
-
visualRegister: this.register
|
|
28932
|
+
visualRegister: this.register,
|
|
28933
|
+
simulation: this.simulation
|
|
28014
28934
|
});
|
|
28015
28935
|
if (this.disposed) {
|
|
28016
28936
|
this.register.RemoveRegos({
|
|
@@ -29235,6 +30155,55 @@
|
|
|
29235
30155
|
get ModelSpace() {
|
|
29236
30156
|
return this.modelSpace;
|
|
29237
30157
|
}
|
|
30158
|
+
/**
|
|
30159
|
+
* Every node of the Assembly read so far, so a caller can work out motion in the Assembly's own terms.
|
|
30160
|
+
* @param timeMs the scene time for each node's current pose. Default: the clock's.
|
|
30161
|
+
* @returns per node its pose within its parent from the API (local) and as drawn at the time (current).
|
|
30162
|
+
*/
|
|
30163
|
+
GetNodes(timeMs) {
|
|
30164
|
+
const at = timeMs !== null && timeMs !== void 0 ? timeMs : Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime();
|
|
30165
|
+
const rowsOf = (m) => m ? [0, 1, 2, 3].map(row => [0, 1, 2, 3].map(column => m[(column * 4) + row])) : null;
|
|
30166
|
+
return Object.values(this.hierarchyNodeByEntityId || {}).map(node => {
|
|
30167
|
+
var _a, _b, _c;
|
|
30168
|
+
const entity = (_a = this.apiEntities.get(node.entityId)) !== null && _a !== void 0 ? _a : null;
|
|
30169
|
+
const rows = (_b = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _b === void 0 ? void 0 : _b.AssemblyPosition;
|
|
30170
|
+
return {
|
|
30171
|
+
entityId: node.entityId,
|
|
30172
|
+
name: node.name,
|
|
30173
|
+
parentId: (_c = node.parentId) !== null && _c !== void 0 ? _c : null,
|
|
30174
|
+
local: Manager.MatrixFromRows(rows) ? rows : null,
|
|
30175
|
+
current: rowsOf(this.localAt(node.entityId, at)),
|
|
30176
|
+
entity
|
|
30177
|
+
};
|
|
30178
|
+
});
|
|
30179
|
+
}
|
|
30180
|
+
/**
|
|
30181
|
+
* The root's world frame at a time, history and simulation included, eg. to follow or frame the Assembly.
|
|
30182
|
+
* @param timeMs the scene time. Default: the clock's.
|
|
30183
|
+
* @returns null until the root has been read.
|
|
30184
|
+
*/
|
|
30185
|
+
GetRootFrame(timeMs) {
|
|
30186
|
+
const root = this.rootAt(timeMs !== null && timeMs !== void 0 ? timeMs : Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime());
|
|
30187
|
+
return root ? Manager.rootFrame(root.pos3d, root.heading, root.pitch, root.roll) : null;
|
|
30188
|
+
}
|
|
30189
|
+
/**
|
|
30190
|
+
* A part's world frame at a time as its records and its parents place it, size included.
|
|
30191
|
+
* @param entityId the part.
|
|
30192
|
+
* @param timeMs the scene time. Default: the clock's.
|
|
30193
|
+
* @returns null until the root and the part have been read.
|
|
30194
|
+
*/
|
|
30195
|
+
GetPartFrame(entityId, timeMs) {
|
|
30196
|
+
const at = timeMs !== null && timeMs !== void 0 ? timeMs : Cesium.JulianDate.toDate(this.viewer.clock.currentTime).getTime();
|
|
30197
|
+
const rootFrame = this.GetRootFrame(at);
|
|
30198
|
+
const world = entityId === this.rootId ? Cesium.Matrix4.IDENTITY : this.composeWorld(entityId, at);
|
|
30199
|
+
if (!rootFrame || !world) {
|
|
30200
|
+
return null;
|
|
30201
|
+
}
|
|
30202
|
+
// Where the part is drawn, so its own ground offset is part of its frame.
|
|
30203
|
+
const ground = this.groundOffsets.get(entityId);
|
|
30204
|
+
const placed = ground ? Cesium.Matrix4.multiply(Cesium.Matrix4.fromTranslation(ground), world, new Cesium.Matrix4()) : world;
|
|
30205
|
+
return Cesium.Matrix4.multiply(rootFrame, placed, new Cesium.Matrix4());
|
|
30206
|
+
}
|
|
29238
30207
|
constructor(params) {
|
|
29239
30208
|
this.disposed = false;
|
|
29240
30209
|
// Cache of the hierarchy so that our scene-tree can reference it.
|
|
@@ -29244,19 +30213,41 @@
|
|
|
29244
30213
|
this.hierarchyNodeByEntityId = null;
|
|
29245
30214
|
this.modelSpace = false;
|
|
29246
30215
|
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.
|
|
30216
|
+
// Where the root sits outside its history, and which way it faces in degrees. Children are placed through it.
|
|
29249
30217
|
this.rootPos3d = null;
|
|
29250
30218
|
this.rootHeading = 0;
|
|
29251
|
-
|
|
30219
|
+
this.rootPitch = 0;
|
|
30220
|
+
this.rootRoll = 0;
|
|
30221
|
+
// The root's recorded positions and attitudes, oldest first, kept apart since a record may name only one.
|
|
30222
|
+
this.rootSeries = [];
|
|
30223
|
+
this.rootAttitude = [];
|
|
30224
|
+
// Every placement worked out for the scene time last asked about, shared by all parts drawn at it.
|
|
30225
|
+
this.pose = null;
|
|
30226
|
+
// Entity ID -> what was drawn for it.
|
|
29252
30227
|
this.children = new Map();
|
|
30228
|
+
// Entity ID -> its live position within its parent, for every node fetched including undrawn groups.
|
|
30229
|
+
this.localPositions = new Map();
|
|
30230
|
+
// Entity ID -> how much higher the ground under it is than under the root, along the root's up.
|
|
30231
|
+
this.groundOffsets = new Map();
|
|
30232
|
+
// Entity ID -> its recorded poses within its parent, oldest first.
|
|
30233
|
+
this.jointSeries = new Map();
|
|
30234
|
+
// Drawn children that can move with the clock, so a tick places only these and not the whole Assembly.
|
|
30235
|
+
this.animatedIds = new Set();
|
|
29253
30236
|
// The trail through the root's own movement, which describes the whole Assembly.
|
|
29254
|
-
this.
|
|
30237
|
+
this.trail = null;
|
|
30238
|
+
this.simulationRemoval = null;
|
|
30239
|
+
this.FollowsSimulation = true;
|
|
30240
|
+
// Entity ID -> the record the API gave, so a cleared simulation falls back to it without a refetch.
|
|
30241
|
+
this.apiEntities = new Map();
|
|
30242
|
+
// Re-reads history and re-applies it, eg. after simulated records change. Set while the clock is followed.
|
|
30243
|
+
this.regather = null;
|
|
30244
|
+
this.followingClock = false;
|
|
29255
30245
|
// Callback to dispose the link between scene time and the root's historic position.
|
|
29256
30246
|
this.viewerDateTimeChangeRemoval = null;
|
|
29257
30247
|
this.historicGatherer = null;
|
|
29258
30248
|
this.historicAnimation = null;
|
|
29259
30249
|
const { viewer, register: visualsManager, getters, item } = params;
|
|
30250
|
+
this.simulation = params.simulation;
|
|
29260
30251
|
this.viewer = viewer;
|
|
29261
30252
|
this.getters = getters;
|
|
29262
30253
|
this.item = item;
|
|
@@ -29280,10 +30271,10 @@
|
|
|
29280
30271
|
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
30272
|
}
|
|
29282
30273
|
/*
|
|
29283
|
-
* The root's frame: east-north-up at its position, turned by its heading.
|
|
30274
|
+
* The root's frame: east-north-up at its position, turned by its heading, pitch and roll.
|
|
29284
30275
|
*/
|
|
29285
|
-
static rootFrame(rootPos3d, headingDegrees) {
|
|
29286
|
-
const hpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(headingDegrees || 0), 0, 0);
|
|
30276
|
+
static rootFrame(rootPos3d, headingDegrees, pitchDegrees = 0, rollDegrees = 0) {
|
|
30277
|
+
const hpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(headingDegrees || 0), Cesium.Math.toRadians(pitchDegrees || 0), Cesium.Math.toRadians(rollDegrees || 0));
|
|
29287
30278
|
return Cesium.Transforms.headingPitchRollToFixedFrame(rootPos3d, hpr);
|
|
29288
30279
|
}
|
|
29289
30280
|
/**
|
|
@@ -29306,28 +30297,553 @@
|
|
|
29306
30297
|
return Cesium.Matrix4.multiplyByPoint(Manager.rootFrame(rootPos3d, headingDegrees), offset, new Cesium.Cartesian3());
|
|
29307
30298
|
}
|
|
29308
30299
|
/**
|
|
29309
|
-
* Moves the
|
|
30300
|
+
* Moves where the root sits outside its history, without refetching children; recorded poses still win.
|
|
29310
30301
|
* @param params
|
|
29311
30302
|
*/
|
|
29312
30303
|
ApplyRootPosition(params) {
|
|
29313
|
-
var _a, _b;
|
|
30304
|
+
var _a, _b, _c, _d, _e, _f;
|
|
29314
30305
|
if (this.disposed || !(params === null || params === void 0 ? void 0 : params.pos3d)) {
|
|
29315
30306
|
return;
|
|
29316
30307
|
}
|
|
29317
30308
|
this.rootPos3d = params.pos3d;
|
|
29318
30309
|
this.rootHeading = (_b = (_a = params.heading) !== null && _a !== void 0 ? _a : this.rootHeading) !== null && _b !== void 0 ? _b : 0;
|
|
30310
|
+
this.rootPitch = (_d = (_c = params.pitch) !== null && _c !== void 0 ? _c : this.rootPitch) !== null && _d !== void 0 ? _d : 0;
|
|
30311
|
+
this.rootRoll = (_f = (_e = params.roll) !== null && _e !== void 0 ? _e : this.rootRoll) !== null && _f !== void 0 ? _f : 0;
|
|
30312
|
+
this.repose(true);
|
|
30313
|
+
}
|
|
30314
|
+
/*
|
|
30315
|
+
* Drops every placement worked out so far, after the root or a joint's records change.
|
|
30316
|
+
* @param everyChild re-place the parts that cannot move as well, because where they rest has changed.
|
|
30317
|
+
*/
|
|
30318
|
+
repose(everyChild = false) {
|
|
30319
|
+
this.pose = null;
|
|
29319
30320
|
for (const child of this.children.values()) {
|
|
29320
|
-
|
|
29321
|
-
|
|
30321
|
+
if (everyChild || Boolean(child.moving) != this.canMove(child.entityId)) {
|
|
30322
|
+
this.bindPlacement(child);
|
|
30323
|
+
}
|
|
30324
|
+
}
|
|
30325
|
+
this.viewer.scene.requestRender();
|
|
30326
|
+
}
|
|
30327
|
+
/*
|
|
30328
|
+
* Takes a node's pose outside its history from its record, and for the root where it stands and faces.
|
|
30329
|
+
*/
|
|
30330
|
+
absorbNode(entity) {
|
|
30331
|
+
var _a, _b, _c, _d, _e;
|
|
30332
|
+
const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
30333
|
+
const local = Manager.MatrixFromRows((_b = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _b === void 0 ? void 0 : _b.AssemblyPosition);
|
|
30334
|
+
if (local) {
|
|
30335
|
+
this.localPositions.set(id, local);
|
|
30336
|
+
}
|
|
30337
|
+
// Anchored on the root, which is usually never drawn; everything under it is placed from the hierarchy.
|
|
30338
|
+
if (id === this.rootId || (!this.rootId && !this.rootPos3d)) {
|
|
30339
|
+
const rootPos3d = exports.EntityUtils.GetPos({
|
|
30340
|
+
viewer: this.viewer,
|
|
30341
|
+
entity,
|
|
30342
|
+
recordHeightRef: Manager.GetRecordHeightRef(this.item),
|
|
30343
|
+
returnHeightRef: Cesium.HeightReference.NONE,
|
|
30344
|
+
allowRendered: false
|
|
30345
|
+
});
|
|
30346
|
+
if (rootPos3d) {
|
|
30347
|
+
this.rootPos3d = rootPos3d;
|
|
30348
|
+
this.rootHeading = EnsureNumber((_c = entity.Bruce.Transform) === null || _c === void 0 ? void 0 : _c.heading, 0);
|
|
30349
|
+
this.rootPitch = EnsureNumber((_d = entity.Bruce.Transform) === null || _d === void 0 ? void 0 : _d.pitch, 0);
|
|
30350
|
+
this.rootRoll = EnsureNumber((_e = entity.Bruce.Transform) === null || _e === void 0 ? void 0 : _e.roll, 0);
|
|
30351
|
+
}
|
|
30352
|
+
}
|
|
30353
|
+
}
|
|
30354
|
+
/*
|
|
30355
|
+
* A node's record with its simulation laid over it, keeping what a stand-in leaves out, eg. its model.
|
|
30356
|
+
*/
|
|
30357
|
+
withSimulation(entity) {
|
|
30358
|
+
var _a;
|
|
30359
|
+
const id = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
30360
|
+
if (!this.simulation || !id) {
|
|
30361
|
+
return entity;
|
|
30362
|
+
}
|
|
30363
|
+
const standIn = this.simulation.GetEntity(id);
|
|
30364
|
+
if (!standIn) {
|
|
30365
|
+
return this.simulation.Overlay(entity);
|
|
30366
|
+
}
|
|
30367
|
+
return { ...entity, ...standIn, Bruce: { ...entity.Bruce, ...standIn.Bruce } };
|
|
30368
|
+
}
|
|
30369
|
+
/*
|
|
30370
|
+
* Brings the Assembly in line with a change to what is simulated.
|
|
30371
|
+
*/
|
|
30372
|
+
onSimulationChanged(change) {
|
|
30373
|
+
var _a;
|
|
30374
|
+
if (this.disposed || !this.hierarchyNodeByEntityId) {
|
|
30375
|
+
return;
|
|
30376
|
+
}
|
|
30377
|
+
const ids = change.entityIds.filter(id => this.hierarchyNodeByEntityId[id]);
|
|
30378
|
+
if (!ids.length) {
|
|
30379
|
+
return;
|
|
30380
|
+
}
|
|
30381
|
+
if (change.entities) {
|
|
30382
|
+
for (const id of ids) {
|
|
30383
|
+
const api = this.apiEntities.get(id);
|
|
30384
|
+
if (!api) {
|
|
30385
|
+
// Not loaded yet, and it will be drawn from its simulation when it is.
|
|
30386
|
+
continue;
|
|
30387
|
+
}
|
|
30388
|
+
const entity = this.withSimulation(api);
|
|
30389
|
+
// A cleared blob leaves the node's own matrix where the API has none, so it is reset.
|
|
30390
|
+
if (!((_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.AssemblyPosition)) {
|
|
30391
|
+
this.localPositions.delete(id);
|
|
30392
|
+
}
|
|
30393
|
+
this.absorbNode(entity);
|
|
30394
|
+
const child = this.children.get(id);
|
|
30395
|
+
if (child) {
|
|
30396
|
+
child.entity = entity;
|
|
30397
|
+
}
|
|
30398
|
+
}
|
|
30399
|
+
this.repose(true);
|
|
30400
|
+
}
|
|
30401
|
+
if (change.records) {
|
|
30402
|
+
if (this.regather) {
|
|
30403
|
+
this.regather(true);
|
|
30404
|
+
}
|
|
30405
|
+
else {
|
|
30406
|
+
this.viewerDateTimeSub();
|
|
30407
|
+
}
|
|
30408
|
+
}
|
|
30409
|
+
}
|
|
30410
|
+
/*
|
|
30411
|
+
* Nodes of this Assembly with simulated history.
|
|
30412
|
+
*/
|
|
30413
|
+
simulatedNodeIds() {
|
|
30414
|
+
if (!this.simulation || !this.hierarchyNodeByEntityId) {
|
|
30415
|
+
return [];
|
|
30416
|
+
}
|
|
30417
|
+
return this.simulation.GetRecordEntityIds().filter(id => this.hierarchyNodeByEntityId[id]);
|
|
30418
|
+
}
|
|
30419
|
+
/*
|
|
30420
|
+
* Whether a node can move with time: the root has history, or it or an ancestor does.
|
|
30421
|
+
*/
|
|
30422
|
+
canMove(entityId) {
|
|
30423
|
+
return this.rootSeries.length > 0 || this.rootAttitude.length > 0 || this.animatedIds.has(entityId);
|
|
30424
|
+
}
|
|
30425
|
+
/*
|
|
30426
|
+
* Gives a child its position and orientation, as functions of scene time only when it can move.
|
|
30427
|
+
*/
|
|
30428
|
+
bindPlacement(child) {
|
|
30429
|
+
const id = child.entityId;
|
|
30430
|
+
const moving = this.canMove(id);
|
|
30431
|
+
if (moving) {
|
|
30432
|
+
if (!child.moving) {
|
|
30433
|
+
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);
|
|
30434
|
+
child.cEntity.orientation = new Cesium.CallbackProperty((time, result) => {
|
|
30435
|
+
var _a;
|
|
30436
|
+
const orient = (_a = this.placementAt(id, time)) === null || _a === void 0 ? void 0 : _a.orient;
|
|
30437
|
+
return orient ? Cesium.Quaternion.clone(orient, result) : undefined;
|
|
30438
|
+
}, false);
|
|
30439
|
+
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);
|
|
30440
|
+
}
|
|
30441
|
+
}
|
|
30442
|
+
else {
|
|
30443
|
+
const placed = this.placementAt(id, this.viewer.clock.currentTime);
|
|
30444
|
+
if (placed) {
|
|
30445
|
+
child.cEntity.position = new Cesium.ConstantPositionProperty(placed.pos3d);
|
|
30446
|
+
if (placed.orient) {
|
|
30447
|
+
child.cEntity.orientation = new Cesium.ConstantProperty(placed.orient);
|
|
30448
|
+
}
|
|
30449
|
+
child.cEntity.model.scale = new Cesium.ConstantProperty(placed.scale);
|
|
30450
|
+
}
|
|
30451
|
+
}
|
|
30452
|
+
if (Boolean(child.moving) != moving) {
|
|
30453
|
+
child.moving = moving;
|
|
30454
|
+
this.visualsManager.SetMoving({ moving, entityIds: [id], menuItemId: this.item.id });
|
|
30455
|
+
}
|
|
30456
|
+
}
|
|
30457
|
+
/*
|
|
30458
|
+
* The one scale a model takes from its part's composed matrix, the largest when they are uneven.
|
|
30459
|
+
*/
|
|
30460
|
+
static uniformScale(world) {
|
|
30461
|
+
return Cesium.Cartesian3.maximumComponent(Cesium.Matrix4.getScale(world, new Cesium.Cartesian3()));
|
|
30462
|
+
}
|
|
30463
|
+
static cloneOrUndefined(pos3d, result) {
|
|
30464
|
+
return pos3d ? Cesium.Cartesian3.clone(pos3d, result) : undefined;
|
|
30465
|
+
}
|
|
30466
|
+
/*
|
|
30467
|
+
* Where a node draws at a scene time, from one composition shared by every part asked about at that time.
|
|
30468
|
+
*/
|
|
30469
|
+
placementAt(entityId, time) {
|
|
30470
|
+
if (this.disposed || !time) {
|
|
30471
|
+
return null;
|
|
30472
|
+
}
|
|
30473
|
+
const timeMs = Cesium.JulianDate.toDate(time).getTime();
|
|
30474
|
+
if (!this.pose || this.pose.timeMs !== timeMs) {
|
|
30475
|
+
const root = this.rootAt(timeMs);
|
|
30476
|
+
this.pose = {
|
|
30477
|
+
timeMs,
|
|
30478
|
+
rootFrame: root ? Manager.rootFrame(root.pos3d, root.heading, root.pitch, root.roll) : null,
|
|
30479
|
+
worlds: new Map(),
|
|
30480
|
+
placements: new Map()
|
|
30481
|
+
};
|
|
30482
|
+
}
|
|
30483
|
+
const pose = this.pose;
|
|
30484
|
+
if (!pose.rootFrame) {
|
|
30485
|
+
return null;
|
|
30486
|
+
}
|
|
30487
|
+
let placed = pose.placements.get(entityId);
|
|
30488
|
+
if (!placed) {
|
|
30489
|
+
const world = this.composeWorld(entityId, timeMs, pose.worlds);
|
|
30490
|
+
const offset = world
|
|
30491
|
+
? Cesium.Matrix4.getTranslation(world, new Cesium.Cartesian3())
|
|
30492
|
+
: new Cesium.Cartesian3(0, 0, 0);
|
|
30493
|
+
const ground = this.groundOffsets.get(entityId);
|
|
30494
|
+
if (ground) {
|
|
30495
|
+
Cesium.Cartesian3.add(offset, ground, offset);
|
|
30496
|
+
}
|
|
30497
|
+
placed = {
|
|
30498
|
+
pos3d: Cesium.Matrix4.multiplyByPoint(pose.rootFrame, offset, new Cesium.Cartesian3()),
|
|
30499
|
+
// Without a matrix, eg. the root itself, there is no orientation of its own to apply.
|
|
30500
|
+
orient: world ? exports.EntityUtils.GetAssemblyOrientationInFrame(pose.rootFrame, world) : null,
|
|
30501
|
+
scale: world ? Manager.uniformScale(world) : 1
|
|
30502
|
+
};
|
|
30503
|
+
pose.placements.set(entityId, placed);
|
|
30504
|
+
}
|
|
30505
|
+
return placed;
|
|
30506
|
+
}
|
|
30507
|
+
/*
|
|
30508
|
+
* The root's pose at a time, position and attitude each following their own records as a joint's do.
|
|
30509
|
+
*/
|
|
30510
|
+
rootAt(timeMs) {
|
|
30511
|
+
const pos3d = this.rootPositionAt(timeMs);
|
|
30512
|
+
if (!pos3d) {
|
|
30513
|
+
return null;
|
|
30514
|
+
}
|
|
30515
|
+
const live = { heading: this.rootHeading, pitch: this.rootPitch, roll: this.rootRoll };
|
|
30516
|
+
const series = this.rootAttitude;
|
|
30517
|
+
if (!series.length || timeMs < series[0].timeMs) {
|
|
30518
|
+
return { pos3d, ...live };
|
|
30519
|
+
}
|
|
30520
|
+
let i = 0;
|
|
30521
|
+
while (i < series.length - 1 && series[i + 1].timeMs <= timeMs) {
|
|
30522
|
+
i++;
|
|
30523
|
+
}
|
|
30524
|
+
const a = series[i];
|
|
30525
|
+
const b = series[i + 1];
|
|
30526
|
+
const t = b ? (timeMs - a.timeMs) / (b.timeMs - a.timeMs) : 0;
|
|
30527
|
+
const turn = (from, to, fallback) => {
|
|
30528
|
+
var _a, _b, _c;
|
|
30529
|
+
const x = (_a = from !== null && from !== void 0 ? from : fallback) !== null && _a !== void 0 ? _a : 0;
|
|
30530
|
+
const y = (_c = (_b = (b ? to : from)) !== null && _b !== void 0 ? _b : fallback) !== null && _c !== void 0 ? _c : 0;
|
|
30531
|
+
// The short way round, so 350 to 10 degrees turns through north rather than all the way back.
|
|
30532
|
+
return x + (Cesium.Math.negativePiToPi(Cesium.Math.toRadians(y - x)) * 180 / Math.PI) * t;
|
|
30533
|
+
};
|
|
30534
|
+
return {
|
|
30535
|
+
pos3d,
|
|
30536
|
+
heading: turn(a.heading, b === null || b === void 0 ? void 0 : b.heading, live.heading),
|
|
30537
|
+
pitch: turn(a.pitch, b === null || b === void 0 ? void 0 : b.pitch, live.pitch),
|
|
30538
|
+
roll: turn(a.roll, b === null || b === void 0 ? void 0 : b.roll, live.roll)
|
|
30539
|
+
};
|
|
30540
|
+
}
|
|
30541
|
+
/*
|
|
30542
|
+
* Where the root is at a time, from its recorded positions.
|
|
30543
|
+
*/
|
|
30544
|
+
rootPositionAt(timeMs) {
|
|
30545
|
+
const series = this.rootSeries;
|
|
30546
|
+
if (!series.length || timeMs < series[0].timeMs) {
|
|
30547
|
+
return this.rootPos3d;
|
|
30548
|
+
}
|
|
30549
|
+
let i = 0;
|
|
30550
|
+
while (i < series.length - 1 && series[i + 1].timeMs <= timeMs) {
|
|
30551
|
+
i++;
|
|
30552
|
+
}
|
|
30553
|
+
const a = series[i];
|
|
30554
|
+
const b = series[i + 1];
|
|
30555
|
+
if (!b) {
|
|
30556
|
+
return a.pos3d;
|
|
30557
|
+
}
|
|
30558
|
+
const t = (timeMs - a.timeMs) / (b.timeMs - a.timeMs);
|
|
30559
|
+
// A straight line between orbit samples cuts up to a kilometre inside the path, so it is lifted back out.
|
|
30560
|
+
const chord = Cesium.Cartesian3.lerp(a.pos3d, b.pos3d, t, new Cesium.Cartesian3());
|
|
30561
|
+
const carto = Cesium.Cartographic.fromCartesian(chord);
|
|
30562
|
+
return carto
|
|
30563
|
+
? Cesium.Cartesian3.fromRadians(carto.longitude, carto.latitude, Cesium.Math.lerp(a.height, b.height, t))
|
|
30564
|
+
: chord;
|
|
30565
|
+
}
|
|
30566
|
+
/*
|
|
30567
|
+
* Takes the root's records into its series.
|
|
30568
|
+
* @param replace the records are everything held for the root, so the series becomes exactly them.
|
|
30569
|
+
* @returns whether the series changed.
|
|
30570
|
+
*/
|
|
30571
|
+
absorbRootRecords(posses, replace) {
|
|
30572
|
+
if (!(posses === null || posses === void 0 ? void 0 : posses.length) && !(replace && this.rootSeries.length)) {
|
|
30573
|
+
return false;
|
|
30574
|
+
}
|
|
30575
|
+
const byTime = new Map(replace ? [] : this.rootSeries.map(k => [k.timeMs, k]));
|
|
30576
|
+
for (const pos of posses) {
|
|
30577
|
+
const carto = Cesium.Cartographic.fromCartesian(pos.pos3d);
|
|
30578
|
+
if (!carto) {
|
|
29322
30579
|
continue;
|
|
29323
30580
|
}
|
|
29324
|
-
|
|
29325
|
-
|
|
29326
|
-
|
|
29327
|
-
|
|
30581
|
+
byTime.set(pos.dateTime.getTime(), {
|
|
30582
|
+
timeMs: pos.dateTime.getTime(),
|
|
30583
|
+
pos3d: pos.pos3d,
|
|
30584
|
+
height: carto.height
|
|
30585
|
+
});
|
|
30586
|
+
}
|
|
30587
|
+
const series = Array.from(byTime.values()).sort((x, y) => x.timeMs - y.timeMs);
|
|
30588
|
+
const changed = (series.length !== this.rootSeries.length ||
|
|
30589
|
+
series.some((k, i) => !Cesium.Cartesian3.equals(k.pos3d, this.rootSeries[i].pos3d)));
|
|
30590
|
+
this.rootSeries = series;
|
|
30591
|
+
return changed;
|
|
30592
|
+
}
|
|
30593
|
+
/*
|
|
30594
|
+
* Takes the angles the root's records name into its attitude series, apart from where it is.
|
|
30595
|
+
* @param replace the records are everything held for the root, as for absorbRootRecords.
|
|
30596
|
+
* @returns whether the series changed.
|
|
30597
|
+
*/
|
|
30598
|
+
absorbRootAttitude(records, replace) {
|
|
30599
|
+
const angle = (transform, key) => {
|
|
30600
|
+
var _a;
|
|
30601
|
+
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)];
|
|
30602
|
+
return value == null || isNaN(+value) ? null : +value;
|
|
30603
|
+
};
|
|
30604
|
+
const byTime = new Map(replace ? [] : this.rootAttitude.map(k => [k.timeMs, k]));
|
|
30605
|
+
for (const record of records || []) {
|
|
30606
|
+
const timeMs = (record === null || record === void 0 ? void 0 : record.dateTime) ? new Date(record.dateTime).getTime() : NaN;
|
|
30607
|
+
const key = {
|
|
30608
|
+
timeMs,
|
|
30609
|
+
heading: angle(record === null || record === void 0 ? void 0 : record.transform, "heading"),
|
|
30610
|
+
pitch: angle(record === null || record === void 0 ? void 0 : record.transform, "pitch"),
|
|
30611
|
+
roll: angle(record === null || record === void 0 ? void 0 : record.transform, "roll")
|
|
30612
|
+
};
|
|
30613
|
+
if (isNaN(timeMs) || (key.heading == null && key.pitch == null && key.roll == null)) {
|
|
30614
|
+
continue;
|
|
29328
30615
|
}
|
|
30616
|
+
byTime.set(timeMs, key);
|
|
29329
30617
|
}
|
|
29330
|
-
|
|
30618
|
+
const series = Array.from(byTime.values()).sort((x, y) => x.timeMs - y.timeMs);
|
|
30619
|
+
const held = this.rootAttitude;
|
|
30620
|
+
const differs = (k, i) => (k.timeMs !== held[i].timeMs ||
|
|
30621
|
+
k.heading !== held[i].heading ||
|
|
30622
|
+
k.pitch !== held[i].pitch ||
|
|
30623
|
+
k.roll !== held[i].roll);
|
|
30624
|
+
const changed = series.length !== held.length || series.some(differs);
|
|
30625
|
+
this.rootAttitude = series;
|
|
30626
|
+
return changed;
|
|
30627
|
+
}
|
|
30628
|
+
/*
|
|
30629
|
+
* A node's matrix in the root's frame at a time, from each ancestor's pose within its parent.
|
|
30630
|
+
*/
|
|
30631
|
+
composeWorld(entityId, timeMs, memo, localOf = (id) => this.localAt(id, timeMs)) {
|
|
30632
|
+
var _a, _b, _c, _d;
|
|
30633
|
+
if (memo === null || memo === void 0 ? void 0 : memo.has(entityId)) {
|
|
30634
|
+
return memo.get(entityId);
|
|
30635
|
+
}
|
|
30636
|
+
let world = null;
|
|
30637
|
+
const local = localOf(entityId);
|
|
30638
|
+
if (local) {
|
|
30639
|
+
const parentId = (_b = (_a = this.hierarchyNodeByEntityId) === null || _a === void 0 ? void 0 : _a[entityId]) === null || _b === void 0 ? void 0 : _b.parentId;
|
|
30640
|
+
const parent = parentId ? this.composeWorld(parentId, timeMs, memo, localOf) : null;
|
|
30641
|
+
world = parent ? Cesium.Matrix4.multiply(parent, local, new Cesium.Matrix4()) : Cesium.Matrix4.clone(local);
|
|
30642
|
+
}
|
|
30643
|
+
else if (entityId !== this.rootId) {
|
|
30644
|
+
// A node whose own position was not fetched falls back to the API's composed matrix.
|
|
30645
|
+
const child = this.children.get(entityId);
|
|
30646
|
+
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);
|
|
30647
|
+
}
|
|
30648
|
+
memo === null || memo === void 0 ? void 0 : memo.set(entityId, world);
|
|
30649
|
+
return world;
|
|
30650
|
+
}
|
|
30651
|
+
/*
|
|
30652
|
+
* Under a clamped or relative style, lifts a part by how much higher its ground is than the root's.
|
|
30653
|
+
*/
|
|
30654
|
+
measureGroundOffset(entity) {
|
|
30655
|
+
var _a;
|
|
30656
|
+
const entityId = (_a = entity === null || entity === void 0 ? void 0 : entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID;
|
|
30657
|
+
this.groundOffsets.delete(entityId);
|
|
30658
|
+
const root = this.apiEntities.get(this.rootId);
|
|
30659
|
+
if (!entityId ||
|
|
30660
|
+
entityId === this.rootId ||
|
|
30661
|
+
!root ||
|
|
30662
|
+
!this.rootPos3d ||
|
|
30663
|
+
Manager.GetRecordHeightRef(this.item) === Cesium.HeightReference.NONE) {
|
|
30664
|
+
return;
|
|
30665
|
+
}
|
|
30666
|
+
const rootFrame = Manager.rootFrame(this.rootPos3d, this.rootHeading, this.rootPitch, this.rootRoll);
|
|
30667
|
+
const toRoot = Cesium.Matrix4.inverse(rootFrame, new Cesium.Matrix4());
|
|
30668
|
+
const groundUp = (record) => {
|
|
30669
|
+
const pos3d = exports.EntityUtils.GetPos({
|
|
30670
|
+
viewer: this.viewer,
|
|
30671
|
+
entity: record,
|
|
30672
|
+
recordHeightRef: Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
30673
|
+
returnHeightRef: Cesium.HeightReference.NONE,
|
|
30674
|
+
allowRendered: false
|
|
30675
|
+
});
|
|
30676
|
+
return pos3d ? Cesium.Matrix4.multiplyByPoint(toRoot, pos3d, new Cesium.Cartesian3()).z : null;
|
|
30677
|
+
};
|
|
30678
|
+
const part = groundUp(entity);
|
|
30679
|
+
const under = groundUp(root);
|
|
30680
|
+
if (part == null || under == null || Math.abs(part - under) < 1e-6) {
|
|
30681
|
+
return;
|
|
30682
|
+
}
|
|
30683
|
+
this.groundOffsets.set(entityId, new Cesium.Cartesian3(0, 0, part - under));
|
|
30684
|
+
}
|
|
30685
|
+
/*
|
|
30686
|
+
* The rigid Earth-fixed motion from where a part's record places it to where it is drawn at a time.
|
|
30687
|
+
*/
|
|
30688
|
+
motionAt(entityId, time) {
|
|
30689
|
+
if (this.disposed || !time || !this.rootPos3d) {
|
|
30690
|
+
return null;
|
|
30691
|
+
}
|
|
30692
|
+
const timeMs = Cesium.JulianDate.toDate(time).getTime();
|
|
30693
|
+
const root = this.rootAt(timeMs);
|
|
30694
|
+
const drawn = this.composeWorld(entityId, timeMs, new Map());
|
|
30695
|
+
const stored = this.composeWorld(entityId, timeMs, new Map(), (id) => {
|
|
30696
|
+
var _a, _b, _c, _d;
|
|
30697
|
+
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);
|
|
30698
|
+
});
|
|
30699
|
+
if (!root || !drawn || !stored) {
|
|
30700
|
+
return null;
|
|
30701
|
+
}
|
|
30702
|
+
const drawnFixed = Cesium.Matrix4.multiply(Manager.rootFrame(root.pos3d, root.heading, root.pitch, root.roll), drawn, new Cesium.Matrix4());
|
|
30703
|
+
const storedFixed = Cesium.Matrix4.multiply(Manager.rootFrame(this.rootPos3d, this.rootHeading, this.rootPitch, this.rootRoll), stored, new Cesium.Matrix4());
|
|
30704
|
+
return Cesium.Matrix4.multiply(drawnFixed, Cesium.Matrix4.inverse(storedFixed, new Cesium.Matrix4()), new Cesium.Matrix4());
|
|
30705
|
+
}
|
|
30706
|
+
/*
|
|
30707
|
+
* A node's pose within its parent at a time, interpolated between the records either side.
|
|
30708
|
+
*/
|
|
30709
|
+
localAt(entityId, timeMs) {
|
|
30710
|
+
var _a;
|
|
30711
|
+
// The live pose stands before the first record and the last record holds after it, as in an API read.
|
|
30712
|
+
const live = (_a = this.localPositions.get(entityId)) !== null && _a !== void 0 ? _a : null;
|
|
30713
|
+
const series = this.jointSeries.get(entityId);
|
|
30714
|
+
if (!(series === null || series === void 0 ? void 0 : series.length) || timeMs == null || timeMs < series[0].timeMs) {
|
|
30715
|
+
return live;
|
|
30716
|
+
}
|
|
30717
|
+
let i = 0;
|
|
30718
|
+
while (i < series.length - 1 && series[i + 1].timeMs <= timeMs) {
|
|
30719
|
+
i++;
|
|
30720
|
+
}
|
|
30721
|
+
const a = series[i];
|
|
30722
|
+
const b = series[i + 1];
|
|
30723
|
+
if (!b) {
|
|
30724
|
+
return Cesium.Matrix4.fromTranslationQuaternionRotationScale(a.translation, a.rotation, a.scale);
|
|
30725
|
+
}
|
|
30726
|
+
const t = (timeMs - a.timeMs) / (b.timeMs - a.timeMs);
|
|
30727
|
+
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()));
|
|
30728
|
+
}
|
|
30729
|
+
/*
|
|
30730
|
+
* Rebuilds each node's keyframes from the historic records held so far.
|
|
30731
|
+
* @returns whether any node has keyframes.
|
|
30732
|
+
*/
|
|
30733
|
+
absorbJointRecords(recordsByIds) {
|
|
30734
|
+
var _a;
|
|
30735
|
+
// Everything held is given, so a node with nothing left, eg. its simulated records cleared, stops moving.
|
|
30736
|
+
for (const entityId of Array.from(this.jointSeries.keys())) {
|
|
30737
|
+
if (!((_a = recordsByIds === null || recordsByIds === void 0 ? void 0 : recordsByIds[entityId]) === null || _a === void 0 ? void 0 : _a.length)) {
|
|
30738
|
+
this.jointSeries.delete(entityId);
|
|
30739
|
+
}
|
|
30740
|
+
}
|
|
30741
|
+
for (const entityId of Object.keys(recordsByIds || {})) {
|
|
30742
|
+
const keyframes = [];
|
|
30743
|
+
for (const record of recordsByIds[entityId] || []) {
|
|
30744
|
+
const matrix = Manager.MatrixFromRows(record.assemblyPosition);
|
|
30745
|
+
const timeMs = new Date(record.dateTime).getTime();
|
|
30746
|
+
if (!matrix || isNaN(timeMs)) {
|
|
30747
|
+
continue;
|
|
30748
|
+
}
|
|
30749
|
+
const scale = Cesium.Matrix4.getScale(matrix, new Cesium.Cartesian3());
|
|
30750
|
+
const rotation = Cesium.Matrix4.getRotation(matrix, new Cesium.Matrix3());
|
|
30751
|
+
keyframes.push({
|
|
30752
|
+
timeMs,
|
|
30753
|
+
translation: Cesium.Matrix4.getTranslation(matrix, new Cesium.Cartesian3()),
|
|
30754
|
+
rotation: Cesium.Quaternion.fromRotationMatrix(rotation),
|
|
30755
|
+
scale
|
|
30756
|
+
});
|
|
30757
|
+
}
|
|
30758
|
+
if (keyframes.length) {
|
|
30759
|
+
keyframes.sort((x, y) => x.timeMs - y.timeMs);
|
|
30760
|
+
this.jointSeries.set(entityId, keyframes);
|
|
30761
|
+
}
|
|
30762
|
+
}
|
|
30763
|
+
this.refreshAnimated();
|
|
30764
|
+
return this.jointSeries.size > 0;
|
|
30765
|
+
}
|
|
30766
|
+
/*
|
|
30767
|
+
* Rebuilds which drawn children can move with the clock, by walking each one up to the root.
|
|
30768
|
+
*/
|
|
30769
|
+
refreshAnimated() {
|
|
30770
|
+
this.animatedIds.clear();
|
|
30771
|
+
if (!this.jointSeries.size) {
|
|
30772
|
+
return;
|
|
30773
|
+
}
|
|
30774
|
+
for (const entityId of this.children.keys()) {
|
|
30775
|
+
if (this.hasAnimatedAncestry(entityId)) {
|
|
30776
|
+
this.animatedIds.add(entityId);
|
|
30777
|
+
}
|
|
30778
|
+
}
|
|
30779
|
+
}
|
|
30780
|
+
/*
|
|
30781
|
+
* Whether a node or anything above it has keyframes, so the clock can move it.
|
|
30782
|
+
*/
|
|
30783
|
+
hasAnimatedAncestry(entityId) {
|
|
30784
|
+
var _a, _b;
|
|
30785
|
+
let at = entityId;
|
|
30786
|
+
while (at && this.jointSeries.size) {
|
|
30787
|
+
if (this.jointSeries.has(at)) {
|
|
30788
|
+
return true;
|
|
30789
|
+
}
|
|
30790
|
+
at = (_b = (_a = this.hierarchyNodeByEntityId) === null || _a === void 0 ? void 0 : _a[at]) === null || _b === void 0 ? void 0 : _b.parentId;
|
|
30791
|
+
}
|
|
30792
|
+
return false;
|
|
30793
|
+
}
|
|
30794
|
+
/*
|
|
30795
|
+
* Which nodes to ask history for.
|
|
30796
|
+
*/
|
|
30797
|
+
async historicEntityIds(api) {
|
|
30798
|
+
var _a, _b;
|
|
30799
|
+
// Through the Assembly when there is one, so the hierarchy follows the relation type on its record.
|
|
30800
|
+
const assemblyId = this.item["Assembly.ID"];
|
|
30801
|
+
const root = assemblyId ? { key: "root", AssemblyID: assemblyId } : { key: "root", RootID: this.rootId };
|
|
30802
|
+
const historic = {
|
|
30803
|
+
key: "historic",
|
|
30804
|
+
Historic: { HistoricKey: ((_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey) || undefined }
|
|
30805
|
+
};
|
|
30806
|
+
const query = {
|
|
30807
|
+
[BModels.DataLab.EReqKey.Primary]: { Items: [root, historic], Select: { Type: BModels.DataLab.ESelectType.Id } }
|
|
30808
|
+
};
|
|
30809
|
+
const load = 1000;
|
|
30810
|
+
try {
|
|
30811
|
+
const ids = [];
|
|
30812
|
+
for (let skip = 0;; skip += load) {
|
|
30813
|
+
const { items } = await BModels.DataLab.Run({ api, query, skip, load });
|
|
30814
|
+
ids.push(...(items !== null && items !== void 0 ? items : []));
|
|
30815
|
+
if (!items || items.length < load) {
|
|
30816
|
+
return ids;
|
|
30817
|
+
}
|
|
30818
|
+
}
|
|
30819
|
+
}
|
|
30820
|
+
catch (e) {
|
|
30821
|
+
// An API without the historic criterion gets asked about every node, as before it existed.
|
|
30822
|
+
console.warn("AssemblyRenderManager.historicEntityIds()", e);
|
|
30823
|
+
}
|
|
30824
|
+
return Object.keys((_b = this.hierarchyNodeByEntityId) !== null && _b !== void 0 ? _b : { [this.rootId]: null });
|
|
30825
|
+
}
|
|
30826
|
+
/**
|
|
30827
|
+
* Builds a matrix from the row-major rows that Bruce/AssemblyPosition and AssemblyWorldPosition use.
|
|
30828
|
+
* @param rows
|
|
30829
|
+
*/
|
|
30830
|
+
static MatrixFromRows(rows) {
|
|
30831
|
+
if (!Array.isArray(rows) || rows.length !== 4 || rows.some(r => !Array.isArray(r) || r.length !== 4)) {
|
|
30832
|
+
return null;
|
|
30833
|
+
}
|
|
30834
|
+
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]);
|
|
30835
|
+
}
|
|
30836
|
+
/**
|
|
30837
|
+
* The inverse of MatrixFromRows.
|
|
30838
|
+
* @param matrix
|
|
30839
|
+
*/
|
|
30840
|
+
static RowsFromMatrix(matrix) {
|
|
30841
|
+
const rows = [];
|
|
30842
|
+
for (let r = 0; r < 4; r++) {
|
|
30843
|
+
const row = Cesium.Matrix4.getRow(matrix, r, new Cesium.Cartesian4());
|
|
30844
|
+
rows.push([row.x, row.y, row.z, row.w]);
|
|
30845
|
+
}
|
|
30846
|
+
return rows;
|
|
29331
30847
|
}
|
|
29332
30848
|
Init() {
|
|
29333
30849
|
this.renderPriority = this.item.renderPriority;
|
|
@@ -29335,6 +30851,7 @@
|
|
|
29335
30851
|
this.renderPriority = 1;
|
|
29336
30852
|
}
|
|
29337
30853
|
(async () => {
|
|
30854
|
+
var _a, _b;
|
|
29338
30855
|
if (this.disposed) {
|
|
29339
30856
|
return;
|
|
29340
30857
|
}
|
|
@@ -29350,6 +30867,8 @@
|
|
|
29350
30867
|
this.hierarchyUpdate.Trigger(hierarchy);
|
|
29351
30868
|
// Build hierarchy node cache for quick lookups
|
|
29352
30869
|
this.buildHierarchyNodes(hierarchy);
|
|
30870
|
+
// A set for membership, since searching the list took minutes at 200k nodes.
|
|
30871
|
+
const seenIds = new Set();
|
|
29353
30872
|
const traverseHierarchy = (node, leavesOnly) => {
|
|
29354
30873
|
var _a;
|
|
29355
30874
|
if (node.Children) {
|
|
@@ -29358,7 +30877,8 @@
|
|
|
29358
30877
|
}
|
|
29359
30878
|
}
|
|
29360
30879
|
const addNode = !leavesOnly || !((_a = node.Children) === null || _a === void 0 ? void 0 : _a.length);
|
|
29361
|
-
if (addNode && node.ID && !
|
|
30880
|
+
if (addNode && node.ID && !seenIds.has(node.ID)) {
|
|
30881
|
+
seenIds.add(node.ID);
|
|
29362
30882
|
flatEntityIds.push(node.ID);
|
|
29363
30883
|
}
|
|
29364
30884
|
};
|
|
@@ -29377,17 +30897,17 @@
|
|
|
29377
30897
|
}
|
|
29378
30898
|
}
|
|
29379
30899
|
this.rootId = rootId;
|
|
30900
|
+
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
30901
|
if (this.disposed) {
|
|
29381
30902
|
return;
|
|
29382
30903
|
}
|
|
29383
30904
|
else if (flatEntityIds.length === 0) {
|
|
29384
30905
|
return;
|
|
29385
30906
|
}
|
|
30907
|
+
// Followed while the parts load: in a large Assembly loading takes far longer than anyone waits.
|
|
30908
|
+
const following = this.viewerDateTimeSub();
|
|
29386
30909
|
await this.processEntityIds(flatEntityIds);
|
|
29387
|
-
|
|
29388
|
-
return;
|
|
29389
|
-
}
|
|
29390
|
-
this.viewerDateTimeSub();
|
|
30910
|
+
await following;
|
|
29391
30911
|
}
|
|
29392
30912
|
catch (e) {
|
|
29393
30913
|
console.error("AssemblyRenderManager.Manager.Init()", e);
|
|
@@ -29414,7 +30934,7 @@
|
|
|
29414
30934
|
if (!batch.length) {
|
|
29415
30935
|
continue;
|
|
29416
30936
|
}
|
|
29417
|
-
const { entities:
|
|
30937
|
+
const { entities: apiEntities } = await BModels.Entity.GetListByIds({
|
|
29418
30938
|
entityIds: batch,
|
|
29419
30939
|
api: this.getters.GetBruceApi(),
|
|
29420
30940
|
expandLODs: true,
|
|
@@ -29426,6 +30946,16 @@
|
|
|
29426
30946
|
if (this.disposed) {
|
|
29427
30947
|
return;
|
|
29428
30948
|
}
|
|
30949
|
+
const fetched = apiEntities.map((entity) => {
|
|
30950
|
+
var _a;
|
|
30951
|
+
this.apiEntities.set((_a = entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID, entity);
|
|
30952
|
+
return this.withSimulation(entity);
|
|
30953
|
+
});
|
|
30954
|
+
for (const entity of fetched) {
|
|
30955
|
+
this.absorbNode(entity);
|
|
30956
|
+
}
|
|
30957
|
+
// Placements already worked out did not know about this batch's positions.
|
|
30958
|
+
this.pose = null;
|
|
29429
30959
|
for (const entity of fetched) {
|
|
29430
30960
|
// Filter for valid LODs then take the highest quality one (lowest level).
|
|
29431
30961
|
let lods = entity.Bruce.LOD || [];
|
|
@@ -29448,57 +30978,46 @@
|
|
|
29448
30978
|
// Won't bother with vector data for this experiment.
|
|
29449
30979
|
continue;
|
|
29450
30980
|
}
|
|
29451
|
-
const
|
|
29452
|
-
|
|
29453
|
-
|
|
29454
|
-
|
|
29455
|
-
|
|
29456
|
-
returnHeightRef: Cesium.HeightReference.NONE,
|
|
29457
|
-
allowRendered: false
|
|
29458
|
-
});
|
|
29459
|
-
if (!recordPos3d) {
|
|
30981
|
+
const entityId = entity.Bruce.ID;
|
|
30982
|
+
this.measureGroundOffset(entity);
|
|
30983
|
+
// A placement cached before the offset was known would leave the part off its ground.
|
|
30984
|
+
(_a = this.pose) === null || _a === void 0 ? void 0 : _a.placements.delete(entityId);
|
|
30985
|
+
if (!this.canMove(entityId) && !this.placementAt(entityId, this.viewer.clock.currentTime)) {
|
|
29460
30986
|
continue;
|
|
29461
30987
|
}
|
|
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
30988
|
const cEntity = this.viewer.entities.add({
|
|
29476
30989
|
model: {
|
|
29477
30990
|
uri: lod["ClientFile"].URL,
|
|
29478
30991
|
...exports.ViewUtils.DefaultLightingProps(),
|
|
29479
30992
|
heightReference: Cesium.HeightReference.NONE
|
|
29480
|
-
}
|
|
29481
|
-
position: pos3d,
|
|
29482
|
-
orientation: orient ? new Cesium.ConstantProperty(orient) : undefined
|
|
30993
|
+
}
|
|
29483
30994
|
});
|
|
29484
30995
|
const prior = this.children.get(entityId);
|
|
29485
30996
|
if (prior && prior.cEntity !== cEntity) {
|
|
29486
30997
|
RemoveCEntityFromScene(this.viewer, prior.cEntity);
|
|
29487
30998
|
}
|
|
29488
|
-
|
|
30999
|
+
const child = {
|
|
29489
31000
|
entityId: entityId,
|
|
29490
31001
|
entity: entity,
|
|
29491
|
-
cEntity: cEntity
|
|
29492
|
-
|
|
29493
|
-
|
|
31002
|
+
cEntity: cEntity
|
|
31003
|
+
};
|
|
31004
|
+
this.children.set(entityId, child);
|
|
31005
|
+
// Joins the animated set by its own ancestry, so a late part never re-walks the rest.
|
|
31006
|
+
if (this.hasAnimatedAncestry(entityId)) {
|
|
31007
|
+
this.animatedIds.add(entityId);
|
|
31008
|
+
}
|
|
29494
31009
|
const geometryRadius = BModels.Entity.GetValue({
|
|
29495
31010
|
entity: entity,
|
|
29496
31011
|
path: ["Bruce", "GeometryRadius"]
|
|
29497
31012
|
});
|
|
29498
31013
|
cEntity.model["_radius"] = geometryRadius;
|
|
29499
31014
|
cEntity.model["_radiusLoaded"] = true;
|
|
31015
|
+
// Placed before it is registered, so the register never measures a visual with no position.
|
|
31016
|
+
this.bindPlacement(child);
|
|
29500
31017
|
this.visualsManager.AddRego({
|
|
29501
31018
|
rego: {
|
|
31019
|
+
moving: child.moving ? true : null,
|
|
31020
|
+
motion: (time) => this.motionAt(entity.Bruce.ID, time),
|
|
29502
31021
|
canEdit: true,
|
|
29503
31022
|
entityId: entity.Bruce.ID,
|
|
29504
31023
|
menuItemId: this.item.id,
|
|
@@ -29518,47 +31037,89 @@
|
|
|
29518
31037
|
}
|
|
29519
31038
|
}
|
|
29520
31039
|
/*
|
|
29521
|
-
* Follows the scene clock
|
|
29522
|
-
* Only the root is fetched: everything under it is placed through ApplyRootPosition.
|
|
31040
|
+
* Follows the scene clock, moving the Assembly along the root's history and each joint along its own.
|
|
29523
31041
|
*/
|
|
29524
|
-
viewerDateTimeSub() {
|
|
29525
|
-
|
|
31042
|
+
async viewerDateTimeSub() {
|
|
31043
|
+
var _a;
|
|
31044
|
+
const historic = Manager.IsHistoric(this.item);
|
|
31045
|
+
if (this.followingClock || !this.rootId || (!historic && !this.simulatedNodeIds().length)) {
|
|
29526
31046
|
return;
|
|
29527
31047
|
}
|
|
31048
|
+
this.followingClock = true;
|
|
29528
31049
|
const api = this.getters.GetBruceApi();
|
|
29529
|
-
const
|
|
31050
|
+
const historicIds = historic ? await this.historicEntityIds(api) : [];
|
|
31051
|
+
if (this.disposed) {
|
|
31052
|
+
return;
|
|
31053
|
+
}
|
|
31054
|
+
const attrKey = (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey;
|
|
29530
31055
|
const recordHeightRef = Manager.GetRecordHeightRef(this.item);
|
|
29531
31056
|
const toPosses = (records) => {
|
|
29532
31057
|
return exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(this.viewer, recordHeightRef, Cesium.HeightReference.NONE, records);
|
|
29533
31058
|
};
|
|
29534
|
-
|
|
29535
|
-
|
|
29536
|
-
|
|
29537
|
-
|
|
29538
|
-
|
|
29539
|
-
|
|
29540
|
-
|
|
29541
|
-
|
|
29542
|
-
|
|
29543
|
-
|
|
31059
|
+
if (historicIds.length) {
|
|
31060
|
+
this.historicGatherer = new HistoricGatherer({
|
|
31061
|
+
viewer: this.viewer,
|
|
31062
|
+
getApi: () => api,
|
|
31063
|
+
getAttrKey: () => attrKey,
|
|
31064
|
+
// For clock desync between whatever wrote the record and this client.
|
|
31065
|
+
paddingMs: 15000,
|
|
31066
|
+
simulation: this.simulation,
|
|
31067
|
+
onRecords: (recordsByIds) => {
|
|
31068
|
+
var _a;
|
|
31069
|
+
const records = recordsByIds[this.rootId];
|
|
31070
|
+
if (records === null || records === void 0 ? void 0 : records.length) {
|
|
31071
|
+
const posses = toPosses(records);
|
|
31072
|
+
(_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.SupplementSeries(posses);
|
|
31073
|
+
const moved = this.absorbRootRecords(posses, false);
|
|
31074
|
+
if (this.absorbRootAttitude(records, false) || moved) {
|
|
31075
|
+
this.repose();
|
|
31076
|
+
}
|
|
31077
|
+
}
|
|
31078
|
+
// Joint records go in together once the gather lands, so parents never draw apart from children.
|
|
29544
31079
|
}
|
|
29545
|
-
}
|
|
29546
|
-
}
|
|
31080
|
+
});
|
|
31081
|
+
}
|
|
31082
|
+
// The nodes with history: what the API has records for, and whatever has been simulated since.
|
|
31083
|
+
const nodes = () => Array.from(new Set([...historicIds, ...this.simulatedNodeIds()]));
|
|
29547
31084
|
let gathering = false;
|
|
29548
|
-
|
|
31085
|
+
// Set when what is held changed without a fetch, eg. a simulated record arriving.
|
|
31086
|
+
let stale = true;
|
|
31087
|
+
const gather = async (force) => {
|
|
31088
|
+
var _a, _b;
|
|
31089
|
+
stale = stale || Boolean(force);
|
|
29549
31090
|
if (this.disposed || gathering) {
|
|
29550
31091
|
return;
|
|
29551
31092
|
}
|
|
29552
31093
|
gathering = true;
|
|
29553
31094
|
try {
|
|
29554
|
-
const
|
|
31095
|
+
const ids = nodes();
|
|
31096
|
+
let fetched = false;
|
|
31097
|
+
let recordsByIds;
|
|
31098
|
+
if (this.historicGatherer) {
|
|
31099
|
+
({ fetched, recordsByIds } = await this.historicGatherer.Gather(ids.map(id => ({ Bruce: { ID: id } }))));
|
|
31100
|
+
}
|
|
31101
|
+
else {
|
|
31102
|
+
recordsByIds = (_b = (_a = this.simulation) === null || _a === void 0 ? void 0 : _a.MergeRecords({}, attrKey, ids)) !== null && _b !== void 0 ? _b : {};
|
|
31103
|
+
}
|
|
29555
31104
|
if (this.disposed) {
|
|
29556
31105
|
return;
|
|
29557
31106
|
}
|
|
31107
|
+
// A gather served from what is held changes nothing and runs every tick, so it stops here.
|
|
31108
|
+
if (!fetched && !stale && this.jointSeries.size) {
|
|
31109
|
+
return;
|
|
31110
|
+
}
|
|
31111
|
+
stale = false;
|
|
31112
|
+
let changed = this.absorbJointRecords(recordsByIds);
|
|
29558
31113
|
const posses = toPosses(recordsByIds[this.rootId] || []);
|
|
31114
|
+
changed = this.absorbRootRecords(posses, true) || changed;
|
|
31115
|
+
changed = this.absorbRootAttitude(recordsByIds[this.rootId] || [], true) || changed;
|
|
31116
|
+
if (changed) {
|
|
31117
|
+
this.repose();
|
|
31118
|
+
}
|
|
29559
31119
|
if (!posses.length) {
|
|
29560
31120
|
return;
|
|
29561
31121
|
}
|
|
31122
|
+
// Held for the trail alone; where the root is drawn comes from rootAt(), never from its smoothing.
|
|
29562
31123
|
if (!this.historicAnimation) {
|
|
29563
31124
|
this.historicAnimation = new exports.CesiumAnimatedProperty.AnimatePositionSeries({
|
|
29564
31125
|
posses: posses,
|
|
@@ -29572,15 +31133,21 @@
|
|
|
29572
31133
|
}
|
|
29573
31134
|
catch (e) {
|
|
29574
31135
|
console.error("AssemblyRenderManager.viewerDateTimeSub()", e);
|
|
31136
|
+
// A gather that throws would throw again straight away, so the retry waits for the next tick.
|
|
31137
|
+
stale = false;
|
|
29575
31138
|
}
|
|
29576
31139
|
finally {
|
|
29577
31140
|
gathering = false;
|
|
31141
|
+
// A change that landed mid-gather is not left for a tick that may never come on a paused clock.
|
|
31142
|
+
if (stale && !this.disposed) {
|
|
31143
|
+
gather();
|
|
31144
|
+
}
|
|
29578
31145
|
}
|
|
29579
31146
|
};
|
|
31147
|
+
this.regather = gather;
|
|
29580
31148
|
gather();
|
|
29581
31149
|
let lastTime = null;
|
|
29582
31150
|
const tickRemoval = this.viewer.clock.onTick.addEventListener(() => {
|
|
29583
|
-
var _a;
|
|
29584
31151
|
if (this.disposed) {
|
|
29585
31152
|
return;
|
|
29586
31153
|
}
|
|
@@ -29590,15 +31157,9 @@
|
|
|
29590
31157
|
}
|
|
29591
31158
|
lastTime = now;
|
|
29592
31159
|
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
|
-
});
|
|
31160
|
+
// Moving parts read the clock themselves when drawn, so the scene only needs a new frame.
|
|
31161
|
+
if (this.rootSeries.length || this.rootAttitude.length || this.animatedIds.size) {
|
|
31162
|
+
this.viewer.scene.requestRender();
|
|
29602
31163
|
}
|
|
29603
31164
|
});
|
|
29604
31165
|
this.viewerDateTimeChangeRemoval = () => {
|
|
@@ -29607,6 +31168,10 @@
|
|
|
29607
31168
|
(_a = this.historicGatherer) === null || _a === void 0 ? void 0 : _a.Dispose();
|
|
29608
31169
|
this.historicGatherer = null;
|
|
29609
31170
|
this.historicAnimation = null;
|
|
31171
|
+
this.regather = null;
|
|
31172
|
+
this.rootSeries = [];
|
|
31173
|
+
this.rootAttitude = [];
|
|
31174
|
+
this.pose = null;
|
|
29610
31175
|
};
|
|
29611
31176
|
}
|
|
29612
31177
|
/*
|
|
@@ -29614,7 +31179,7 @@
|
|
|
29614
31179
|
*/
|
|
29615
31180
|
applyRootTrack() {
|
|
29616
31181
|
var _a;
|
|
29617
|
-
if (!this.item.historicDrawTrack || !this.historicAnimation || this.
|
|
31182
|
+
if (!this.item.historicDrawTrack || !this.historicAnimation || this.trail) {
|
|
29618
31183
|
return;
|
|
29619
31184
|
}
|
|
29620
31185
|
const trackStyle = exports.EntityRenderEngine.GetTrackStyle({
|
|
@@ -29624,41 +31189,35 @@
|
|
|
29624
31189
|
if (!trackStyle) {
|
|
29625
31190
|
return;
|
|
29626
31191
|
}
|
|
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,
|
|
31192
|
+
this.trail = new HistoricTrail.Trail({
|
|
29644
31193
|
viewer: this.viewer,
|
|
29645
|
-
|
|
29646
|
-
|
|
31194
|
+
color: trackStyle.color,
|
|
31195
|
+
width: trackStyle.width,
|
|
31196
|
+
clampToGround: exports.EntityRenderEngine.GetHeightRefPolyline(Manager.GetRecordHeightRef(this.item))
|
|
31197
|
+
== Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
31198
|
+
getSeries: () => { var _a, _b; return (_b = (_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.GetSeries()) !== null && _b !== void 0 ? _b : []; },
|
|
31199
|
+
trailSeconds: HistoricTrail.GetTrailSeconds(this.item),
|
|
31200
|
+
// Where the root is drawn, so the trail ends on the model; nothing before the first record held.
|
|
31201
|
+
positionAt: (timeMs) => (this.rootSeries.length && timeMs >= this.rootSeries[0].timeMs ? this.rootPositionAt(timeMs) : null)
|
|
29647
31202
|
});
|
|
29648
31203
|
}
|
|
29649
31204
|
Dispose() {
|
|
29650
|
-
var _a;
|
|
31205
|
+
var _a, _b, _c;
|
|
29651
31206
|
if (this.disposed) {
|
|
29652
31207
|
return;
|
|
29653
31208
|
}
|
|
29654
31209
|
this.disposed = true;
|
|
29655
31210
|
(_a = this.viewerDateTimeChangeRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
29656
31211
|
this.viewerDateTimeChangeRemoval = null;
|
|
29657
|
-
|
|
29658
|
-
|
|
29659
|
-
|
|
29660
|
-
|
|
31212
|
+
(_b = this.simulationRemoval) === null || _b === void 0 ? void 0 : _b.call(this);
|
|
31213
|
+
this.simulationRemoval = null;
|
|
31214
|
+
this.apiEntities.clear();
|
|
31215
|
+
(_c = this.trail) === null || _c === void 0 ? void 0 : _c.Dispose();
|
|
31216
|
+
this.trail = null;
|
|
29661
31217
|
this.children.clear();
|
|
31218
|
+
this.localPositions.clear();
|
|
31219
|
+
this.jointSeries.clear();
|
|
31220
|
+
this.animatedIds.clear();
|
|
29662
31221
|
this.visualsManager.RemoveRegos({
|
|
29663
31222
|
menuItemId: this.item.id
|
|
29664
31223
|
});
|
|
@@ -30112,6 +31671,9 @@
|
|
|
30112
31671
|
this.OnSeriesUpdated.Trigger({ itemId, segments: [] });
|
|
30113
31672
|
}
|
|
30114
31673
|
}
|
|
31674
|
+
get Simulation() {
|
|
31675
|
+
return this.simulation;
|
|
31676
|
+
}
|
|
30115
31677
|
get Monitor() {
|
|
30116
31678
|
return this.sharedMonitor;
|
|
30117
31679
|
}
|
|
@@ -30137,6 +31699,7 @@
|
|
|
30137
31699
|
this.visualsRegister = visualsRegister;
|
|
30138
31700
|
this.sharedGetters = new exports.SharedGetters.Cache();
|
|
30139
31701
|
this.sharedHistoric = new SharedHistoricGetters.Cache();
|
|
31702
|
+
this.simulation = exports.EntitySimulation.Get(this.viewer);
|
|
30140
31703
|
this.sharedMonitor = new exports.CesiumViewMonitor.Monitor(this.viewer);
|
|
30141
31704
|
this.tilesetInitQueue = new InitQueueTileset(this.getters);
|
|
30142
31705
|
}
|
|
@@ -30350,7 +31913,8 @@
|
|
|
30350
31913
|
monitor: this.sharedMonitor,
|
|
30351
31914
|
item: params.item,
|
|
30352
31915
|
sharedGetters: this.sharedGetters,
|
|
30353
|
-
onSeriesDiscovered: (segment) => this.RecordSeriesSegment(rItem.id, segment)
|
|
31916
|
+
onSeriesDiscovered: (segment) => this.RecordSeriesSegment(rItem.id, segment),
|
|
31917
|
+
simulation: this.simulation
|
|
30354
31918
|
});
|
|
30355
31919
|
break;
|
|
30356
31920
|
case BModels.MenuItem.EType.EntitiesLoaded:
|
|
@@ -30359,7 +31923,8 @@
|
|
|
30359
31923
|
register: this.visualsRegister,
|
|
30360
31924
|
apiGetter: params.apiGetter,
|
|
30361
31925
|
monitor: this.sharedMonitor,
|
|
30362
|
-
item: params.item
|
|
31926
|
+
item: params.item,
|
|
31927
|
+
simulation: this.simulation
|
|
30363
31928
|
});
|
|
30364
31929
|
break;
|
|
30365
31930
|
case BModels.MenuItem.EType.EntitiesIds:
|
|
@@ -30369,7 +31934,8 @@
|
|
|
30369
31934
|
apiGetter: params.apiGetter,
|
|
30370
31935
|
monitor: this.sharedMonitor,
|
|
30371
31936
|
item: params.item,
|
|
30372
|
-
sharedHistoric: this.sharedHistoric
|
|
31937
|
+
sharedHistoric: this.sharedHistoric,
|
|
31938
|
+
simulation: this.simulation
|
|
30373
31939
|
});
|
|
30374
31940
|
break;
|
|
30375
31941
|
case BModels.MenuItem.EType.Entity:
|
|
@@ -30378,7 +31944,8 @@
|
|
|
30378
31944
|
register: this.visualsRegister,
|
|
30379
31945
|
apiGetter: params.apiGetter,
|
|
30380
31946
|
monitor: this.sharedMonitor,
|
|
30381
|
-
item: params.item
|
|
31947
|
+
item: params.item,
|
|
31948
|
+
simulation: this.simulation
|
|
30382
31949
|
});
|
|
30383
31950
|
break;
|
|
30384
31951
|
case BModels.MenuItem.EType.CadTileset:
|
|
@@ -30388,7 +31955,8 @@
|
|
|
30388
31955
|
getters: this.getters,
|
|
30389
31956
|
item: params.item,
|
|
30390
31957
|
modelSpace: params.modelSpace,
|
|
30391
|
-
initQueue: this.tilesetInitQueue
|
|
31958
|
+
initQueue: this.tilesetInitQueue,
|
|
31959
|
+
simulation: this.simulation
|
|
30392
31960
|
});
|
|
30393
31961
|
break;
|
|
30394
31962
|
case BModels.MenuItem.EType.Assembly:
|
|
@@ -30398,6 +31966,7 @@
|
|
|
30398
31966
|
getters: params.getters,
|
|
30399
31967
|
item: params.item,
|
|
30400
31968
|
modelSpace: params.modelSpace,
|
|
31969
|
+
simulation: this.simulation
|
|
30401
31970
|
});
|
|
30402
31971
|
break;
|
|
30403
31972
|
case BModels.MenuItem.EType.Osm:
|
|
@@ -30425,7 +31994,8 @@
|
|
|
30425
31994
|
getters: this.getters,
|
|
30426
31995
|
monitor: this.sharedMonitor,
|
|
30427
31996
|
item: params.item,
|
|
30428
|
-
initQueue: this.tilesetInitQueue
|
|
31997
|
+
initQueue: this.tilesetInitQueue,
|
|
31998
|
+
simulation: this.simulation
|
|
30429
31999
|
});
|
|
30430
32000
|
break;
|
|
30431
32001
|
case BModels.MenuItem.EType.Kml:
|
|
@@ -30449,7 +32019,8 @@
|
|
|
30449
32019
|
getters: params.getters,
|
|
30450
32020
|
item: params.item,
|
|
30451
32021
|
viewer: this.viewer,
|
|
30452
|
-
register: this.visualsRegister
|
|
32022
|
+
register: this.visualsRegister,
|
|
32023
|
+
simulation: this.simulation
|
|
30453
32024
|
});
|
|
30454
32025
|
break;
|
|
30455
32026
|
// Deprecated to support a few demos until new one is phased in.
|
|
@@ -30459,7 +32030,8 @@
|
|
|
30459
32030
|
apiGetter: params.apiGetter,
|
|
30460
32031
|
item: params.item,
|
|
30461
32032
|
register: this.visualsRegister,
|
|
30462
|
-
viewer: this.viewer
|
|
32033
|
+
viewer: this.viewer,
|
|
32034
|
+
simulation: this.simulation
|
|
30463
32035
|
});
|
|
30464
32036
|
break;
|
|
30465
32037
|
case BModels.MenuItem.EType.Relationships:
|
|
@@ -30467,7 +32039,8 @@
|
|
|
30467
32039
|
apiGetter: params.apiGetter,
|
|
30468
32040
|
item: params.item,
|
|
30469
32041
|
register: this.visualsRegister,
|
|
30470
|
-
viewer: this.viewer
|
|
32042
|
+
viewer: this.viewer,
|
|
32043
|
+
simulation: this.simulation
|
|
30471
32044
|
});
|
|
30472
32045
|
break;
|
|
30473
32046
|
case BModels.MenuItem.EType.GooglePhotoTileset:
|
|
@@ -30499,7 +32072,8 @@
|
|
|
30499
32072
|
item: params.item,
|
|
30500
32073
|
apiGetter: params.apiGetter,
|
|
30501
32074
|
monitor: this.sharedMonitor,
|
|
30502
|
-
visualsRegister: this.visualsRegister
|
|
32075
|
+
visualsRegister: this.visualsRegister,
|
|
32076
|
+
simulation: this.simulation
|
|
30503
32077
|
});
|
|
30504
32078
|
break;
|
|
30505
32079
|
// Any "none" type can be ignored. These are just containers for other items.
|
|
@@ -30712,6 +32286,63 @@
|
|
|
30712
32286
|
}
|
|
30713
32287
|
}
|
|
30714
32288
|
}
|
|
32289
|
+
/**
|
|
32290
|
+
* Draws Entities from data given here as well as, or instead of, the API's, until ClearSimulation is called.
|
|
32291
|
+
* @param params.set the simulation this belongs to, so it can be cleared apart from others. Default "default".
|
|
32292
|
+
* @param params.entities stand-ins that replace each Entity's record; API data for them is ignored.
|
|
32293
|
+
* @param params.patches partial Entities laid over each Entity; live API data shows where a patch is silent.
|
|
32294
|
+
* @param params.records historic records naming entityId, dateTime and only the data they change.
|
|
32295
|
+
* @param params.menuItemIds the items to redraw. By default every item already drawing one of the Entities.
|
|
32296
|
+
*/
|
|
32297
|
+
async Simulate(params) {
|
|
32298
|
+
const { set, entities, patches, records, menuItemIds } = params;
|
|
32299
|
+
this.simulation.SetEntities(entities, set);
|
|
32300
|
+
this.simulation.SetPatches(patches, set);
|
|
32301
|
+
this.simulation.SetRecords(records, set);
|
|
32302
|
+
const entityIds = [
|
|
32303
|
+
...(entities || []).map(x => { var _a; return (_a = x === null || x === void 0 ? void 0 : x.Bruce) === null || _a === void 0 ? void 0 : _a.ID; }),
|
|
32304
|
+
...(patches || []).map(x => { var _a; return (_a = x === null || x === void 0 ? void 0 : x.Bruce) === null || _a === void 0 ? void 0 : _a.ID; }),
|
|
32305
|
+
...(records || []).map(x => x === null || x === void 0 ? void 0 : x.entityId)
|
|
32306
|
+
];
|
|
32307
|
+
await this.reRenderSimulated(entityIds, menuItemIds);
|
|
32308
|
+
}
|
|
32309
|
+
/**
|
|
32310
|
+
* Stops simulating these Entities, or every Entity when none are named, and redraws them.
|
|
32311
|
+
* @param params.set the simulation to clear. By default every one.
|
|
32312
|
+
* @param params.entities clear the stand-ins and patches. Default true.
|
|
32313
|
+
* @param params.records clear the historic records. Default true.
|
|
32314
|
+
*/
|
|
32315
|
+
async ClearSimulation(params) {
|
|
32316
|
+
var _a;
|
|
32317
|
+
const entityIds = (_a = params === null || params === void 0 ? void 0 : params.entityIds) !== null && _a !== void 0 ? _a : [
|
|
32318
|
+
...this.simulation.GetEntityIds(),
|
|
32319
|
+
...this.simulation.GetRecordEntityIds()
|
|
32320
|
+
];
|
|
32321
|
+
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 });
|
|
32322
|
+
await this.reRenderSimulated(entityIds, params === null || params === void 0 ? void 0 : params.menuItemIds);
|
|
32323
|
+
}
|
|
32324
|
+
/*
|
|
32325
|
+
* Redraws simulated Entities only in the items holding a visual for them, unless the caller names the items.
|
|
32326
|
+
*/
|
|
32327
|
+
async reRenderSimulated(entityIds, menuItemIds) {
|
|
32328
|
+
const ids = Array.from(new Set(entityIds.filter(x => !!x)));
|
|
32329
|
+
if (!ids.length) {
|
|
32330
|
+
return;
|
|
32331
|
+
}
|
|
32332
|
+
const items = (menuItemIds === null || menuItemIds === void 0 ? void 0 : menuItemIds.length) ? this.items.filter(x => menuItemIds.includes(x.id)) : this.items;
|
|
32333
|
+
for (const item of items) {
|
|
32334
|
+
// Some managers follow the store themselves, and redrawing them here would only repeat that.
|
|
32335
|
+
if (!item.renderManager || item.renderManager.FollowsSimulation) {
|
|
32336
|
+
continue;
|
|
32337
|
+
}
|
|
32338
|
+
const drawn = (menuItemIds === null || menuItemIds === void 0 ? void 0 : menuItemIds.length)
|
|
32339
|
+
? ids
|
|
32340
|
+
: ids.filter(id => this.visualsRegister.GetRego({ entityId: id, menuItemId: item.id }));
|
|
32341
|
+
if (drawn.length) {
|
|
32342
|
+
await item.renderManager.ReRender({ entityIds: drawn, force: true });
|
|
32343
|
+
}
|
|
32344
|
+
}
|
|
32345
|
+
}
|
|
30715
32346
|
}
|
|
30716
32347
|
MenuItemManager.Manager = Manager;
|
|
30717
32348
|
})(exports.MenuItemManager || (exports.MenuItemManager = {}));
|
|
@@ -39248,6 +40879,7 @@
|
|
|
39248
40879
|
}
|
|
39249
40880
|
class WidgetInfoView extends exports.Widget.AWidget {
|
|
39250
40881
|
constructor(params) {
|
|
40882
|
+
var _a;
|
|
39251
40883
|
super(params);
|
|
39252
40884
|
this.STYLESHEET_ID = "nextspace-info-view-stylesheet";
|
|
39253
40885
|
this._generateStyles();
|
|
@@ -39257,10 +40889,19 @@
|
|
|
39257
40889
|
this._updateInfoView();
|
|
39258
40890
|
}
|
|
39259
40891
|
});
|
|
40892
|
+
// The selected Entity is read once per selection, so a change to its simulation reads it again.
|
|
40893
|
+
this._simulationRemoval = (_a = this._manager.Simulation) === null || _a === void 0 ? void 0 : _a.OnChanged.Subscribe((change) => {
|
|
40894
|
+
if (this._lastSelectedId && change.entityIds.includes(this._lastSelectedId)) {
|
|
40895
|
+
this._lastSelectedId = null;
|
|
40896
|
+
this._updateInfoView();
|
|
40897
|
+
}
|
|
40898
|
+
});
|
|
39260
40899
|
}
|
|
39261
40900
|
Dispose() {
|
|
40901
|
+
var _a;
|
|
39262
40902
|
super.Dispose();
|
|
39263
40903
|
this._updateRemoval();
|
|
40904
|
+
(_a = this._simulationRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
39264
40905
|
}
|
|
39265
40906
|
_generateStyles() {
|
|
39266
40907
|
if (document.getElementById(this.STYLESHEET_ID)) {
|
|
@@ -39722,7 +41363,7 @@
|
|
|
39722
41363
|
}
|
|
39723
41364
|
}
|
|
39724
41365
|
async _updateInfoView() {
|
|
39725
|
-
var
|
|
41366
|
+
var _a, _c, _d, _e, _f;
|
|
39726
41367
|
const selectedIds = this._manager.VisualsRegister.GetSelected();
|
|
39727
41368
|
if (selectedIds.length <= 0) {
|
|
39728
41369
|
this._element.style.display = "none";
|
|
@@ -39744,17 +41385,20 @@
|
|
|
39744
41385
|
this._summary.innerHTML = "";
|
|
39745
41386
|
this._imageContainer.style.display = "none";
|
|
39746
41387
|
const api = this._apiGetters.GetBruceApi();
|
|
39747
|
-
|
|
41388
|
+
// A simulated Entity is shown as simulated: a stand-in as is, a patch over what the API has.
|
|
41389
|
+
const simulation = this._manager.Simulation;
|
|
41390
|
+
let entity = (_a = simulation === null || simulation === void 0 ? void 0 : simulation.GetEntity(firstId)) !== null && _a !== void 0 ? _a : (await BModels.Entity.Get({
|
|
39748
41391
|
entityId: firstId,
|
|
39749
41392
|
api: api,
|
|
39750
41393
|
migrated: true,
|
|
39751
41394
|
expandLocation: DISPLAY_ASSEMBLY_INFO
|
|
39752
|
-
});
|
|
41395
|
+
})).entity;
|
|
41396
|
+
entity = entity && simulation ? simulation.Resolve(firstId, entity) : entity;
|
|
39753
41397
|
if (!entity) {
|
|
39754
41398
|
throw (new Error("Could not get entity."));
|
|
39755
41399
|
}
|
|
39756
41400
|
const { entityType } = await BModels.EntityType.Get({
|
|
39757
|
-
entityTypeId: (
|
|
41401
|
+
entityTypeId: (_c = entity.Bruce) === null || _c === void 0 ? void 0 : _c["EntityType.ID"],
|
|
39758
41402
|
api: api
|
|
39759
41403
|
});
|
|
39760
41404
|
let name = BModels.Entity.CalculateName({
|
|
@@ -39777,7 +41421,7 @@
|
|
|
39777
41421
|
const defaultImage = images.length ? images[0] : null;
|
|
39778
41422
|
if (defaultImage) {
|
|
39779
41423
|
this._imageContainer.style.display = "flex";
|
|
39780
|
-
const url = (
|
|
41424
|
+
const url = (_d = defaultImage.URL) !== null && _d !== void 0 ? _d : BModels.ClientFile.GetUrl({
|
|
39781
41425
|
fileId: defaultImage["ClientFile.ID"],
|
|
39782
41426
|
api: api,
|
|
39783
41427
|
viaCdn: true
|
|
@@ -39790,7 +41434,7 @@
|
|
|
39790
41434
|
this._summary.appendChild(detailsTitle);
|
|
39791
41435
|
// TODO: Selection for what mode instead of always doing "all".
|
|
39792
41436
|
const attributes = gatherAttributes(EMode.ShowAll, entity, entityType);
|
|
39793
|
-
const groups = groupAttributes(attributes, (
|
|
41437
|
+
const groups = groupAttributes(attributes, (_f = (_e = entityType.DataSchema) === null || _e === void 0 ? void 0 : _e.Structure) !== null && _f !== void 0 ? _f : []);
|
|
39794
41438
|
for (const group of groups) {
|
|
39795
41439
|
this._generateAttrGroup(entityType, entity, group);
|
|
39796
41440
|
}
|
|
@@ -42384,7 +44028,7 @@
|
|
|
42384
44028
|
* @param params
|
|
42385
44029
|
*/
|
|
42386
44030
|
async function GetLocation(params) {
|
|
42387
|
-
var _a, _b, _c, _d;
|
|
44031
|
+
var _a, _b, _c, _d, _e;
|
|
42388
44032
|
let { api, viewer, samples, visualRegister, minimumAlt, paddingAlt } = params;
|
|
42389
44033
|
if (!paddingAlt) {
|
|
42390
44034
|
paddingAlt = 0;
|
|
@@ -42932,6 +44576,13 @@
|
|
|
42932
44576
|
recordSamples.push(sample);
|
|
42933
44577
|
}
|
|
42934
44578
|
}
|
|
44579
|
+
// A simulated Entity is where its blob says, never where the API has it.
|
|
44580
|
+
const simulation = exports.EntitySimulation.Get(viewer);
|
|
44581
|
+
for (const sample of recordSamples) {
|
|
44582
|
+
if (!sample.entity && sample.entityId) {
|
|
44583
|
+
sample.entity = (_e = simulation === null || simulation === void 0 ? void 0 : simulation.GetEntity(sample.entityId)) !== null && _e !== void 0 ? _e : sample.entity;
|
|
44584
|
+
}
|
|
44585
|
+
}
|
|
42935
44586
|
// Bulk requesting Entity records.
|
|
42936
44587
|
try {
|
|
42937
44588
|
const toSearchIds = recordSamples.filter(x => !x.entity && x.entityId).map(x => x.entityId);
|
|
@@ -42952,7 +44603,8 @@
|
|
|
42952
44603
|
for (let i = 0; i < recordSamples.length; i++) {
|
|
42953
44604
|
const sample = recordSamples[i];
|
|
42954
44605
|
if (!sample.entity && sample.entityId) {
|
|
42955
|
-
|
|
44606
|
+
const read = entitiesMap.get(sample.entityId);
|
|
44607
|
+
sample.entity = read && simulation ? simulation.Overlay(read) : read;
|
|
42956
44608
|
}
|
|
42957
44609
|
}
|
|
42958
44610
|
}
|
|
@@ -42966,6 +44618,11 @@
|
|
|
42966
44618
|
// We have to detect whatever is an Assembly Entity and expand it.
|
|
42967
44619
|
try {
|
|
42968
44620
|
const needsExpansion = recordSamples.filter(x => {
|
|
44621
|
+
var _a;
|
|
44622
|
+
// Expanding reads the API's record, which would replace the stand-in or undo the patch.
|
|
44623
|
+
if (simulation === null || simulation === void 0 ? void 0 : simulation.HasBlob((_a = x.entity.Bruce) === null || _a === void 0 ? void 0 : _a.ID)) {
|
|
44624
|
+
return false;
|
|
44625
|
+
}
|
|
42969
44626
|
const assemblyPos = BModels.Entity.GetValue({
|
|
42970
44627
|
entity: x.entity,
|
|
42971
44628
|
path: ["Bruce", "AssemblyPosition"]
|
|
@@ -43324,6 +44981,21 @@
|
|
|
43324
44981
|
return Cesium.Quaternion.multiply(combined, _assemblyAxisShift, new Cesium.Quaternion());
|
|
43325
44982
|
}
|
|
43326
44983
|
EntityUtils.GetAssemblyOrientation = GetAssemblyOrientation;
|
|
44984
|
+
/**
|
|
44985
|
+
* Returns the orientation a part's model is drawn with, for its world matrix within the root's frame.
|
|
44986
|
+
* @param rootFrame the root's frame in the world, eg. from Transforms.headingPitchRollToFixedFrame.
|
|
44987
|
+
* @param world the part's matrix within the root's frame.
|
|
44988
|
+
*/
|
|
44989
|
+
function GetAssemblyOrientationInFrame(rootFrame, world) {
|
|
44990
|
+
if (!rootFrame || !world) {
|
|
44991
|
+
return null;
|
|
44992
|
+
}
|
|
44993
|
+
const combined = Cesium.Matrix4.multiply(rootFrame, world, new Cesium.Matrix4());
|
|
44994
|
+
const rotation = Cesium.Matrix4.getRotation(combined, new Cesium.Matrix3());
|
|
44995
|
+
const q = Cesium.Quaternion.fromRotationMatrix(rotation);
|
|
44996
|
+
return Cesium.Quaternion.multiply(q, _assemblyAxisShift, new Cesium.Quaternion());
|
|
44997
|
+
}
|
|
44998
|
+
EntityUtils.GetAssemblyOrientationInFrame = GetAssemblyOrientationInFrame;
|
|
43327
44999
|
/**
|
|
43328
45000
|
* Returns the position of the entity.
|
|
43329
45001
|
* This is an async variant that checks for related assemblies.
|
|
@@ -43333,6 +45005,18 @@
|
|
|
43333
45005
|
*/
|
|
43334
45006
|
async function GetPosAsync(params) {
|
|
43335
45007
|
let { viewer, entityId, entity, visualRegister, returnHeightRef, recordHeightRef, api } = params;
|
|
45008
|
+
// A simulated Entity is where its stand-in says, or where its patch puts the API's record.
|
|
45009
|
+
const simulation = exports.EntitySimulation.Get(viewer);
|
|
45010
|
+
entity = entity !== null && entity !== void 0 ? entity : simulation === null || simulation === void 0 ? void 0 : simulation.GetEntity(entityId);
|
|
45011
|
+
if (!entity && entityId && (simulation === null || simulation === void 0 ? void 0 : simulation.HasBlob(entityId))) {
|
|
45012
|
+
try {
|
|
45013
|
+
const read = (await BModels.Entity.Get({ api, entityId, expandLocation: false, migrated: true })).entity;
|
|
45014
|
+
entity = read ? simulation.Overlay(read) : null;
|
|
45015
|
+
}
|
|
45016
|
+
catch (e) {
|
|
45017
|
+
console.error(e);
|
|
45018
|
+
}
|
|
45019
|
+
}
|
|
43336
45020
|
// We have issues where imported BRZ files have improper expandLocation=true info.
|
|
43337
45021
|
// As a result we'll double-request the data.
|
|
43338
45022
|
// If there is a location then we won't bother using expanded information.
|
|
@@ -53294,7 +54978,7 @@ void main() {
|
|
|
53294
54978
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
53295
54979
|
})(exports.StyleUtils || (exports.StyleUtils = {}));
|
|
53296
54980
|
|
|
53297
|
-
const VERSION = "7.6.
|
|
54981
|
+
const VERSION = "7.6.2";
|
|
53298
54982
|
/**
|
|
53299
54983
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
53300
54984
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|