bruce-cesium 7.3.8 → 7.3.9
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 +315 -26
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +313 -24
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/entity-gatherer.js +249 -16
- package/dist/lib/rendering/entity-gatherer.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/historic-utils.js +64 -7
- package/dist/lib/rendering/render-managers/common/historic-utils.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/entity-gatherer.d.ts +27 -4
- package/dist/types/rendering/render-managers/common/historic-utils.d.ts +12 -4
- package/package.json +1 -1
package/dist/bruce-cesium.umd.js
CHANGED
|
@@ -11027,10 +11027,6 @@
|
|
|
11027
11027
|
|
|
11028
11028
|
/**
|
|
11029
11029
|
* How often a historic refresh is worth running, and which Entities it should ask about first.
|
|
11030
|
-
*
|
|
11031
|
-
* A handful of tracked vehicles can afford to re-read on almost every clock tick. Thousands of
|
|
11032
|
-
* parcels cannot, and refreshing them that often was never buying anything since the answer barely
|
|
11033
|
-
* changes between ticks.
|
|
11034
11030
|
*/
|
|
11035
11031
|
var HistoricFetchOrder;
|
|
11036
11032
|
(function (HistoricFetchOrder) {
|
|
@@ -11075,6 +11071,13 @@
|
|
|
11075
11071
|
HistoricFetchOrder.IntervalForClock = IntervalForClock;
|
|
11076
11072
|
// Upper bounds in metres for the distance bands, nearest first.
|
|
11077
11073
|
HistoricFetchOrder.DEFAULT_BANDS = [500, 2000, 10000, 50000];
|
|
11074
|
+
// How far outside the visible rectangle something still counts as worth re-reading, share of the view itself.
|
|
11075
|
+
HistoricFetchOrder.REFRESH_MARGIN_FRACTION = 0.5;
|
|
11076
|
+
// A close view still gets a usable buffer, and a distant one does not reach half the account.
|
|
11077
|
+
HistoricFetchOrder.MIN_REFRESH_MARGIN_METRES = 250;
|
|
11078
|
+
HistoricFetchOrder.MAX_REFRESH_MARGIN_METRES = 2000;
|
|
11079
|
+
const METRES_PER_DEGREE_LAT = 111320;
|
|
11080
|
+
const MIN_LAT_COSINE = 0.01;
|
|
11078
11081
|
/**
|
|
11079
11082
|
* Resolves what to order by from the view monitor, falling back to the camera itself.
|
|
11080
11083
|
*/
|
|
@@ -11155,6 +11158,55 @@
|
|
|
11155
11158
|
return grouped.filter(group => group.length > 0);
|
|
11156
11159
|
}
|
|
11157
11160
|
HistoricFetchOrder.ByCameraDistanceOf = ByCameraDistanceOf;
|
|
11161
|
+
/**
|
|
11162
|
+
* Returns how far past a visible rectangle a refresh should still reach, in metres.
|
|
11163
|
+
*/
|
|
11164
|
+
function RefreshMarginFor(bounds) {
|
|
11165
|
+
if (!bounds) {
|
|
11166
|
+
return HistoricFetchOrder.MIN_REFRESH_MARGIN_METRES;
|
|
11167
|
+
}
|
|
11168
|
+
const latSpan = Math.abs(bounds.north - bounds.south) * METRES_PER_DEGREE_LAT;
|
|
11169
|
+
const cosine = Math.max(MIN_LAT_COSINE, Math.cos(Cesium.Math.toRadians((bounds.north + bounds.south) / 2)));
|
|
11170
|
+
const lonDegrees = bounds.west > bounds.east
|
|
11171
|
+
? (bounds.east + 360) - bounds.west
|
|
11172
|
+
: bounds.east - bounds.west;
|
|
11173
|
+
const lonSpan = Math.abs(lonDegrees) * METRES_PER_DEGREE_LAT * cosine;
|
|
11174
|
+
const span = Math.min(latSpan, lonSpan);
|
|
11175
|
+
if (!(span > 0)) {
|
|
11176
|
+
return HistoricFetchOrder.MIN_REFRESH_MARGIN_METRES;
|
|
11177
|
+
}
|
|
11178
|
+
return Math.min(HistoricFetchOrder.MAX_REFRESH_MARGIN_METRES, Math.max(HistoricFetchOrder.MIN_REFRESH_MARGIN_METRES, span * HistoricFetchOrder.REFRESH_MARGIN_FRACTION));
|
|
11179
|
+
}
|
|
11180
|
+
HistoricFetchOrder.RefreshMarginFor = RefreshMarginFor;
|
|
11181
|
+
/**
|
|
11182
|
+
* Returns the rectangle grown outwards by a margin in metres.
|
|
11183
|
+
*/
|
|
11184
|
+
function GrowBounds(bounds, metres) {
|
|
11185
|
+
if (!bounds || !(metres > 0)) {
|
|
11186
|
+
return bounds;
|
|
11187
|
+
}
|
|
11188
|
+
const dLat = metres / METRES_PER_DEGREE_LAT;
|
|
11189
|
+
const north = Math.min(90, bounds.north + dLat);
|
|
11190
|
+
const south = Math.max(-90, bounds.south - dLat);
|
|
11191
|
+
const cosine = Math.cos(Cesium.Math.toRadians((bounds.north + bounds.south) / 2));
|
|
11192
|
+
if (cosine < MIN_LAT_COSINE) {
|
|
11193
|
+
return { north, south, west: -180, east: 180 };
|
|
11194
|
+
}
|
|
11195
|
+
const dLon = metres / (METRES_PER_DEGREE_LAT * cosine);
|
|
11196
|
+
const straddles = bounds.west > bounds.east;
|
|
11197
|
+
const gap = straddles ? bounds.west - bounds.east : 360 - (bounds.east - bounds.west);
|
|
11198
|
+
if (gap <= dLon * 2) {
|
|
11199
|
+
return { north, south, west: -180, east: 180 };
|
|
11200
|
+
}
|
|
11201
|
+
return { north, south, west: wrapLongitude(bounds.west - dLon), east: wrapLongitude(bounds.east + dLon) };
|
|
11202
|
+
}
|
|
11203
|
+
HistoricFetchOrder.GrowBounds = GrowBounds;
|
|
11204
|
+
/*
|
|
11205
|
+
* Returns a longitude folded back into the range the bounds are expressed in.
|
|
11206
|
+
*/
|
|
11207
|
+
function wrapLongitude(lon) {
|
|
11208
|
+
return (((lon + 180) % 360) + 360) % 360 - 180;
|
|
11209
|
+
}
|
|
11158
11210
|
/*
|
|
11159
11211
|
* Returns whether a world position sits inside a ground rectangle given in degrees.
|
|
11160
11212
|
*/
|
|
@@ -11163,17 +11215,22 @@
|
|
|
11163
11215
|
if (!degrees) {
|
|
11164
11216
|
return false;
|
|
11165
11217
|
}
|
|
11166
|
-
|
|
11218
|
+
return InDegreeBounds(degrees.lat, degrees.lon, bounds);
|
|
11219
|
+
}
|
|
11220
|
+
HistoricFetchOrder.InBounds = InBounds;
|
|
11221
|
+
/*
|
|
11222
|
+
* The same test for a caller that already holds the degrees and should not pay to resolve them from a world position again.
|
|
11223
|
+
*/
|
|
11224
|
+
function InDegreeBounds(lat, lon, bounds) {
|
|
11167
11225
|
if (lat < bounds.south || lat > bounds.north) {
|
|
11168
11226
|
return false;
|
|
11169
11227
|
}
|
|
11170
|
-
// A view straddling the antimeridian reports west east of east, so the span is the outside.
|
|
11171
11228
|
if (bounds.west > bounds.east) {
|
|
11172
11229
|
return lon >= bounds.west || lon <= bounds.east;
|
|
11173
11230
|
}
|
|
11174
11231
|
return lon >= bounds.west && lon <= bounds.east;
|
|
11175
11232
|
}
|
|
11176
|
-
HistoricFetchOrder.
|
|
11233
|
+
HistoricFetchOrder.InDegreeBounds = InDegreeBounds;
|
|
11177
11234
|
/*
|
|
11178
11235
|
* Returns an Entity's world position, or null when it has none to place it by.
|
|
11179
11236
|
*/
|
|
@@ -14559,6 +14616,19 @@
|
|
|
14559
14616
|
// All IDs that have ever been queued.
|
|
14560
14617
|
// When nothing is in queue, we'll re-request the existing IDs based on timeline changes.
|
|
14561
14618
|
this.allEIds = new Set();
|
|
14619
|
+
// IDs a historic read has actually answered with a record, rather than falling back to a stub.
|
|
14620
|
+
// A refresh serves these before the ones that have never produced anything.
|
|
14621
|
+
this.everFound = new Set();
|
|
14622
|
+
// Every known Entity bucketed by the ground cell its position falls in, so a refresh can ask
|
|
14623
|
+
// what the view reaches instead of walking the whole set. Built as IDs arrive.
|
|
14624
|
+
this.cells = new Map();
|
|
14625
|
+
// IDs the position source could not place yet. They are always refreshed.
|
|
14626
|
+
this.unplaced = new Set();
|
|
14627
|
+
// The IDs the last decision found inside the view, so a camera move can queue the difference
|
|
14628
|
+
// rather than re-requesting everything it already asked about.
|
|
14629
|
+
this.lastInView = new Set();
|
|
14630
|
+
// Unsubscribes the view monitor listener that queues what the camera has moved onto.
|
|
14631
|
+
this.monitorRemoval = null;
|
|
14562
14632
|
// Indicates a tick is active.
|
|
14563
14633
|
// When true, we won't bother calling onTick again.
|
|
14564
14634
|
this.runningTick = false;
|
|
@@ -14609,6 +14679,16 @@
|
|
|
14609
14679
|
}
|
|
14610
14680
|
this.historic = historic;
|
|
14611
14681
|
this.expandSources = expandSources;
|
|
14682
|
+
if (this.historic) {
|
|
14683
|
+
// Anything already known was taken in before the index was being built, so it is filed
|
|
14684
|
+
// a bounded number at a time from here rather than in one pass now.
|
|
14685
|
+
for (const entityId of this.allEIds) {
|
|
14686
|
+
this.unplaced.add(entityId);
|
|
14687
|
+
}
|
|
14688
|
+
}
|
|
14689
|
+
else {
|
|
14690
|
+
this.clearIndex();
|
|
14691
|
+
}
|
|
14612
14692
|
if (this.historic) {
|
|
14613
14693
|
// 4 ticks per second.
|
|
14614
14694
|
// The fastest data we are working with is 5 times per second.
|
|
@@ -14660,6 +14740,8 @@
|
|
|
14660
14740
|
this.lastOrderFocus = null;
|
|
14661
14741
|
this.allEIds.clear();
|
|
14662
14742
|
this.lastFoundDateTimes.clear();
|
|
14743
|
+
this.everFound.clear();
|
|
14744
|
+
this.clearIndex();
|
|
14663
14745
|
this.lastDateTime = null;
|
|
14664
14746
|
}
|
|
14665
14747
|
ReQueueAll() {
|
|
@@ -14670,22 +14752,193 @@
|
|
|
14670
14752
|
this.eIdQueued = new Set(this.eIdQueue);
|
|
14671
14753
|
this.priorityCount = 0;
|
|
14672
14754
|
this.lastOrderFocus = null;
|
|
14755
|
+
this.clearIndex();
|
|
14673
14756
|
}
|
|
14674
14757
|
/**
|
|
14675
|
-
* Supplies a lookup from Entity ID to world position, letting the queue resolve what the camera
|
|
14676
|
-
*
|
|
14758
|
+
* Supplies a lookup from Entity ID to world position, letting the queue resolve what the camera is nearest first.
|
|
14759
|
+
* Sources that cannot answer should not call this, and are served in order.
|
|
14677
14760
|
*/
|
|
14678
14761
|
SetPositionSource(positionOf) {
|
|
14679
14762
|
this.positionOf = positionOf;
|
|
14680
14763
|
this.lastOrderFocus = null;
|
|
14764
|
+
this.cells.clear();
|
|
14765
|
+
this.lastInView.clear();
|
|
14766
|
+
for (const entityId of this.allEIds) {
|
|
14767
|
+
this.unplaced.add(entityId);
|
|
14768
|
+
}
|
|
14681
14769
|
}
|
|
14682
14770
|
/**
|
|
14683
|
-
* Supplies the view monitor, so the order follows the ground the camera is aimed at and prefers
|
|
14684
|
-
*
|
|
14771
|
+
* Supplies the view monitor, so the order follows the ground the camera is aimed at and prefers what is on screen.
|
|
14772
|
+
* Without one the ordering falls back to distance from the camera itself.
|
|
14685
14773
|
*/
|
|
14686
14774
|
SetViewMonitor(monitor) {
|
|
14775
|
+
var _a;
|
|
14776
|
+
(_a = this.monitorRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
14777
|
+
this.monitorRemoval = null;
|
|
14687
14778
|
this.monitor = monitor;
|
|
14688
14779
|
this.lastOrderFocus = null;
|
|
14780
|
+
if (!monitor) {
|
|
14781
|
+
return;
|
|
14782
|
+
}
|
|
14783
|
+
this.monitorRemoval = monitor.Updated().Subscribe(() => {
|
|
14784
|
+
this.admitNewlyInView();
|
|
14785
|
+
});
|
|
14786
|
+
}
|
|
14787
|
+
/*
|
|
14788
|
+
* Queues whatever the camera has moved onto since the last decision.
|
|
14789
|
+
*/
|
|
14790
|
+
admitNewlyInView() {
|
|
14791
|
+
if (this.disposed || !this.historic) {
|
|
14792
|
+
return;
|
|
14793
|
+
}
|
|
14794
|
+
const inView = this.decideInView();
|
|
14795
|
+
if (!inView) {
|
|
14796
|
+
return;
|
|
14797
|
+
}
|
|
14798
|
+
const admit = [];
|
|
14799
|
+
for (const entityId of inView) {
|
|
14800
|
+
if (!this.lastInView.has(entityId)) {
|
|
14801
|
+
admit.push(entityId);
|
|
14802
|
+
}
|
|
14803
|
+
}
|
|
14804
|
+
this.lastInView = new Set(inView);
|
|
14805
|
+
if (admit.length) {
|
|
14806
|
+
this.Queue(admit);
|
|
14807
|
+
}
|
|
14808
|
+
}
|
|
14809
|
+
/*
|
|
14810
|
+
* Returns the IDs a refresh should ask about, or null when the view cannot say and the answer has to be everything.
|
|
14811
|
+
*/
|
|
14812
|
+
decideInView() {
|
|
14813
|
+
if (!this.historic || !this.positionOf || !this.monitor) {
|
|
14814
|
+
return null;
|
|
14815
|
+
}
|
|
14816
|
+
const area = this.refreshArea();
|
|
14817
|
+
if (!area) {
|
|
14818
|
+
return null;
|
|
14819
|
+
}
|
|
14820
|
+
const inView = [];
|
|
14821
|
+
for (const key of this.candidateCellKeys(area)) {
|
|
14822
|
+
const cell = this.cells.get(key);
|
|
14823
|
+
if (!cell) {
|
|
14824
|
+
continue;
|
|
14825
|
+
}
|
|
14826
|
+
for (let i = 0; i < cell.ids.length; i++) {
|
|
14827
|
+
if (HistoricFetchOrder.InDegreeBounds(cell.lats[i], cell.lons[i], area)) {
|
|
14828
|
+
inView.push(cell.ids[i]);
|
|
14829
|
+
}
|
|
14830
|
+
}
|
|
14831
|
+
}
|
|
14832
|
+
// Anything the source cannot place yet is asked about rather than quietly dropped.
|
|
14833
|
+
for (const entityId of this.unplaced) {
|
|
14834
|
+
inView.push(entityId);
|
|
14835
|
+
}
|
|
14836
|
+
return inView;
|
|
14837
|
+
}
|
|
14838
|
+
/*
|
|
14839
|
+
* Returns the cell keys a rectangle can reach.
|
|
14840
|
+
*/
|
|
14841
|
+
candidateCellKeys(area) {
|
|
14842
|
+
const size = EntityGatherer.CELL_DEGREES;
|
|
14843
|
+
const southCell = Math.floor(area.south / size);
|
|
14844
|
+
const northCell = Math.floor(area.north / size);
|
|
14845
|
+
const spans = (area.west > area.east ? [
|
|
14846
|
+
{
|
|
14847
|
+
from: Math.floor(area.west / size),
|
|
14848
|
+
to: Math.floor(180 / size)
|
|
14849
|
+
},
|
|
14850
|
+
{
|
|
14851
|
+
from: Math.floor(-180 / size),
|
|
14852
|
+
to: Math.floor(area.east / size)
|
|
14853
|
+
}
|
|
14854
|
+
] :
|
|
14855
|
+
[{
|
|
14856
|
+
from: Math.floor(area.west / size),
|
|
14857
|
+
to: Math.floor(area.east / size)
|
|
14858
|
+
}]);
|
|
14859
|
+
let width = 0;
|
|
14860
|
+
for (const span of spans) {
|
|
14861
|
+
width += (span.to - span.from) + 1;
|
|
14862
|
+
}
|
|
14863
|
+
const wanted = ((northCell - southCell) + 1) * width;
|
|
14864
|
+
if (!(wanted > 0) || wanted > this.cells.size) {
|
|
14865
|
+
return Array.from(this.cells.keys());
|
|
14866
|
+
}
|
|
14867
|
+
const keys = [];
|
|
14868
|
+
for (let lat = southCell; lat <= northCell; lat++) {
|
|
14869
|
+
for (const span of spans) {
|
|
14870
|
+
for (let lon = span.from; lon <= span.to; lon++) {
|
|
14871
|
+
keys.push(lat + ":" + lon);
|
|
14872
|
+
}
|
|
14873
|
+
}
|
|
14874
|
+
}
|
|
14875
|
+
return keys;
|
|
14876
|
+
}
|
|
14877
|
+
/*
|
|
14878
|
+
* Files an Entity in the cell its position falls in.
|
|
14879
|
+
*/
|
|
14880
|
+
place(entityId) {
|
|
14881
|
+
const degrees = this.degreesOf(entityId);
|
|
14882
|
+
if (!degrees) {
|
|
14883
|
+
this.unplaced.add(entityId);
|
|
14884
|
+
return;
|
|
14885
|
+
}
|
|
14886
|
+
const size = EntityGatherer.CELL_DEGREES;
|
|
14887
|
+
const key = Math.floor(degrees.lat / size) + ":" + Math.floor(degrees.lon / size);
|
|
14888
|
+
let cell = this.cells.get(key);
|
|
14889
|
+
if (!cell) {
|
|
14890
|
+
cell = { ids: [], lats: [], lons: [] };
|
|
14891
|
+
this.cells.set(key, cell);
|
|
14892
|
+
}
|
|
14893
|
+
cell.ids.push(entityId);
|
|
14894
|
+
cell.lats.push(degrees.lat);
|
|
14895
|
+
cell.lons.push(degrees.lon);
|
|
14896
|
+
this.unplaced.delete(entityId);
|
|
14897
|
+
}
|
|
14898
|
+
/*
|
|
14899
|
+
* Retries a bounded number of the Entities the source could not place before, so a late baked
|
|
14900
|
+
* position joins the index without any one tick paying for all of them.
|
|
14901
|
+
*/
|
|
14902
|
+
placeStragglers() {
|
|
14903
|
+
if (!this.unplaced.size || !this.positionOf) {
|
|
14904
|
+
return;
|
|
14905
|
+
}
|
|
14906
|
+
let budget = EntityGatherer.PLACE_BATCH;
|
|
14907
|
+
for (const entityId of this.unplaced) {
|
|
14908
|
+
if (budget-- <= 0) {
|
|
14909
|
+
return;
|
|
14910
|
+
}
|
|
14911
|
+
this.place(entityId);
|
|
14912
|
+
}
|
|
14913
|
+
}
|
|
14914
|
+
clearIndex() {
|
|
14915
|
+
this.cells.clear();
|
|
14916
|
+
this.unplaced.clear();
|
|
14917
|
+
this.lastInView.clear();
|
|
14918
|
+
}
|
|
14919
|
+
/*
|
|
14920
|
+
* Returns where an Entity sits in degrees, or null when the source cannot place it.
|
|
14921
|
+
*/
|
|
14922
|
+
degreesOf(entityId) {
|
|
14923
|
+
let pos = null;
|
|
14924
|
+
try {
|
|
14925
|
+
pos = this.positionOf ? this.positionOf(entityId) : null;
|
|
14926
|
+
}
|
|
14927
|
+
catch {
|
|
14928
|
+
pos = null;
|
|
14929
|
+
}
|
|
14930
|
+
return pos ? CartesianToDegrees(pos) : null;
|
|
14931
|
+
}
|
|
14932
|
+
/*
|
|
14933
|
+
* Returns the visible rectangle plus the margin a refresh still reaches into,
|
|
14934
|
+
* or null when the view cannot say, which is what leaves every Entity in.
|
|
14935
|
+
*/
|
|
14936
|
+
refreshArea() {
|
|
14937
|
+
const focus = HistoricFetchOrder.FocusFrom({ viewer: this.viewer, monitor: this.monitor });
|
|
14938
|
+
if (!(focus === null || focus === void 0 ? void 0 : focus.bounds)) {
|
|
14939
|
+
return null;
|
|
14940
|
+
}
|
|
14941
|
+
return HistoricFetchOrder.GrowBounds(focus.bounds, HistoricFetchOrder.RefreshMarginFor(focus.bounds));
|
|
14689
14942
|
}
|
|
14690
14943
|
/**
|
|
14691
14944
|
* Re-bands the pending queue so the nearest Entities are requested first.
|
|
@@ -14698,8 +14951,6 @@
|
|
|
14698
14951
|
if (!focus) {
|
|
14699
14952
|
return;
|
|
14700
14953
|
}
|
|
14701
|
-
// Re-banding on every batch would cost a full pass per request for no change in the answer.
|
|
14702
|
-
// Measured on the focus, so panning across the ground counts even when the eye barely moves.
|
|
14703
14954
|
if (this.lastOrderFocus && !EntityGatherer.boundsChanged(this.lastOrderFocus, focus) &&
|
|
14704
14955
|
Cesium.Cartesian3.distance(this.lastOrderFocus.origin, focus.origin) < EntityGatherer.REORDER_MOVE_METRES) {
|
|
14705
14956
|
return;
|
|
@@ -14746,26 +14997,47 @@
|
|
|
14746
14997
|
});
|
|
14747
14998
|
const ordered = [];
|
|
14748
14999
|
for (const band of banded) {
|
|
15000
|
+
// Within a band, the ones a read has answered for go first.
|
|
15001
|
+
// A building that has never produced a record is the one least likely to start now, so it waits.
|
|
15002
|
+
const withData = [];
|
|
15003
|
+
const withoutData = [];
|
|
14749
15004
|
for (const entityId of band) {
|
|
15005
|
+
(this.everFound.has(entityId) ? withData : withoutData).push(entityId);
|
|
15006
|
+
}
|
|
15007
|
+
for (const entityId of withData) {
|
|
15008
|
+
ordered.push(entityId);
|
|
15009
|
+
}
|
|
15010
|
+
for (const entityId of withoutData) {
|
|
14750
15011
|
ordered.push(entityId);
|
|
14751
15012
|
}
|
|
14752
15013
|
}
|
|
14753
15014
|
return ordered;
|
|
14754
15015
|
}
|
|
15016
|
+
/*
|
|
15017
|
+
* Takes an ID into the known set, filing it in the index the first time it is seen.
|
|
15018
|
+
*/
|
|
15019
|
+
remember(entityId) {
|
|
15020
|
+
if (this.allEIds.has(entityId)) {
|
|
15021
|
+
return;
|
|
15022
|
+
}
|
|
15023
|
+
this.allEIds.add(entityId);
|
|
15024
|
+
// Only a historic refresh reads the index, so nothing else pays to build it.
|
|
15025
|
+
if (this.historic) {
|
|
15026
|
+
this.place(entityId);
|
|
15027
|
+
}
|
|
15028
|
+
}
|
|
14755
15029
|
Queue(entityIds, topOfQueue = false) {
|
|
14756
15030
|
if (this.disposed || !(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
|
|
14757
15031
|
return;
|
|
14758
15032
|
}
|
|
14759
15033
|
let changes = 0;
|
|
14760
15034
|
if (topOfQueue) {
|
|
14761
|
-
// Walked back to front so a repeated ID keeps the position of its last occurrence, then
|
|
14762
|
-
// laid down in that order, which is where inserting one at a time leaves them.
|
|
14763
15035
|
const toFront = [];
|
|
14764
15036
|
const promoting = new Set();
|
|
14765
15037
|
let anyAlreadyQueued = false;
|
|
14766
15038
|
for (let i = entityIds.length - 1; i >= 0; i--) {
|
|
14767
15039
|
const eId = entityIds[i];
|
|
14768
|
-
this.
|
|
15040
|
+
this.remember(eId);
|
|
14769
15041
|
if (promoting.has(eId)) {
|
|
14770
15042
|
continue;
|
|
14771
15043
|
}
|
|
@@ -14801,7 +15073,7 @@
|
|
|
14801
15073
|
else {
|
|
14802
15074
|
for (let i = 0; i < entityIds.length; i++) {
|
|
14803
15075
|
const eId = entityIds[i];
|
|
14804
|
-
this.
|
|
15076
|
+
this.remember(eId);
|
|
14805
15077
|
if (this.eIdQueued.has(eId)) {
|
|
14806
15078
|
continue;
|
|
14807
15079
|
}
|
|
@@ -14816,19 +15088,22 @@
|
|
|
14816
15088
|
this.onTick(false);
|
|
14817
15089
|
}
|
|
14818
15090
|
Dispose() {
|
|
15091
|
+
var _a;
|
|
14819
15092
|
if (this.disposed) {
|
|
14820
15093
|
return;
|
|
14821
15094
|
}
|
|
14822
15095
|
this.disposed = true;
|
|
15096
|
+
(_a = this.monitorRemoval) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
15097
|
+
this.monitorRemoval = null;
|
|
14823
15098
|
this.hDisposals.forEach((d) => d());
|
|
14824
15099
|
this.hDisposals = [];
|
|
14825
|
-
// A tick still awaiting a response resumes after this, and anything left here would have it
|
|
14826
|
-
// ask for the whole set again on the way out.
|
|
14827
15100
|
this.eIdQueue = [];
|
|
14828
15101
|
this.eIdQueued.clear();
|
|
14829
15102
|
this.priorityCount = 0;
|
|
14830
15103
|
this.allEIds.clear();
|
|
14831
15104
|
this.lastFoundDateTimes.clear();
|
|
15105
|
+
this.everFound.clear();
|
|
15106
|
+
this.clearIndex();
|
|
14832
15107
|
this.entityDataOverrides.clear();
|
|
14833
15108
|
}
|
|
14834
15109
|
checkRange(force) {
|
|
@@ -14852,6 +15127,7 @@
|
|
|
14852
15127
|
this.lastDateTime = rTime;
|
|
14853
15128
|
(async () => {
|
|
14854
15129
|
this.runningTick = true;
|
|
15130
|
+
this.placeStragglers();
|
|
14855
15131
|
let rerun = false;
|
|
14856
15132
|
try {
|
|
14857
15133
|
const handleResponse = async (requestedBatch, entities) => {
|
|
@@ -14864,6 +15140,13 @@
|
|
|
14864
15140
|
foundById.set(entityId, entity);
|
|
14865
15141
|
}
|
|
14866
15142
|
}
|
|
15143
|
+
if (this.historic) {
|
|
15144
|
+
for (const entityId of requestedBatch || []) {
|
|
15145
|
+
if (foundById.has(entityId)) {
|
|
15146
|
+
this.everFound.add(entityId);
|
|
15147
|
+
}
|
|
15148
|
+
}
|
|
15149
|
+
}
|
|
14867
15150
|
for (const entityId of requestedBatch || []) {
|
|
14868
15151
|
const override = this.entityDataOverrides.get(entityId);
|
|
14869
15152
|
if (override) {
|
|
@@ -14992,15 +15275,16 @@
|
|
|
14992
15275
|
this._onQueueProgress.Trigger(100);
|
|
14993
15276
|
}
|
|
14994
15277
|
}
|
|
14995
|
-
// Now run through
|
|
15278
|
+
// Now run through the IDs we've seen that the view still reaches, and request them.
|
|
14996
15279
|
// We'll skip those that we just requested.
|
|
14997
|
-
|
|
15280
|
+
const inView = this.decideInView();
|
|
15281
|
+
this.lastInView = inView ? new Set(inView) : new Set();
|
|
15282
|
+
let allEIds = inView || Array.from(this.allEIds);
|
|
14998
15283
|
if (requestedIds.size) {
|
|
14999
15284
|
allEIds = allEIds.filter((eId) => !requestedIds.has(eId));
|
|
15000
15285
|
}
|
|
15001
15286
|
if (allEIds.length) {
|
|
15002
|
-
//
|
|
15003
|
-
// first here even more than in the queue above.
|
|
15287
|
+
// The near ones are resolved first out of whatever the view still reaches.
|
|
15004
15288
|
allEIds = this.bandIds(allEIds);
|
|
15005
15289
|
while (allEIds.length && !this.disposed && !this.eIdQueue.length) {
|
|
15006
15290
|
if (this.historic && this.lastDateTime !== rTime) {
|
|
@@ -15039,6 +15323,11 @@
|
|
|
15039
15323
|
}
|
|
15040
15324
|
// Below this the whole queue clears in one or two requests, so ordering it buys nothing.
|
|
15041
15325
|
EntityGatherer.MIN_ORDER_QUEUE = 500;
|
|
15326
|
+
// Side of the ground cells Entities are bucketed into, in degrees.
|
|
15327
|
+
// About a kilometre, so a view covers a handful of them rather than hundreds.
|
|
15328
|
+
EntityGatherer.CELL_DEGREES = 0.01;
|
|
15329
|
+
// How many Entities one tick will try to place in the index.
|
|
15330
|
+
EntityGatherer.PLACE_BATCH = 20000;
|
|
15042
15331
|
// How far the point being looked at has to move before the queue is worth re-banding, in metres.
|
|
15043
15332
|
// Under the nearest band's width, so a move that could change what is nearest still triggers one.
|
|
15044
15333
|
EntityGatherer.REORDER_MOVE_METRES = 250;
|
|
@@ -47784,7 +48073,7 @@ void main() {
|
|
|
47784
48073
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
47785
48074
|
})(exports.StyleUtils || (exports.StyleUtils = {}));
|
|
47786
48075
|
|
|
47787
|
-
const VERSION = "7.3.
|
|
48076
|
+
const VERSION = "7.3.9";
|
|
47788
48077
|
/**
|
|
47789
48078
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
47790
48079
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|