bruce-cesium 7.2.4 → 7.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bruce-cesium.es5.js +386 -52
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +384 -50
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/internal/cesium-utils.js +32 -1
- package/dist/lib/internal/cesium-utils.js.map +1 -1
- package/dist/lib/rendering/entity-gatherer.js +170 -17
- package/dist/lib/rendering/entity-gatherer.js.map +1 -1
- package/dist/lib/rendering/menu-item-manager.js +1 -0
- package/dist/lib/rendering/menu-item-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/historic-utils.js +91 -24
- package/dist/lib/rendering/render-managers/common/historic-utils.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js +1 -0
- package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/entities/entities-render-manager.js +1 -0
- package/dist/lib/rendering/render-managers/entities/entities-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-entities-render-manager.js +61 -3
- package/dist/lib/rendering/render-managers/tilesets/tileset-entities-render-manager.js.map +1 -1
- package/dist/lib/rendering/texture-frame-series-animator.js +20 -3
- package/dist/lib/rendering/texture-frame-series-animator.js.map +1 -1
- package/dist/lib/rendering/tileset-styler.js +10 -1
- package/dist/lib/rendering/tileset-styler.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/internal/cesium-utils.d.ts +9 -0
- package/dist/types/rendering/entity-gatherer.d.ts +24 -0
- package/dist/types/rendering/render-managers/common/historic-utils.d.ts +30 -5
- package/dist/types/rendering/render-managers/tilesets/tileset-entities-render-manager.d.ts +5 -0
- package/dist/types/rendering/texture-frame-series-animator.d.ts +1 -0
- package/dist/types/rendering/tileset-styler.d.ts +3 -0
- package/package.json +1 -1
package/dist/bruce-cesium.umd.js
CHANGED
|
@@ -2883,6 +2883,36 @@
|
|
|
2883
2883
|
function ColorToCColor(color) {
|
|
2884
2884
|
return new Cesium.Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
|
|
2885
2885
|
}
|
|
2886
|
+
const degreesCache = new WeakMap();
|
|
2887
|
+
/**
|
|
2888
|
+
* Returns a world position's latitude and longitude in degrees, or null when it has none.
|
|
2889
|
+
* @param pos
|
|
2890
|
+
*/
|
|
2891
|
+
function CartesianToDegrees(pos) {
|
|
2892
|
+
if (!pos) {
|
|
2893
|
+
return null;
|
|
2894
|
+
}
|
|
2895
|
+
const cached = degreesCache.get(pos);
|
|
2896
|
+
if (cached) {
|
|
2897
|
+
return cached;
|
|
2898
|
+
}
|
|
2899
|
+
let carto;
|
|
2900
|
+
try {
|
|
2901
|
+
carto = Cesium.Cartographic.fromCartesian(pos);
|
|
2902
|
+
}
|
|
2903
|
+
catch {
|
|
2904
|
+
return null;
|
|
2905
|
+
}
|
|
2906
|
+
if (!carto) {
|
|
2907
|
+
return null;
|
|
2908
|
+
}
|
|
2909
|
+
const degrees = {
|
|
2910
|
+
lat: Cesium.Math.toDegrees(carto.latitude),
|
|
2911
|
+
lon: Cesium.Math.toDegrees(carto.longitude)
|
|
2912
|
+
};
|
|
2913
|
+
degreesCache.set(pos, degrees);
|
|
2914
|
+
return degrees;
|
|
2915
|
+
}
|
|
2886
2916
|
/**
|
|
2887
2917
|
* Removes duplicate points in a row and returns a new array.
|
|
2888
2918
|
* Passed array is not mutated.
|
|
@@ -10737,41 +10767,107 @@
|
|
|
10737
10767
|
return Math.round(minMs + ((maxMs - minMs) * progress));
|
|
10738
10768
|
}
|
|
10739
10769
|
HistoricFetchOrder.IntervalFor = IntervalFor;
|
|
10770
|
+
// Upper bounds in metres for the distance bands, nearest first.
|
|
10771
|
+
HistoricFetchOrder.DEFAULT_BANDS = [500, 2000, 10000, 50000];
|
|
10740
10772
|
/**
|
|
10741
|
-
*
|
|
10742
|
-
*
|
|
10743
|
-
* Bands rather than a true sort, so a small camera move does not reshuffle the whole queue and
|
|
10744
|
-
* restart it. What the user is looking at resolves first either way.
|
|
10773
|
+
* Resolves what to order by from the view monitor, falling back to the camera itself.
|
|
10745
10774
|
*/
|
|
10746
|
-
function
|
|
10775
|
+
function FocusFrom(params) {
|
|
10747
10776
|
var _a;
|
|
10748
|
-
const { viewer,
|
|
10749
|
-
|
|
10750
|
-
|
|
10777
|
+
const { viewer, monitor } = params;
|
|
10778
|
+
let origin = null;
|
|
10779
|
+
let bounds = null;
|
|
10780
|
+
try {
|
|
10781
|
+
// Null whenever the view has no ground intersection, eg. a camera aimed at the sky.
|
|
10782
|
+
const target = monitor === null || monitor === void 0 ? void 0 : monitor.GetTarget();
|
|
10783
|
+
if (target && isFinite(target.latitude) && isFinite(target.longitude)) {
|
|
10784
|
+
origin = Cesium.Cartesian3.fromDegrees(target.longitude, target.latitude);
|
|
10785
|
+
}
|
|
10786
|
+
bounds = (monitor === null || monitor === void 0 ? void 0 : monitor.GetBounds()) || null;
|
|
10787
|
+
}
|
|
10788
|
+
catch {
|
|
10789
|
+
origin = null;
|
|
10790
|
+
bounds = null;
|
|
10791
|
+
}
|
|
10792
|
+
if (!origin) {
|
|
10793
|
+
origin = (_a = viewer === null || viewer === void 0 ? void 0 : viewer.camera) === null || _a === void 0 ? void 0 : _a.position;
|
|
10794
|
+
}
|
|
10795
|
+
if (!origin) {
|
|
10796
|
+
return null;
|
|
10797
|
+
}
|
|
10798
|
+
return bounds ? { origin, bounds } : { origin };
|
|
10799
|
+
}
|
|
10800
|
+
HistoricFetchOrder.FocusFrom = FocusFrom;
|
|
10801
|
+
/**
|
|
10802
|
+
* Returns the Entities grouped nearest first, on screen ahead of off screen.
|
|
10803
|
+
*/
|
|
10804
|
+
function ByCameraDistance(params) {
|
|
10805
|
+
const { viewer, entities, monitor } = params;
|
|
10806
|
+
return ByCameraDistanceOf({
|
|
10807
|
+
focus: FocusFrom({ viewer, monitor }),
|
|
10808
|
+
items: entities,
|
|
10809
|
+
posOf: (entity) => SafePos(entity, viewer),
|
|
10810
|
+
bands: params.bands
|
|
10811
|
+
});
|
|
10812
|
+
}
|
|
10813
|
+
HistoricFetchOrder.ByCameraDistance = ByCameraDistance;
|
|
10814
|
+
/**
|
|
10815
|
+
* Bands anything that can name its own world position, on the same bounds as the Entity form.
|
|
10816
|
+
*/
|
|
10817
|
+
function ByCameraDistanceOf(params) {
|
|
10818
|
+
const { focus, items, posOf } = params;
|
|
10819
|
+
const bands = params.bands || HistoricFetchOrder.DEFAULT_BANDS;
|
|
10820
|
+
if (!(items === null || items === void 0 ? void 0 : items.length)) {
|
|
10751
10821
|
return [];
|
|
10752
10822
|
}
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10823
|
+
if (!(focus === null || focus === void 0 ? void 0 : focus.origin)) {
|
|
10824
|
+
return [items];
|
|
10825
|
+
}
|
|
10826
|
+
// One band past the named bounds, for everything beyond the last of them. Then the same
|
|
10827
|
+
// again for what is off screen, so nothing visible waits behind something that is not.
|
|
10828
|
+
const perTier = bands.length + 1;
|
|
10829
|
+
const offScreenTier = focus.bounds ? perTier : 0;
|
|
10830
|
+
const placeless = offScreenTier + perTier;
|
|
10831
|
+
const grouped = [];
|
|
10832
|
+
for (let i = 0; i <= placeless; i++) {
|
|
10833
|
+
grouped.push([]);
|
|
10756
10834
|
}
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
const pos = SafePos(entity, viewer);
|
|
10835
|
+
for (const item of items) {
|
|
10836
|
+
// An item with no position falls to the last group rather than blocking the near ones.
|
|
10837
|
+
const pos = posOf(item);
|
|
10761
10838
|
if (!pos) {
|
|
10762
|
-
|
|
10839
|
+
grouped[placeless].push(item);
|
|
10763
10840
|
continue;
|
|
10764
10841
|
}
|
|
10765
|
-
const distance = Cesium.Cartesian3.distance(
|
|
10766
|
-
let
|
|
10767
|
-
if (
|
|
10768
|
-
|
|
10842
|
+
const distance = Cesium.Cartesian3.distance(focus.origin, pos);
|
|
10843
|
+
let band = bands.findIndex(bound => distance <= bound);
|
|
10844
|
+
if (band < 0) {
|
|
10845
|
+
band = bands.length;
|
|
10769
10846
|
}
|
|
10770
|
-
|
|
10847
|
+
grouped[(focus.bounds && !InBounds(pos, focus.bounds)) ? offScreenTier + band : band].push(item);
|
|
10771
10848
|
}
|
|
10772
|
-
return
|
|
10849
|
+
return grouped.filter(group => group.length > 0);
|
|
10773
10850
|
}
|
|
10774
|
-
HistoricFetchOrder.
|
|
10851
|
+
HistoricFetchOrder.ByCameraDistanceOf = ByCameraDistanceOf;
|
|
10852
|
+
/*
|
|
10853
|
+
* Returns whether a world position sits inside a ground rectangle given in degrees.
|
|
10854
|
+
*/
|
|
10855
|
+
function InBounds(pos, bounds) {
|
|
10856
|
+
const degrees = CartesianToDegrees(pos);
|
|
10857
|
+
if (!degrees) {
|
|
10858
|
+
return false;
|
|
10859
|
+
}
|
|
10860
|
+
const { lat, lon } = degrees;
|
|
10861
|
+
if (lat < bounds.south || lat > bounds.north) {
|
|
10862
|
+
return false;
|
|
10863
|
+
}
|
|
10864
|
+
// A view straddling the antimeridian reports west east of east, so the span is the outside.
|
|
10865
|
+
if (bounds.west > bounds.east) {
|
|
10866
|
+
return lon >= bounds.west || lon <= bounds.east;
|
|
10867
|
+
}
|
|
10868
|
+
return lon >= bounds.west && lon <= bounds.east;
|
|
10869
|
+
}
|
|
10870
|
+
HistoricFetchOrder.InBounds = InBounds;
|
|
10775
10871
|
/*
|
|
10776
10872
|
* Returns an Entity's world position, or null when it has none to place it by.
|
|
10777
10873
|
*/
|
|
@@ -11089,7 +11185,7 @@
|
|
|
11089
11185
|
}
|
|
11090
11186
|
if (plan.detail) {
|
|
11091
11187
|
const bands = entities.length > HistoricFetchOrder.SMALL_SET
|
|
11092
|
-
? HistoricFetchOrder.ByCameraDistance({ viewer, entities })
|
|
11188
|
+
? HistoricFetchOrder.ByCameraDistance({ viewer, entities, monitor: this.params.monitor })
|
|
11093
11189
|
: [entities];
|
|
11094
11190
|
for (const range of this.cache.MissingRanges(plan.detail.start, plan.detail.stop)) {
|
|
11095
11191
|
if (this.disposed) {
|
|
@@ -11253,6 +11349,7 @@
|
|
|
11253
11349
|
this.onSeriesDiscovered = onSeriesDiscovered;
|
|
11254
11350
|
this.historicGatherer = new HistoricGatherer({
|
|
11255
11351
|
viewer: this.viewer,
|
|
11352
|
+
monitor: this.monitor,
|
|
11256
11353
|
getApi: () => this.apiGetter.getApi(),
|
|
11257
11354
|
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
11258
11355
|
// A second either side, to take in records sitting exactly on the boundary.
|
|
@@ -13358,6 +13455,7 @@
|
|
|
13358
13455
|
this.visualsManager = visualsManager;
|
|
13359
13456
|
this.historicGatherer = new HistoricGatherer({
|
|
13360
13457
|
viewer: this.viewer,
|
|
13458
|
+
monitor: this.monitor,
|
|
13361
13459
|
getApi: () => this.apiGetter.getApi(),
|
|
13362
13460
|
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
13363
13461
|
// Padding either side of a requested range, for clock desync between us and the server.
|
|
@@ -13992,6 +14090,18 @@
|
|
|
13992
14090
|
this.lastFoundDateTimes = new Map();
|
|
13993
14091
|
// ID of Entity IDs that need to be requested.
|
|
13994
14092
|
this.eIdQueue = [];
|
|
14093
|
+
// Membership mirror of eIdQueue for quick checks.
|
|
14094
|
+
this.eIdQueued = new Set();
|
|
14095
|
+
// Resolves where an Entity sits without reading its record, when the caller can say.
|
|
14096
|
+
// Unset leaves the queue in insertion order, which is what sources that bake no coordinates get.
|
|
14097
|
+
this.positionOf = null;
|
|
14098
|
+
// How many IDs at the front of the queue were explicitly asked for first.
|
|
14099
|
+
// Camera ordering leaves those alone, since an explicit re-render outranks proximity.
|
|
14100
|
+
this.priorityCount = 0;
|
|
14101
|
+
// View focus the queue was last banded from.
|
|
14102
|
+
this.lastOrderFocus = null;
|
|
14103
|
+
// Reports what the camera is aimed at, rather than only where it sits.
|
|
14104
|
+
this.monitor = null;
|
|
13995
14105
|
// All IDs that have ever been queued.
|
|
13996
14106
|
// When nothing is in queue, we'll re-request the existing IDs based on timeline changes.
|
|
13997
14107
|
this.allEIds = new Set();
|
|
@@ -14091,6 +14201,9 @@
|
|
|
14091
14201
|
return;
|
|
14092
14202
|
}
|
|
14093
14203
|
this.eIdQueue = [];
|
|
14204
|
+
this.eIdQueued.clear();
|
|
14205
|
+
this.priorityCount = 0;
|
|
14206
|
+
this.lastOrderFocus = null;
|
|
14094
14207
|
this.allEIds.clear();
|
|
14095
14208
|
this.lastFoundDateTimes.clear();
|
|
14096
14209
|
this.lastDateTime = null;
|
|
@@ -14100,29 +14213,148 @@
|
|
|
14100
14213
|
return;
|
|
14101
14214
|
}
|
|
14102
14215
|
this.eIdQueue = Array.from(this.allEIds);
|
|
14216
|
+
this.eIdQueued = new Set(this.eIdQueue);
|
|
14217
|
+
this.priorityCount = 0;
|
|
14218
|
+
this.lastOrderFocus = null;
|
|
14219
|
+
}
|
|
14220
|
+
/**
|
|
14221
|
+
* Supplies a lookup from Entity ID to world position, letting the queue resolve what the camera
|
|
14222
|
+
* is nearest first. Sources that cannot answer should not call this, and are served in order.
|
|
14223
|
+
*/
|
|
14224
|
+
SetPositionSource(positionOf) {
|
|
14225
|
+
this.positionOf = positionOf;
|
|
14226
|
+
this.lastOrderFocus = null;
|
|
14227
|
+
}
|
|
14228
|
+
/**
|
|
14229
|
+
* Supplies the view monitor, so the order follows the ground the camera is aimed at and prefers
|
|
14230
|
+
* what is on screen. Without one the ordering falls back to distance from the camera itself.
|
|
14231
|
+
*/
|
|
14232
|
+
SetViewMonitor(monitor) {
|
|
14233
|
+
this.monitor = monitor;
|
|
14234
|
+
this.lastOrderFocus = null;
|
|
14235
|
+
}
|
|
14236
|
+
/**
|
|
14237
|
+
* Re-bands the pending queue so the nearest Entities are requested first.
|
|
14238
|
+
*/
|
|
14239
|
+
orderQueueByCamera() {
|
|
14240
|
+
if (!this.positionOf || this.eIdQueue.length < EntityGatherer.MIN_ORDER_QUEUE) {
|
|
14241
|
+
return;
|
|
14242
|
+
}
|
|
14243
|
+
const focus = HistoricFetchOrder.FocusFrom({ viewer: this.viewer, monitor: this.monitor });
|
|
14244
|
+
if (!focus) {
|
|
14245
|
+
return;
|
|
14246
|
+
}
|
|
14247
|
+
// Re-banding on every batch would cost a full pass per request for no change in the answer.
|
|
14248
|
+
// Measured on the focus, so panning across the ground counts even when the eye barely moves.
|
|
14249
|
+
if (this.lastOrderFocus && !EntityGatherer.boundsChanged(this.lastOrderFocus, focus) &&
|
|
14250
|
+
Cesium.Cartesian3.distance(this.lastOrderFocus.origin, focus.origin) < EntityGatherer.REORDER_MOVE_METRES) {
|
|
14251
|
+
return;
|
|
14252
|
+
}
|
|
14253
|
+
this.lastOrderFocus = focus;
|
|
14254
|
+
const priority = this.priorityCount > 0 ? this.eIdQueue.slice(0, this.priorityCount) : [];
|
|
14255
|
+
const rest = this.priorityCount > 0 ? this.eIdQueue.slice(this.priorityCount) : this.eIdQueue;
|
|
14256
|
+
if (!rest.length) {
|
|
14257
|
+
return;
|
|
14258
|
+
}
|
|
14259
|
+
this.eIdQueue = priority.concat(this.bandIds(rest, focus));
|
|
14260
|
+
}
|
|
14261
|
+
/*
|
|
14262
|
+
* Returns whether the visible rectangle differs enough to change what counts as on screen.
|
|
14263
|
+
*/
|
|
14264
|
+
static boundsChanged(a, b) {
|
|
14265
|
+
if (!a.bounds || !b.bounds) {
|
|
14266
|
+
return Boolean(a.bounds) !== Boolean(b.bounds);
|
|
14267
|
+
}
|
|
14268
|
+
return (a.bounds.north !== b.bounds.north ||
|
|
14269
|
+
a.bounds.south !== b.bounds.south ||
|
|
14270
|
+
a.bounds.east !== b.bounds.east ||
|
|
14271
|
+
a.bounds.west !== b.bounds.west);
|
|
14272
|
+
}
|
|
14273
|
+
/*
|
|
14274
|
+
* Returns the IDs reordered nearest band first, or unchanged when there is nothing to order by.
|
|
14275
|
+
*/
|
|
14276
|
+
bandIds(entityIds, focus) {
|
|
14277
|
+
const from = focus || HistoricFetchOrder.FocusFrom({ viewer: this.viewer, monitor: this.monitor });
|
|
14278
|
+
if (!this.positionOf || !from || !entityIds.length) {
|
|
14279
|
+
return entityIds;
|
|
14280
|
+
}
|
|
14281
|
+
const banded = HistoricFetchOrder.ByCameraDistanceOf({
|
|
14282
|
+
focus: from,
|
|
14283
|
+
items: entityIds,
|
|
14284
|
+
posOf: (entityId) => {
|
|
14285
|
+
try {
|
|
14286
|
+
return this.positionOf(entityId);
|
|
14287
|
+
}
|
|
14288
|
+
catch {
|
|
14289
|
+
return null;
|
|
14290
|
+
}
|
|
14291
|
+
}
|
|
14292
|
+
});
|
|
14293
|
+
const ordered = [];
|
|
14294
|
+
for (const band of banded) {
|
|
14295
|
+
for (const entityId of band) {
|
|
14296
|
+
ordered.push(entityId);
|
|
14297
|
+
}
|
|
14298
|
+
}
|
|
14299
|
+
return ordered;
|
|
14103
14300
|
}
|
|
14104
14301
|
Queue(entityIds, topOfQueue = false) {
|
|
14105
14302
|
if (this.disposed || !(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
|
|
14106
14303
|
return;
|
|
14107
14304
|
}
|
|
14108
14305
|
let changes = 0;
|
|
14109
|
-
|
|
14110
|
-
|
|
14111
|
-
|
|
14112
|
-
|
|
14113
|
-
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
this.
|
|
14118
|
-
|
|
14306
|
+
if (topOfQueue) {
|
|
14307
|
+
// Walked back to front so a repeated ID keeps the position of its last occurrence, then
|
|
14308
|
+
// laid down in that order, which is where inserting one at a time leaves them.
|
|
14309
|
+
const toFront = [];
|
|
14310
|
+
const promoting = new Set();
|
|
14311
|
+
let anyAlreadyQueued = false;
|
|
14312
|
+
for (let i = entityIds.length - 1; i >= 0; i--) {
|
|
14313
|
+
const eId = entityIds[i];
|
|
14314
|
+
this.allEIds.add(eId);
|
|
14315
|
+
if (promoting.has(eId)) {
|
|
14316
|
+
continue;
|
|
14317
|
+
}
|
|
14318
|
+
promoting.add(eId);
|
|
14319
|
+
toFront.push(eId);
|
|
14320
|
+
if (this.eIdQueued.has(eId)) {
|
|
14321
|
+
anyAlreadyQueued = true;
|
|
14322
|
+
}
|
|
14323
|
+
}
|
|
14324
|
+
if (anyAlreadyQueued && this.eIdQueue.length) {
|
|
14325
|
+
const kept = [];
|
|
14326
|
+
let removedFromPriority = 0;
|
|
14327
|
+
for (let i = 0; i < this.eIdQueue.length; i++) {
|
|
14328
|
+
const eId = this.eIdQueue[i];
|
|
14329
|
+
if (promoting.has(eId)) {
|
|
14330
|
+
if (i < this.priorityCount) {
|
|
14331
|
+
removedFromPriority += 1;
|
|
14332
|
+
}
|
|
14333
|
+
continue;
|
|
14334
|
+
}
|
|
14335
|
+
kept.push(eId);
|
|
14336
|
+
}
|
|
14337
|
+
this.eIdQueue = kept;
|
|
14338
|
+
this.priorityCount = Math.max(0, this.priorityCount - removedFromPriority);
|
|
14119
14339
|
}
|
|
14120
|
-
|
|
14340
|
+
this.eIdQueue = toFront.concat(this.eIdQueue);
|
|
14341
|
+
this.priorityCount += toFront.length;
|
|
14342
|
+
for (let i = 0; i < toFront.length; i++) {
|
|
14343
|
+
this.eIdQueued.add(toFront[i]);
|
|
14344
|
+
}
|
|
14345
|
+
changes = toFront.length;
|
|
14346
|
+
}
|
|
14347
|
+
else {
|
|
14348
|
+
for (let i = 0; i < entityIds.length; i++) {
|
|
14349
|
+
const eId = entityIds[i];
|
|
14350
|
+
this.allEIds.add(eId);
|
|
14351
|
+
if (this.eIdQueued.has(eId)) {
|
|
14352
|
+
continue;
|
|
14353
|
+
}
|
|
14354
|
+
this.eIdQueued.add(eId);
|
|
14121
14355
|
this.eIdQueue.push(eId);
|
|
14122
14356
|
changes += 1;
|
|
14123
14357
|
}
|
|
14124
|
-
// Flag that we've seen this ID.
|
|
14125
|
-
this.allEIds.add(entityIds[i]);
|
|
14126
14358
|
}
|
|
14127
14359
|
if (!changes) {
|
|
14128
14360
|
return;
|
|
@@ -14256,7 +14488,7 @@
|
|
|
14256
14488
|
this.emitEntities(toEmit, tags);
|
|
14257
14489
|
};
|
|
14258
14490
|
const QUEUE_BATCH_SIZE = 500;
|
|
14259
|
-
const requestedIds =
|
|
14491
|
+
const requestedIds = new Set();
|
|
14260
14492
|
// If we have a queue, we need to request those first.
|
|
14261
14493
|
if (this.eIdQueue.length) {
|
|
14262
14494
|
const total = this.eIdQueue.length;
|
|
@@ -14265,7 +14497,12 @@
|
|
|
14265
14497
|
if (this.historic && this.lastDateTime !== rTime) {
|
|
14266
14498
|
break;
|
|
14267
14499
|
}
|
|
14500
|
+
this.orderQueueByCamera();
|
|
14268
14501
|
const batch = this.eIdQueue.splice(0, QUEUE_BATCH_SIZE);
|
|
14502
|
+
this.priorityCount = Math.max(0, this.priorityCount - batch.length);
|
|
14503
|
+
for (let i = 0; i < batch.length; i++) {
|
|
14504
|
+
this.eIdQueued.delete(batch[i]);
|
|
14505
|
+
}
|
|
14269
14506
|
const { entities } = await BModels.Entity.GetListByIds({
|
|
14270
14507
|
entityIds: batch,
|
|
14271
14508
|
historicPoint: this.historic ? rTime : null,
|
|
@@ -14274,7 +14511,9 @@
|
|
|
14274
14511
|
maxSearchTimeSec: 60 * 2
|
|
14275
14512
|
});
|
|
14276
14513
|
handleResponse(batch, entities);
|
|
14277
|
-
|
|
14514
|
+
for (let i = 0; i < batch.length; i++) {
|
|
14515
|
+
requestedIds.add(batch[i]);
|
|
14516
|
+
}
|
|
14278
14517
|
done += batch.length;
|
|
14279
14518
|
if (this._onQueueProgress) {
|
|
14280
14519
|
let progress = (done / total) * 100;
|
|
@@ -14294,10 +14533,13 @@
|
|
|
14294
14533
|
// Now run through all IDs that we've seen and request them.
|
|
14295
14534
|
// We'll skip those that we just requested.
|
|
14296
14535
|
let allEIds = Array.from(this.allEIds);
|
|
14297
|
-
if (requestedIds.
|
|
14298
|
-
allEIds = allEIds.filter((eId) => requestedIds.
|
|
14536
|
+
if (requestedIds.size) {
|
|
14537
|
+
allEIds = allEIds.filter((eId) => !requestedIds.has(eId));
|
|
14299
14538
|
}
|
|
14300
14539
|
if (allEIds.length) {
|
|
14540
|
+
// A historic tick re-reads the whole set, so the near ones are worth resolving
|
|
14541
|
+
// first here even more than in the queue above.
|
|
14542
|
+
allEIds = this.bandIds(allEIds);
|
|
14301
14543
|
while (allEIds.length && !this.disposed && !this.eIdQueue.length) {
|
|
14302
14544
|
if (this.historic && this.lastDateTime !== rTime) {
|
|
14303
14545
|
break;
|
|
@@ -14311,7 +14553,9 @@
|
|
|
14311
14553
|
maxSearchTimeSec: 60 * 2
|
|
14312
14554
|
});
|
|
14313
14555
|
handleResponse(batch, entities);
|
|
14314
|
-
|
|
14556
|
+
for (let i = 0; i < batch.length; i++) {
|
|
14557
|
+
requestedIds.add(batch[i]);
|
|
14558
|
+
}
|
|
14315
14559
|
}
|
|
14316
14560
|
}
|
|
14317
14561
|
// If we had leftovers because we stopped early, we need to re-run the tick.
|
|
@@ -14331,6 +14575,11 @@
|
|
|
14331
14575
|
})();
|
|
14332
14576
|
}
|
|
14333
14577
|
}
|
|
14578
|
+
// Below this the whole queue clears in one or two requests, so ordering it buys nothing.
|
|
14579
|
+
EntityGatherer.MIN_ORDER_QUEUE = 500;
|
|
14580
|
+
// How far the point being looked at has to move before the queue is worth re-banding, in metres.
|
|
14581
|
+
// Under the nearest band's width, so a move that could change what is nearest still triggers one.
|
|
14582
|
+
EntityGatherer.REORDER_MOVE_METRES = 250;
|
|
14334
14583
|
|
|
14335
14584
|
// ND-1641. BOOKMARKS - (DEMO) View does not match bookmark.
|
|
14336
14585
|
// We have some evil hard-coded style mappings that need to be fixed.
|
|
@@ -14454,7 +14703,8 @@
|
|
|
14454
14703
|
}
|
|
14455
14704
|
Init(params) {
|
|
14456
14705
|
var _a, _b;
|
|
14457
|
-
let { viewer, api, cTileset, fallbackStyleId, styleMapping, expandSources, menuItemId, register, scenario, historic, applyStyles } = params;
|
|
14706
|
+
let { viewer, api, cTileset, fallbackStyleId, styleMapping, expandSources, menuItemId, register, scenario, historic, applyStyles, monitor } = params;
|
|
14707
|
+
this.monitor = monitor;
|
|
14458
14708
|
this.viewer = viewer;
|
|
14459
14709
|
this.api = api;
|
|
14460
14710
|
this.cTileset = cTileset;
|
|
@@ -14510,6 +14760,14 @@
|
|
|
14510
14760
|
}
|
|
14511
14761
|
}
|
|
14512
14762
|
});
|
|
14763
|
+
// Only Entities Sets bake coordinates into their features, so for any other source this
|
|
14764
|
+
// resolves nothing and the gather stays in insertion order.
|
|
14765
|
+
this.entityGatherer.SetViewMonitor(this.monitor);
|
|
14766
|
+
this.entityGatherer.SetPositionSource((entityId) => {
|
|
14767
|
+
var _a;
|
|
14768
|
+
const visual = (_a = this.getEntityRego(entityId)) === null || _a === void 0 ? void 0 : _a.visual;
|
|
14769
|
+
return (visual === null || visual === void 0 ? void 0 : visual._bakedPos) || null;
|
|
14770
|
+
});
|
|
14513
14771
|
this.loaded = true;
|
|
14514
14772
|
this.loadStyles();
|
|
14515
14773
|
const feed = (_b = this.api) === null || _b === void 0 ? void 0 : _b.RecordChangeFeed;
|
|
@@ -19721,7 +19979,8 @@
|
|
|
19721
19979
|
// Saves having to do a case-insensitive lookup every time.
|
|
19722
19980
|
this.featurePropCache = new Map();
|
|
19723
19981
|
this.featurePropsChecked = 0;
|
|
19724
|
-
const { viewer, register: visualsManager, getters: apiGetter, item, initQueue } = params;
|
|
19982
|
+
const { viewer, register: visualsManager, getters: apiGetter, item, initQueue, monitor } = params;
|
|
19983
|
+
this.monitor = monitor;
|
|
19725
19984
|
this.viewer = viewer;
|
|
19726
19985
|
this.getters = apiGetter;
|
|
19727
19986
|
this.item = item;
|
|
@@ -19830,7 +20089,8 @@
|
|
|
19830
20089
|
menuItemId: this.item.id,
|
|
19831
20090
|
register: this.visualsManager,
|
|
19832
20091
|
historic: Manager.IsHistoric(this.item),
|
|
19833
|
-
applyStyles: Boolean(this.item.ApplyStyles)
|
|
20092
|
+
applyStyles: Boolean(this.item.ApplyStyles),
|
|
20093
|
+
monitor: this.monitor
|
|
19834
20094
|
});
|
|
19835
20095
|
}
|
|
19836
20096
|
this.onCTilesetLoad();
|
|
@@ -19990,6 +20250,16 @@
|
|
|
19990
20250
|
else if (lowered === "internalid") {
|
|
19991
20251
|
this.featurePropCache.set("internalId", prop);
|
|
19992
20252
|
}
|
|
20253
|
+
else if (lowered === "latitude") {
|
|
20254
|
+
this.featurePropCache.set("latitude", prop);
|
|
20255
|
+
}
|
|
20256
|
+
else if (lowered === "longitude") {
|
|
20257
|
+
this.featurePropCache.set("longitude", prop);
|
|
20258
|
+
}
|
|
20259
|
+
// b3dm names the baked height TerrainHeight, the glTF metadata table calls it Altitude.
|
|
20260
|
+
else if (lowered === "terrainheight" || lowered === "altitude") {
|
|
20261
|
+
this.featurePropCache.set("height", prop);
|
|
20262
|
+
}
|
|
19993
20263
|
}
|
|
19994
20264
|
}
|
|
19995
20265
|
Dispose() {
|
|
@@ -20144,7 +20414,8 @@
|
|
|
20144
20414
|
menuItemId: this.item.id,
|
|
20145
20415
|
register: this.visualsManager,
|
|
20146
20416
|
historic: Manager.IsHistoric(this.item),
|
|
20147
|
-
applyStyles: Boolean(this.item.ApplyStyles)
|
|
20417
|
+
applyStyles: Boolean(this.item.ApplyStyles),
|
|
20418
|
+
monitor: this.monitor
|
|
20148
20419
|
});
|
|
20149
20420
|
this.queueHandoffRestyle(this.visualsManager.GetRegos({ menuItemId: this.item.id }));
|
|
20150
20421
|
}
|
|
@@ -20187,6 +20458,45 @@
|
|
|
20187
20458
|
}
|
|
20188
20459
|
}, 10);
|
|
20189
20460
|
}
|
|
20461
|
+
/*
|
|
20462
|
+
* Reads a numeric feature property, returning null for anything that is not one.
|
|
20463
|
+
*/
|
|
20464
|
+
static readNumber(feature, prop) {
|
|
20465
|
+
const raw = feature.getProperty(prop);
|
|
20466
|
+
// Coercing straight to a number would turn null, undefined and "" into a valid zero,
|
|
20467
|
+
// which for a coordinate is a real place off the coast of Africa.
|
|
20468
|
+
if (raw == null || raw === "" || typeof raw === "boolean") {
|
|
20469
|
+
return null;
|
|
20470
|
+
}
|
|
20471
|
+
const value = +raw;
|
|
20472
|
+
return isFinite(value) ? value : null;
|
|
20473
|
+
}
|
|
20474
|
+
/*
|
|
20475
|
+
* Returns the world position an Entities Set bakes into each feature, or null when it has none.
|
|
20476
|
+
*/
|
|
20477
|
+
readBakedPos(feature) {
|
|
20478
|
+
const latProp = this.featurePropCache.get("latitude");
|
|
20479
|
+
const lonProp = this.featurePropCache.get("longitude");
|
|
20480
|
+
if (!latProp || !lonProp) {
|
|
20481
|
+
return null;
|
|
20482
|
+
}
|
|
20483
|
+
try {
|
|
20484
|
+
const lat = Manager.readNumber(feature, latProp);
|
|
20485
|
+
const lon = Manager.readNumber(feature, lonProp);
|
|
20486
|
+
// Degrees, per the batch table the generator writes. The range check doubles as a
|
|
20487
|
+
// guard against a source that bakes radians, which would otherwise read as valid.
|
|
20488
|
+
if (lat == null || lon == null || Math.abs(lat) > 90 || Math.abs(lon) > 180) {
|
|
20489
|
+
return null;
|
|
20490
|
+
}
|
|
20491
|
+
// A height that will not read is worth losing, the position it belongs to is not.
|
|
20492
|
+
const heightProp = this.featurePropCache.get("height");
|
|
20493
|
+
const height = heightProp ? Manager.readNumber(feature, heightProp) : 0;
|
|
20494
|
+
return Cesium.Cartesian3.fromDegrees(lon, lat, height !== null && height !== void 0 ? height : 0);
|
|
20495
|
+
}
|
|
20496
|
+
catch {
|
|
20497
|
+
return null;
|
|
20498
|
+
}
|
|
20499
|
+
}
|
|
20190
20500
|
mapTilesetFeature(feature) {
|
|
20191
20501
|
var _a, _b, _c;
|
|
20192
20502
|
this.evaluateFeatureProps(feature);
|
|
@@ -20267,6 +20577,12 @@
|
|
|
20267
20577
|
rego.internalId = parsed;
|
|
20268
20578
|
}
|
|
20269
20579
|
}
|
|
20580
|
+
// Stamped on the feature the properties came from, so a sibling keeps its own position
|
|
20581
|
+
// and nothing has to be cleaned up when the tile unloads.
|
|
20582
|
+
const bakedPos = this.readBakedPos(feature);
|
|
20583
|
+
if (bakedPos) {
|
|
20584
|
+
feature._bakedPos = bakedPos;
|
|
20585
|
+
}
|
|
20270
20586
|
this.loadedCesiumEntities[rego.entityId] = rego;
|
|
20271
20587
|
this.visualsManager.AddRego({
|
|
20272
20588
|
rego,
|
|
@@ -24131,6 +24447,7 @@
|
|
|
24131
24447
|
viewer: this.viewer,
|
|
24132
24448
|
register: this.visualsRegister,
|
|
24133
24449
|
getters: this.getters,
|
|
24450
|
+
monitor: this.sharedMonitor,
|
|
24134
24451
|
item: params.item,
|
|
24135
24452
|
initQueue: this.tilesetInitQueue
|
|
24136
24453
|
});
|
|
@@ -40886,9 +41203,11 @@
|
|
|
40886
41203
|
return;
|
|
40887
41204
|
}
|
|
40888
41205
|
let next = -1;
|
|
41206
|
+
let isTarget = false;
|
|
40889
41207
|
if (this.pendingIndex !== -1) {
|
|
40890
41208
|
next = this.pendingIndex;
|
|
40891
41209
|
this.pendingIndex = -1;
|
|
41210
|
+
isTarget = true;
|
|
40892
41211
|
}
|
|
40893
41212
|
else {
|
|
40894
41213
|
next = this.nearestUncachedFrame();
|
|
@@ -40897,7 +41216,7 @@
|
|
|
40897
41216
|
return;
|
|
40898
41217
|
}
|
|
40899
41218
|
this.inFlightIndex = next;
|
|
40900
|
-
this.fetchAndTint(next)
|
|
41219
|
+
this.fetchAndTint(next, isTarget)
|
|
40901
41220
|
.catch(() => {
|
|
40902
41221
|
// Eating it.
|
|
40903
41222
|
})
|
|
@@ -40908,7 +41227,7 @@
|
|
|
40908
41227
|
}
|
|
40909
41228
|
});
|
|
40910
41229
|
}
|
|
40911
|
-
async fetchAndTint(idx) {
|
|
41230
|
+
async fetchAndTint(idx, isTarget = true) {
|
|
40912
41231
|
const tiles = this.tiles;
|
|
40913
41232
|
// Every tile's frame for one timestep sits contiguously, because the generator writes
|
|
40914
41233
|
// frame major. So a tiled frame is still ONE range request, not one per tile.
|
|
@@ -40940,10 +41259,25 @@
|
|
|
40940
41259
|
this.frameCache[idx] = decoded.pixels;
|
|
40941
41260
|
this.frameDims[idx] = { width: decoded.width, height: decoded.height };
|
|
40942
41261
|
this.valueCache[idx] = decoded.valuePixels || null;
|
|
40943
|
-
if (idx
|
|
41262
|
+
if (this.shouldPresent(idx, isTarget)) {
|
|
40944
41263
|
this.beginCrossfadeTo(idx);
|
|
40945
41264
|
}
|
|
40946
41265
|
}
|
|
41266
|
+
/*
|
|
41267
|
+
* Whether a frame that has just decoded is worth putting on screen.
|
|
41268
|
+
*/
|
|
41269
|
+
shouldPresent(idx, isTarget) {
|
|
41270
|
+
if (idx === this.currentFrameIndex) {
|
|
41271
|
+
return true;
|
|
41272
|
+
}
|
|
41273
|
+
// A prefetch is for a frame nobody asked to see, so it stays in the cache.
|
|
41274
|
+
if (!isTarget) {
|
|
41275
|
+
return false;
|
|
41276
|
+
}
|
|
41277
|
+
// Dragging the timeline retargets faster than a frame can be fetched, so the frame that
|
|
41278
|
+
// lands is rarely the one now under the playhead.
|
|
41279
|
+
return !this.frameCache[this.currentFrameIndex];
|
|
41280
|
+
}
|
|
40947
41281
|
/*
|
|
40948
41282
|
* Draws every tile of one frame into a single raster covering the drape extent.
|
|
40949
41283
|
*/
|
|
@@ -45481,7 +45815,7 @@ void main() {
|
|
|
45481
45815
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
45482
45816
|
})(exports.StyleUtils || (exports.StyleUtils = {}));
|
|
45483
45817
|
|
|
45484
|
-
const VERSION = "7.2.
|
|
45818
|
+
const VERSION = "7.2.6";
|
|
45485
45819
|
/**
|
|
45486
45820
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
45487
45821
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|