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.es5.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Cesium from 'cesium';
|
|
2
|
-
import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature,
|
|
3
|
-
import { Cartes, Entity as Entity$1, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, EntityLod, EntityTag, EntityType, LRUCache, ObjectUtils, Style,
|
|
2
|
+
import { Cartographic, ColorMaterialProperty, Entity, Color, ConstantProperty, CallbackProperty, Primitive, Cesium3DTileFeature, ShaderSource, Cartesian3, Math as Math$1, Ellipsoid, Transforms, Matrix4, Geometry, GeometryAttribute, ComponentDatatype, PrimitiveType, BoundingSphere, GeometryPipeline, sampleTerrain, Texture, PixelFormat, Sampler, TextureWrap, TextureMinificationFilter, TextureMagnificationFilter, VertexArray, BufferUsage, ShaderProgram, RenderState, BlendingState, DrawCommand, Pass, Cartesian2, HeightReference, ColorBlendMode, HeadingPitchRoll, ShadowMode, ClassificationType, Model, DistanceDisplayCondition, JulianDate, Quaternion, ArcType, CornerType, ConstantPositionProperty, HorizontalOrigin, VerticalOrigin, SceneTransforms, ImageMaterialProperty, PolygonHierarchy, PolylineGraphics, Rectangle, KmlDataSource, NearFarScalar, Matrix3, GeoJsonDataSource, SceneMode, Cesium3DTileStyle, HeadingPitchRange, Ion, IonResource, Cesium3DTileColorBlendMode, EllipsoidTerrainProvider, IonImageryProvider, createWorldImagery, createWorldImageryAsync, BingMapsImageryProvider, BingMapsStyle, MapboxImageryProvider, MapboxStyleImageryProvider, ArcGisMapServerImageryProvider, OpenStreetMapImageryProvider, UrlTemplateImageryProvider, GridImageryProvider, GeographicTilingScheme, ImageryLayer, TileMapServiceImageryProvider, CesiumTerrainProvider, Cesium3DTileset, OrthographicFrustum, EasingFunction, Intersect, EllipsoidGeodesic, sampleTerrainMostDetailed, defined, PolygonPipeline, ModelGraphics, PolygonGraphics, CorridorGraphics, PointGraphics, BillboardGraphics, EllipseGraphics, PolylineDashMaterialProperty, GeometryInstance, CesiumInspector, ClockRange, DynamicEnvironmentMapManager, ScreenSpaceEventHandler, ScreenSpaceEventType, CustomDataSource, Fullscreen, CzmlDataSource } from 'cesium';
|
|
3
|
+
import { Cartes, Entity as Entity$1, ProjectViewTile, ENVIRONMENT, Calculator, ClientFile, EntityLod, EntityTag, EntityType, LRUCache, ObjectUtils, Style, Carto, Geometry as Geometry$1, Api, MenuItem, ProjectView, ProjectViewBookmark, Tileset, ZoomControl, BruceEvent, EntityCoords, Bounds, Color as Color$1, DataLab, DelayQueue, EntityRelation, BruceApi, AccountConcept, RecordChangeFeed, ProgramKey, ProjectViewLegacyTile, EntitySource, Camera, Account, AccountLimits, Session, UrlUtils, EntityAttachment, EntityAttachmentType, EntityAttribute, MathUtils, ProjectViewBookmarkGroup, EntityRelationType, EntityHistoricData } from 'bruce-models';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Ensures a number is returned from a given value.
|
|
@@ -2889,6 +2889,36 @@ function SetCPropIfChanged(params) {
|
|
|
2889
2889
|
function ColorToCColor(color) {
|
|
2890
2890
|
return new Color(color.red ? color.red / 255 : 0, color.green ? color.green / 255 : 0, color.blue ? color.blue / 255 : 0, color.alpha);
|
|
2891
2891
|
}
|
|
2892
|
+
const degreesCache = new WeakMap();
|
|
2893
|
+
/**
|
|
2894
|
+
* Returns a world position's latitude and longitude in degrees, or null when it has none.
|
|
2895
|
+
* @param pos
|
|
2896
|
+
*/
|
|
2897
|
+
function CartesianToDegrees(pos) {
|
|
2898
|
+
if (!pos) {
|
|
2899
|
+
return null;
|
|
2900
|
+
}
|
|
2901
|
+
const cached = degreesCache.get(pos);
|
|
2902
|
+
if (cached) {
|
|
2903
|
+
return cached;
|
|
2904
|
+
}
|
|
2905
|
+
let carto;
|
|
2906
|
+
try {
|
|
2907
|
+
carto = Cartographic.fromCartesian(pos);
|
|
2908
|
+
}
|
|
2909
|
+
catch {
|
|
2910
|
+
return null;
|
|
2911
|
+
}
|
|
2912
|
+
if (!carto) {
|
|
2913
|
+
return null;
|
|
2914
|
+
}
|
|
2915
|
+
const degrees = {
|
|
2916
|
+
lat: Math$1.toDegrees(carto.latitude),
|
|
2917
|
+
lon: Math$1.toDegrees(carto.longitude)
|
|
2918
|
+
};
|
|
2919
|
+
degreesCache.set(pos, degrees);
|
|
2920
|
+
return degrees;
|
|
2921
|
+
}
|
|
2892
2922
|
/**
|
|
2893
2923
|
* Removes duplicate points in a row and returns a new array.
|
|
2894
2924
|
* Passed array is not mutated.
|
|
@@ -10758,41 +10788,107 @@ var HistoricFetchOrder;
|
|
|
10758
10788
|
return Math.round(minMs + ((maxMs - minMs) * progress));
|
|
10759
10789
|
}
|
|
10760
10790
|
HistoricFetchOrder.IntervalFor = IntervalFor;
|
|
10791
|
+
// Upper bounds in metres for the distance bands, nearest first.
|
|
10792
|
+
HistoricFetchOrder.DEFAULT_BANDS = [500, 2000, 10000, 50000];
|
|
10761
10793
|
/**
|
|
10762
|
-
*
|
|
10763
|
-
*
|
|
10764
|
-
* Bands rather than a true sort, so a small camera move does not reshuffle the whole queue and
|
|
10765
|
-
* restart it. What the user is looking at resolves first either way.
|
|
10794
|
+
* Resolves what to order by from the view monitor, falling back to the camera itself.
|
|
10766
10795
|
*/
|
|
10767
|
-
function
|
|
10796
|
+
function FocusFrom(params) {
|
|
10768
10797
|
var _a;
|
|
10769
|
-
const { viewer,
|
|
10770
|
-
|
|
10771
|
-
|
|
10798
|
+
const { viewer, monitor } = params;
|
|
10799
|
+
let origin = null;
|
|
10800
|
+
let bounds = null;
|
|
10801
|
+
try {
|
|
10802
|
+
// Null whenever the view has no ground intersection, eg. a camera aimed at the sky.
|
|
10803
|
+
const target = monitor === null || monitor === void 0 ? void 0 : monitor.GetTarget();
|
|
10804
|
+
if (target && isFinite(target.latitude) && isFinite(target.longitude)) {
|
|
10805
|
+
origin = Cartesian3.fromDegrees(target.longitude, target.latitude);
|
|
10806
|
+
}
|
|
10807
|
+
bounds = (monitor === null || monitor === void 0 ? void 0 : monitor.GetBounds()) || null;
|
|
10808
|
+
}
|
|
10809
|
+
catch {
|
|
10810
|
+
origin = null;
|
|
10811
|
+
bounds = null;
|
|
10812
|
+
}
|
|
10813
|
+
if (!origin) {
|
|
10814
|
+
origin = (_a = viewer === null || viewer === void 0 ? void 0 : viewer.camera) === null || _a === void 0 ? void 0 : _a.position;
|
|
10815
|
+
}
|
|
10816
|
+
if (!origin) {
|
|
10817
|
+
return null;
|
|
10818
|
+
}
|
|
10819
|
+
return bounds ? { origin, bounds } : { origin };
|
|
10820
|
+
}
|
|
10821
|
+
HistoricFetchOrder.FocusFrom = FocusFrom;
|
|
10822
|
+
/**
|
|
10823
|
+
* Returns the Entities grouped nearest first, on screen ahead of off screen.
|
|
10824
|
+
*/
|
|
10825
|
+
function ByCameraDistance(params) {
|
|
10826
|
+
const { viewer, entities, monitor } = params;
|
|
10827
|
+
return ByCameraDistanceOf({
|
|
10828
|
+
focus: FocusFrom({ viewer, monitor }),
|
|
10829
|
+
items: entities,
|
|
10830
|
+
posOf: (entity) => SafePos(entity, viewer),
|
|
10831
|
+
bands: params.bands
|
|
10832
|
+
});
|
|
10833
|
+
}
|
|
10834
|
+
HistoricFetchOrder.ByCameraDistance = ByCameraDistance;
|
|
10835
|
+
/**
|
|
10836
|
+
* Bands anything that can name its own world position, on the same bounds as the Entity form.
|
|
10837
|
+
*/
|
|
10838
|
+
function ByCameraDistanceOf(params) {
|
|
10839
|
+
const { focus, items, posOf } = params;
|
|
10840
|
+
const bands = params.bands || HistoricFetchOrder.DEFAULT_BANDS;
|
|
10841
|
+
if (!(items === null || items === void 0 ? void 0 : items.length)) {
|
|
10772
10842
|
return [];
|
|
10773
10843
|
}
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10844
|
+
if (!(focus === null || focus === void 0 ? void 0 : focus.origin)) {
|
|
10845
|
+
return [items];
|
|
10846
|
+
}
|
|
10847
|
+
// One band past the named bounds, for everything beyond the last of them. Then the same
|
|
10848
|
+
// again for what is off screen, so nothing visible waits behind something that is not.
|
|
10849
|
+
const perTier = bands.length + 1;
|
|
10850
|
+
const offScreenTier = focus.bounds ? perTier : 0;
|
|
10851
|
+
const placeless = offScreenTier + perTier;
|
|
10852
|
+
const grouped = [];
|
|
10853
|
+
for (let i = 0; i <= placeless; i++) {
|
|
10854
|
+
grouped.push([]);
|
|
10777
10855
|
}
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
const pos = SafePos(entity, viewer);
|
|
10856
|
+
for (const item of items) {
|
|
10857
|
+
// An item with no position falls to the last group rather than blocking the near ones.
|
|
10858
|
+
const pos = posOf(item);
|
|
10782
10859
|
if (!pos) {
|
|
10783
|
-
|
|
10860
|
+
grouped[placeless].push(item);
|
|
10784
10861
|
continue;
|
|
10785
10862
|
}
|
|
10786
|
-
const distance = Cartesian3.distance(
|
|
10787
|
-
let
|
|
10788
|
-
if (
|
|
10789
|
-
|
|
10863
|
+
const distance = Cartesian3.distance(focus.origin, pos);
|
|
10864
|
+
let band = bands.findIndex(bound => distance <= bound);
|
|
10865
|
+
if (band < 0) {
|
|
10866
|
+
band = bands.length;
|
|
10790
10867
|
}
|
|
10791
|
-
|
|
10868
|
+
grouped[(focus.bounds && !InBounds(pos, focus.bounds)) ? offScreenTier + band : band].push(item);
|
|
10792
10869
|
}
|
|
10793
|
-
return
|
|
10870
|
+
return grouped.filter(group => group.length > 0);
|
|
10794
10871
|
}
|
|
10795
|
-
HistoricFetchOrder.
|
|
10872
|
+
HistoricFetchOrder.ByCameraDistanceOf = ByCameraDistanceOf;
|
|
10873
|
+
/*
|
|
10874
|
+
* Returns whether a world position sits inside a ground rectangle given in degrees.
|
|
10875
|
+
*/
|
|
10876
|
+
function InBounds(pos, bounds) {
|
|
10877
|
+
const degrees = CartesianToDegrees(pos);
|
|
10878
|
+
if (!degrees) {
|
|
10879
|
+
return false;
|
|
10880
|
+
}
|
|
10881
|
+
const { lat, lon } = degrees;
|
|
10882
|
+
if (lat < bounds.south || lat > bounds.north) {
|
|
10883
|
+
return false;
|
|
10884
|
+
}
|
|
10885
|
+
// A view straddling the antimeridian reports west east of east, so the span is the outside.
|
|
10886
|
+
if (bounds.west > bounds.east) {
|
|
10887
|
+
return lon >= bounds.west || lon <= bounds.east;
|
|
10888
|
+
}
|
|
10889
|
+
return lon >= bounds.west && lon <= bounds.east;
|
|
10890
|
+
}
|
|
10891
|
+
HistoricFetchOrder.InBounds = InBounds;
|
|
10796
10892
|
/*
|
|
10797
10893
|
* Returns an Entity's world position, or null when it has none to place it by.
|
|
10798
10894
|
*/
|
|
@@ -11110,7 +11206,7 @@ class HistoricGatherer {
|
|
|
11110
11206
|
}
|
|
11111
11207
|
if (plan.detail) {
|
|
11112
11208
|
const bands = entities.length > HistoricFetchOrder.SMALL_SET
|
|
11113
|
-
? HistoricFetchOrder.ByCameraDistance({ viewer, entities })
|
|
11209
|
+
? HistoricFetchOrder.ByCameraDistance({ viewer, entities, monitor: this.params.monitor })
|
|
11114
11210
|
: [entities];
|
|
11115
11211
|
for (const range of this.cache.MissingRanges(plan.detail.start, plan.detail.stop)) {
|
|
11116
11212
|
if (this.disposed) {
|
|
@@ -11279,6 +11375,7 @@ var EntitiesRenderManager;
|
|
|
11279
11375
|
this.onSeriesDiscovered = onSeriesDiscovered;
|
|
11280
11376
|
this.historicGatherer = new HistoricGatherer({
|
|
11281
11377
|
viewer: this.viewer,
|
|
11378
|
+
monitor: this.monitor,
|
|
11282
11379
|
getApi: () => this.apiGetter.getApi(),
|
|
11283
11380
|
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
11284
11381
|
// A second either side, to take in records sitting exactly on the boundary.
|
|
@@ -13395,6 +13492,7 @@ var EntitiesIdsRenderManager;
|
|
|
13395
13492
|
this.visualsManager = visualsManager;
|
|
13396
13493
|
this.historicGatherer = new HistoricGatherer({
|
|
13397
13494
|
viewer: this.viewer,
|
|
13495
|
+
monitor: this.monitor,
|
|
13398
13496
|
getApi: () => this.apiGetter.getApi(),
|
|
13399
13497
|
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
13400
13498
|
// Padding either side of a requested range, for clock desync between us and the server.
|
|
@@ -14033,6 +14131,18 @@ class EntityGatherer {
|
|
|
14033
14131
|
this.lastFoundDateTimes = new Map();
|
|
14034
14132
|
// ID of Entity IDs that need to be requested.
|
|
14035
14133
|
this.eIdQueue = [];
|
|
14134
|
+
// Membership mirror of eIdQueue for quick checks.
|
|
14135
|
+
this.eIdQueued = new Set();
|
|
14136
|
+
// Resolves where an Entity sits without reading its record, when the caller can say.
|
|
14137
|
+
// Unset leaves the queue in insertion order, which is what sources that bake no coordinates get.
|
|
14138
|
+
this.positionOf = null;
|
|
14139
|
+
// How many IDs at the front of the queue were explicitly asked for first.
|
|
14140
|
+
// Camera ordering leaves those alone, since an explicit re-render outranks proximity.
|
|
14141
|
+
this.priorityCount = 0;
|
|
14142
|
+
// View focus the queue was last banded from.
|
|
14143
|
+
this.lastOrderFocus = null;
|
|
14144
|
+
// Reports what the camera is aimed at, rather than only where it sits.
|
|
14145
|
+
this.monitor = null;
|
|
14036
14146
|
// All IDs that have ever been queued.
|
|
14037
14147
|
// When nothing is in queue, we'll re-request the existing IDs based on timeline changes.
|
|
14038
14148
|
this.allEIds = new Set();
|
|
@@ -14132,6 +14242,9 @@ class EntityGatherer {
|
|
|
14132
14242
|
return;
|
|
14133
14243
|
}
|
|
14134
14244
|
this.eIdQueue = [];
|
|
14245
|
+
this.eIdQueued.clear();
|
|
14246
|
+
this.priorityCount = 0;
|
|
14247
|
+
this.lastOrderFocus = null;
|
|
14135
14248
|
this.allEIds.clear();
|
|
14136
14249
|
this.lastFoundDateTimes.clear();
|
|
14137
14250
|
this.lastDateTime = null;
|
|
@@ -14141,29 +14254,148 @@ class EntityGatherer {
|
|
|
14141
14254
|
return;
|
|
14142
14255
|
}
|
|
14143
14256
|
this.eIdQueue = Array.from(this.allEIds);
|
|
14257
|
+
this.eIdQueued = new Set(this.eIdQueue);
|
|
14258
|
+
this.priorityCount = 0;
|
|
14259
|
+
this.lastOrderFocus = null;
|
|
14260
|
+
}
|
|
14261
|
+
/**
|
|
14262
|
+
* Supplies a lookup from Entity ID to world position, letting the queue resolve what the camera
|
|
14263
|
+
* is nearest first. Sources that cannot answer should not call this, and are served in order.
|
|
14264
|
+
*/
|
|
14265
|
+
SetPositionSource(positionOf) {
|
|
14266
|
+
this.positionOf = positionOf;
|
|
14267
|
+
this.lastOrderFocus = null;
|
|
14268
|
+
}
|
|
14269
|
+
/**
|
|
14270
|
+
* Supplies the view monitor, so the order follows the ground the camera is aimed at and prefers
|
|
14271
|
+
* what is on screen. Without one the ordering falls back to distance from the camera itself.
|
|
14272
|
+
*/
|
|
14273
|
+
SetViewMonitor(monitor) {
|
|
14274
|
+
this.monitor = monitor;
|
|
14275
|
+
this.lastOrderFocus = null;
|
|
14276
|
+
}
|
|
14277
|
+
/**
|
|
14278
|
+
* Re-bands the pending queue so the nearest Entities are requested first.
|
|
14279
|
+
*/
|
|
14280
|
+
orderQueueByCamera() {
|
|
14281
|
+
if (!this.positionOf || this.eIdQueue.length < EntityGatherer.MIN_ORDER_QUEUE) {
|
|
14282
|
+
return;
|
|
14283
|
+
}
|
|
14284
|
+
const focus = HistoricFetchOrder.FocusFrom({ viewer: this.viewer, monitor: this.monitor });
|
|
14285
|
+
if (!focus) {
|
|
14286
|
+
return;
|
|
14287
|
+
}
|
|
14288
|
+
// Re-banding on every batch would cost a full pass per request for no change in the answer.
|
|
14289
|
+
// Measured on the focus, so panning across the ground counts even when the eye barely moves.
|
|
14290
|
+
if (this.lastOrderFocus && !EntityGatherer.boundsChanged(this.lastOrderFocus, focus) &&
|
|
14291
|
+
Cartesian3.distance(this.lastOrderFocus.origin, focus.origin) < EntityGatherer.REORDER_MOVE_METRES) {
|
|
14292
|
+
return;
|
|
14293
|
+
}
|
|
14294
|
+
this.lastOrderFocus = focus;
|
|
14295
|
+
const priority = this.priorityCount > 0 ? this.eIdQueue.slice(0, this.priorityCount) : [];
|
|
14296
|
+
const rest = this.priorityCount > 0 ? this.eIdQueue.slice(this.priorityCount) : this.eIdQueue;
|
|
14297
|
+
if (!rest.length) {
|
|
14298
|
+
return;
|
|
14299
|
+
}
|
|
14300
|
+
this.eIdQueue = priority.concat(this.bandIds(rest, focus));
|
|
14301
|
+
}
|
|
14302
|
+
/*
|
|
14303
|
+
* Returns whether the visible rectangle differs enough to change what counts as on screen.
|
|
14304
|
+
*/
|
|
14305
|
+
static boundsChanged(a, b) {
|
|
14306
|
+
if (!a.bounds || !b.bounds) {
|
|
14307
|
+
return Boolean(a.bounds) !== Boolean(b.bounds);
|
|
14308
|
+
}
|
|
14309
|
+
return (a.bounds.north !== b.bounds.north ||
|
|
14310
|
+
a.bounds.south !== b.bounds.south ||
|
|
14311
|
+
a.bounds.east !== b.bounds.east ||
|
|
14312
|
+
a.bounds.west !== b.bounds.west);
|
|
14313
|
+
}
|
|
14314
|
+
/*
|
|
14315
|
+
* Returns the IDs reordered nearest band first, or unchanged when there is nothing to order by.
|
|
14316
|
+
*/
|
|
14317
|
+
bandIds(entityIds, focus) {
|
|
14318
|
+
const from = focus || HistoricFetchOrder.FocusFrom({ viewer: this.viewer, monitor: this.monitor });
|
|
14319
|
+
if (!this.positionOf || !from || !entityIds.length) {
|
|
14320
|
+
return entityIds;
|
|
14321
|
+
}
|
|
14322
|
+
const banded = HistoricFetchOrder.ByCameraDistanceOf({
|
|
14323
|
+
focus: from,
|
|
14324
|
+
items: entityIds,
|
|
14325
|
+
posOf: (entityId) => {
|
|
14326
|
+
try {
|
|
14327
|
+
return this.positionOf(entityId);
|
|
14328
|
+
}
|
|
14329
|
+
catch {
|
|
14330
|
+
return null;
|
|
14331
|
+
}
|
|
14332
|
+
}
|
|
14333
|
+
});
|
|
14334
|
+
const ordered = [];
|
|
14335
|
+
for (const band of banded) {
|
|
14336
|
+
for (const entityId of band) {
|
|
14337
|
+
ordered.push(entityId);
|
|
14338
|
+
}
|
|
14339
|
+
}
|
|
14340
|
+
return ordered;
|
|
14144
14341
|
}
|
|
14145
14342
|
Queue(entityIds, topOfQueue = false) {
|
|
14146
14343
|
if (this.disposed || !(entityIds === null || entityIds === void 0 ? void 0 : entityIds.length)) {
|
|
14147
14344
|
return;
|
|
14148
14345
|
}
|
|
14149
14346
|
let changes = 0;
|
|
14150
|
-
|
|
14151
|
-
|
|
14152
|
-
|
|
14153
|
-
|
|
14154
|
-
|
|
14155
|
-
|
|
14156
|
-
|
|
14157
|
-
|
|
14158
|
-
this.
|
|
14159
|
-
|
|
14347
|
+
if (topOfQueue) {
|
|
14348
|
+
// Walked back to front so a repeated ID keeps the position of its last occurrence, then
|
|
14349
|
+
// laid down in that order, which is where inserting one at a time leaves them.
|
|
14350
|
+
const toFront = [];
|
|
14351
|
+
const promoting = new Set();
|
|
14352
|
+
let anyAlreadyQueued = false;
|
|
14353
|
+
for (let i = entityIds.length - 1; i >= 0; i--) {
|
|
14354
|
+
const eId = entityIds[i];
|
|
14355
|
+
this.allEIds.add(eId);
|
|
14356
|
+
if (promoting.has(eId)) {
|
|
14357
|
+
continue;
|
|
14358
|
+
}
|
|
14359
|
+
promoting.add(eId);
|
|
14360
|
+
toFront.push(eId);
|
|
14361
|
+
if (this.eIdQueued.has(eId)) {
|
|
14362
|
+
anyAlreadyQueued = true;
|
|
14363
|
+
}
|
|
14364
|
+
}
|
|
14365
|
+
if (anyAlreadyQueued && this.eIdQueue.length) {
|
|
14366
|
+
const kept = [];
|
|
14367
|
+
let removedFromPriority = 0;
|
|
14368
|
+
for (let i = 0; i < this.eIdQueue.length; i++) {
|
|
14369
|
+
const eId = this.eIdQueue[i];
|
|
14370
|
+
if (promoting.has(eId)) {
|
|
14371
|
+
if (i < this.priorityCount) {
|
|
14372
|
+
removedFromPriority += 1;
|
|
14373
|
+
}
|
|
14374
|
+
continue;
|
|
14375
|
+
}
|
|
14376
|
+
kept.push(eId);
|
|
14377
|
+
}
|
|
14378
|
+
this.eIdQueue = kept;
|
|
14379
|
+
this.priorityCount = Math.max(0, this.priorityCount - removedFromPriority);
|
|
14160
14380
|
}
|
|
14161
|
-
|
|
14381
|
+
this.eIdQueue = toFront.concat(this.eIdQueue);
|
|
14382
|
+
this.priorityCount += toFront.length;
|
|
14383
|
+
for (let i = 0; i < toFront.length; i++) {
|
|
14384
|
+
this.eIdQueued.add(toFront[i]);
|
|
14385
|
+
}
|
|
14386
|
+
changes = toFront.length;
|
|
14387
|
+
}
|
|
14388
|
+
else {
|
|
14389
|
+
for (let i = 0; i < entityIds.length; i++) {
|
|
14390
|
+
const eId = entityIds[i];
|
|
14391
|
+
this.allEIds.add(eId);
|
|
14392
|
+
if (this.eIdQueued.has(eId)) {
|
|
14393
|
+
continue;
|
|
14394
|
+
}
|
|
14395
|
+
this.eIdQueued.add(eId);
|
|
14162
14396
|
this.eIdQueue.push(eId);
|
|
14163
14397
|
changes += 1;
|
|
14164
14398
|
}
|
|
14165
|
-
// Flag that we've seen this ID.
|
|
14166
|
-
this.allEIds.add(entityIds[i]);
|
|
14167
14399
|
}
|
|
14168
14400
|
if (!changes) {
|
|
14169
14401
|
return;
|
|
@@ -14297,7 +14529,7 @@ class EntityGatherer {
|
|
|
14297
14529
|
this.emitEntities(toEmit, tags);
|
|
14298
14530
|
};
|
|
14299
14531
|
const QUEUE_BATCH_SIZE = 500;
|
|
14300
|
-
const requestedIds =
|
|
14532
|
+
const requestedIds = new Set();
|
|
14301
14533
|
// If we have a queue, we need to request those first.
|
|
14302
14534
|
if (this.eIdQueue.length) {
|
|
14303
14535
|
const total = this.eIdQueue.length;
|
|
@@ -14306,7 +14538,12 @@ class EntityGatherer {
|
|
|
14306
14538
|
if (this.historic && this.lastDateTime !== rTime) {
|
|
14307
14539
|
break;
|
|
14308
14540
|
}
|
|
14541
|
+
this.orderQueueByCamera();
|
|
14309
14542
|
const batch = this.eIdQueue.splice(0, QUEUE_BATCH_SIZE);
|
|
14543
|
+
this.priorityCount = Math.max(0, this.priorityCount - batch.length);
|
|
14544
|
+
for (let i = 0; i < batch.length; i++) {
|
|
14545
|
+
this.eIdQueued.delete(batch[i]);
|
|
14546
|
+
}
|
|
14310
14547
|
const { entities } = await Entity$1.GetListByIds({
|
|
14311
14548
|
entityIds: batch,
|
|
14312
14549
|
historicPoint: this.historic ? rTime : null,
|
|
@@ -14315,7 +14552,9 @@ class EntityGatherer {
|
|
|
14315
14552
|
maxSearchTimeSec: 60 * 2
|
|
14316
14553
|
});
|
|
14317
14554
|
handleResponse(batch, entities);
|
|
14318
|
-
|
|
14555
|
+
for (let i = 0; i < batch.length; i++) {
|
|
14556
|
+
requestedIds.add(batch[i]);
|
|
14557
|
+
}
|
|
14319
14558
|
done += batch.length;
|
|
14320
14559
|
if (this._onQueueProgress) {
|
|
14321
14560
|
let progress = (done / total) * 100;
|
|
@@ -14335,10 +14574,13 @@ class EntityGatherer {
|
|
|
14335
14574
|
// Now run through all IDs that we've seen and request them.
|
|
14336
14575
|
// We'll skip those that we just requested.
|
|
14337
14576
|
let allEIds = Array.from(this.allEIds);
|
|
14338
|
-
if (requestedIds.
|
|
14339
|
-
allEIds = allEIds.filter((eId) => requestedIds.
|
|
14577
|
+
if (requestedIds.size) {
|
|
14578
|
+
allEIds = allEIds.filter((eId) => !requestedIds.has(eId));
|
|
14340
14579
|
}
|
|
14341
14580
|
if (allEIds.length) {
|
|
14581
|
+
// A historic tick re-reads the whole set, so the near ones are worth resolving
|
|
14582
|
+
// first here even more than in the queue above.
|
|
14583
|
+
allEIds = this.bandIds(allEIds);
|
|
14342
14584
|
while (allEIds.length && !this.disposed && !this.eIdQueue.length) {
|
|
14343
14585
|
if (this.historic && this.lastDateTime !== rTime) {
|
|
14344
14586
|
break;
|
|
@@ -14352,7 +14594,9 @@ class EntityGatherer {
|
|
|
14352
14594
|
maxSearchTimeSec: 60 * 2
|
|
14353
14595
|
});
|
|
14354
14596
|
handleResponse(batch, entities);
|
|
14355
|
-
|
|
14597
|
+
for (let i = 0; i < batch.length; i++) {
|
|
14598
|
+
requestedIds.add(batch[i]);
|
|
14599
|
+
}
|
|
14356
14600
|
}
|
|
14357
14601
|
}
|
|
14358
14602
|
// If we had leftovers because we stopped early, we need to re-run the tick.
|
|
@@ -14372,6 +14616,11 @@ class EntityGatherer {
|
|
|
14372
14616
|
})();
|
|
14373
14617
|
}
|
|
14374
14618
|
}
|
|
14619
|
+
// Below this the whole queue clears in one or two requests, so ordering it buys nothing.
|
|
14620
|
+
EntityGatherer.MIN_ORDER_QUEUE = 500;
|
|
14621
|
+
// How far the point being looked at has to move before the queue is worth re-banding, in metres.
|
|
14622
|
+
// Under the nearest band's width, so a move that could change what is nearest still triggers one.
|
|
14623
|
+
EntityGatherer.REORDER_MOVE_METRES = 250;
|
|
14375
14624
|
|
|
14376
14625
|
// ND-1641. BOOKMARKS - (DEMO) View does not match bookmark.
|
|
14377
14626
|
// We have some evil hard-coded style mappings that need to be fixed.
|
|
@@ -14495,7 +14744,8 @@ class TilesetStyler {
|
|
|
14495
14744
|
}
|
|
14496
14745
|
Init(params) {
|
|
14497
14746
|
var _a, _b;
|
|
14498
|
-
let { viewer, api, cTileset, fallbackStyleId, styleMapping, expandSources, menuItemId, register, scenario, historic, applyStyles } = params;
|
|
14747
|
+
let { viewer, api, cTileset, fallbackStyleId, styleMapping, expandSources, menuItemId, register, scenario, historic, applyStyles, monitor } = params;
|
|
14748
|
+
this.monitor = monitor;
|
|
14499
14749
|
this.viewer = viewer;
|
|
14500
14750
|
this.api = api;
|
|
14501
14751
|
this.cTileset = cTileset;
|
|
@@ -14551,6 +14801,14 @@ class TilesetStyler {
|
|
|
14551
14801
|
}
|
|
14552
14802
|
}
|
|
14553
14803
|
});
|
|
14804
|
+
// Only Entities Sets bake coordinates into their features, so for any other source this
|
|
14805
|
+
// resolves nothing and the gather stays in insertion order.
|
|
14806
|
+
this.entityGatherer.SetViewMonitor(this.monitor);
|
|
14807
|
+
this.entityGatherer.SetPositionSource((entityId) => {
|
|
14808
|
+
var _a;
|
|
14809
|
+
const visual = (_a = this.getEntityRego(entityId)) === null || _a === void 0 ? void 0 : _a.visual;
|
|
14810
|
+
return (visual === null || visual === void 0 ? void 0 : visual._bakedPos) || null;
|
|
14811
|
+
});
|
|
14554
14812
|
this.loaded = true;
|
|
14555
14813
|
this.loadStyles();
|
|
14556
14814
|
const feed = (_b = this.api) === null || _b === void 0 ? void 0 : _b.RecordChangeFeed;
|
|
@@ -19774,7 +20032,8 @@ var TilesetEntitiesRenderManager;
|
|
|
19774
20032
|
// Saves having to do a case-insensitive lookup every time.
|
|
19775
20033
|
this.featurePropCache = new Map();
|
|
19776
20034
|
this.featurePropsChecked = 0;
|
|
19777
|
-
const { viewer, register: visualsManager, getters: apiGetter, item, initQueue } = params;
|
|
20035
|
+
const { viewer, register: visualsManager, getters: apiGetter, item, initQueue, monitor } = params;
|
|
20036
|
+
this.monitor = monitor;
|
|
19778
20037
|
this.viewer = viewer;
|
|
19779
20038
|
this.getters = apiGetter;
|
|
19780
20039
|
this.item = item;
|
|
@@ -19883,7 +20142,8 @@ var TilesetEntitiesRenderManager;
|
|
|
19883
20142
|
menuItemId: this.item.id,
|
|
19884
20143
|
register: this.visualsManager,
|
|
19885
20144
|
historic: Manager.IsHistoric(this.item),
|
|
19886
|
-
applyStyles: Boolean(this.item.ApplyStyles)
|
|
20145
|
+
applyStyles: Boolean(this.item.ApplyStyles),
|
|
20146
|
+
monitor: this.monitor
|
|
19887
20147
|
});
|
|
19888
20148
|
}
|
|
19889
20149
|
this.onCTilesetLoad();
|
|
@@ -20043,6 +20303,16 @@ var TilesetEntitiesRenderManager;
|
|
|
20043
20303
|
else if (lowered === "internalid") {
|
|
20044
20304
|
this.featurePropCache.set("internalId", prop);
|
|
20045
20305
|
}
|
|
20306
|
+
else if (lowered === "latitude") {
|
|
20307
|
+
this.featurePropCache.set("latitude", prop);
|
|
20308
|
+
}
|
|
20309
|
+
else if (lowered === "longitude") {
|
|
20310
|
+
this.featurePropCache.set("longitude", prop);
|
|
20311
|
+
}
|
|
20312
|
+
// b3dm names the baked height TerrainHeight, the glTF metadata table calls it Altitude.
|
|
20313
|
+
else if (lowered === "terrainheight" || lowered === "altitude") {
|
|
20314
|
+
this.featurePropCache.set("height", prop);
|
|
20315
|
+
}
|
|
20046
20316
|
}
|
|
20047
20317
|
}
|
|
20048
20318
|
Dispose() {
|
|
@@ -20197,7 +20467,8 @@ var TilesetEntitiesRenderManager;
|
|
|
20197
20467
|
menuItemId: this.item.id,
|
|
20198
20468
|
register: this.visualsManager,
|
|
20199
20469
|
historic: Manager.IsHistoric(this.item),
|
|
20200
|
-
applyStyles: Boolean(this.item.ApplyStyles)
|
|
20470
|
+
applyStyles: Boolean(this.item.ApplyStyles),
|
|
20471
|
+
monitor: this.monitor
|
|
20201
20472
|
});
|
|
20202
20473
|
this.queueHandoffRestyle(this.visualsManager.GetRegos({ menuItemId: this.item.id }));
|
|
20203
20474
|
}
|
|
@@ -20240,6 +20511,45 @@ var TilesetEntitiesRenderManager;
|
|
|
20240
20511
|
}
|
|
20241
20512
|
}, 10);
|
|
20242
20513
|
}
|
|
20514
|
+
/*
|
|
20515
|
+
* Reads a numeric feature property, returning null for anything that is not one.
|
|
20516
|
+
*/
|
|
20517
|
+
static readNumber(feature, prop) {
|
|
20518
|
+
const raw = feature.getProperty(prop);
|
|
20519
|
+
// Coercing straight to a number would turn null, undefined and "" into a valid zero,
|
|
20520
|
+
// which for a coordinate is a real place off the coast of Africa.
|
|
20521
|
+
if (raw == null || raw === "" || typeof raw === "boolean") {
|
|
20522
|
+
return null;
|
|
20523
|
+
}
|
|
20524
|
+
const value = +raw;
|
|
20525
|
+
return isFinite(value) ? value : null;
|
|
20526
|
+
}
|
|
20527
|
+
/*
|
|
20528
|
+
* Returns the world position an Entities Set bakes into each feature, or null when it has none.
|
|
20529
|
+
*/
|
|
20530
|
+
readBakedPos(feature) {
|
|
20531
|
+
const latProp = this.featurePropCache.get("latitude");
|
|
20532
|
+
const lonProp = this.featurePropCache.get("longitude");
|
|
20533
|
+
if (!latProp || !lonProp) {
|
|
20534
|
+
return null;
|
|
20535
|
+
}
|
|
20536
|
+
try {
|
|
20537
|
+
const lat = Manager.readNumber(feature, latProp);
|
|
20538
|
+
const lon = Manager.readNumber(feature, lonProp);
|
|
20539
|
+
// Degrees, per the batch table the generator writes. The range check doubles as a
|
|
20540
|
+
// guard against a source that bakes radians, which would otherwise read as valid.
|
|
20541
|
+
if (lat == null || lon == null || Math.abs(lat) > 90 || Math.abs(lon) > 180) {
|
|
20542
|
+
return null;
|
|
20543
|
+
}
|
|
20544
|
+
// A height that will not read is worth losing, the position it belongs to is not.
|
|
20545
|
+
const heightProp = this.featurePropCache.get("height");
|
|
20546
|
+
const height = heightProp ? Manager.readNumber(feature, heightProp) : 0;
|
|
20547
|
+
return Cartesian3.fromDegrees(lon, lat, height !== null && height !== void 0 ? height : 0);
|
|
20548
|
+
}
|
|
20549
|
+
catch {
|
|
20550
|
+
return null;
|
|
20551
|
+
}
|
|
20552
|
+
}
|
|
20243
20553
|
mapTilesetFeature(feature) {
|
|
20244
20554
|
var _a, _b, _c;
|
|
20245
20555
|
this.evaluateFeatureProps(feature);
|
|
@@ -20320,6 +20630,12 @@ var TilesetEntitiesRenderManager;
|
|
|
20320
20630
|
rego.internalId = parsed;
|
|
20321
20631
|
}
|
|
20322
20632
|
}
|
|
20633
|
+
// Stamped on the feature the properties came from, so a sibling keeps its own position
|
|
20634
|
+
// and nothing has to be cleaned up when the tile unloads.
|
|
20635
|
+
const bakedPos = this.readBakedPos(feature);
|
|
20636
|
+
if (bakedPos) {
|
|
20637
|
+
feature._bakedPos = bakedPos;
|
|
20638
|
+
}
|
|
20323
20639
|
this.loadedCesiumEntities[rego.entityId] = rego;
|
|
20324
20640
|
this.visualsManager.AddRego({
|
|
20325
20641
|
rego,
|
|
@@ -24205,6 +24521,7 @@ var MenuItemManager;
|
|
|
24205
24521
|
viewer: this.viewer,
|
|
24206
24522
|
register: this.visualsRegister,
|
|
24207
24523
|
getters: this.getters,
|
|
24524
|
+
monitor: this.sharedMonitor,
|
|
24208
24525
|
item: params.item,
|
|
24209
24526
|
initQueue: this.tilesetInitQueue
|
|
24210
24527
|
});
|
|
@@ -40999,9 +41316,11 @@ var TextureFrameSeriesAnimator;
|
|
|
40999
41316
|
return;
|
|
41000
41317
|
}
|
|
41001
41318
|
let next = -1;
|
|
41319
|
+
let isTarget = false;
|
|
41002
41320
|
if (this.pendingIndex !== -1) {
|
|
41003
41321
|
next = this.pendingIndex;
|
|
41004
41322
|
this.pendingIndex = -1;
|
|
41323
|
+
isTarget = true;
|
|
41005
41324
|
}
|
|
41006
41325
|
else {
|
|
41007
41326
|
next = this.nearestUncachedFrame();
|
|
@@ -41010,7 +41329,7 @@ var TextureFrameSeriesAnimator;
|
|
|
41010
41329
|
return;
|
|
41011
41330
|
}
|
|
41012
41331
|
this.inFlightIndex = next;
|
|
41013
|
-
this.fetchAndTint(next)
|
|
41332
|
+
this.fetchAndTint(next, isTarget)
|
|
41014
41333
|
.catch(() => {
|
|
41015
41334
|
// Eating it.
|
|
41016
41335
|
})
|
|
@@ -41021,7 +41340,7 @@ var TextureFrameSeriesAnimator;
|
|
|
41021
41340
|
}
|
|
41022
41341
|
});
|
|
41023
41342
|
}
|
|
41024
|
-
async fetchAndTint(idx) {
|
|
41343
|
+
async fetchAndTint(idx, isTarget = true) {
|
|
41025
41344
|
const tiles = this.tiles;
|
|
41026
41345
|
// Every tile's frame for one timestep sits contiguously, because the generator writes
|
|
41027
41346
|
// frame major. So a tiled frame is still ONE range request, not one per tile.
|
|
@@ -41053,10 +41372,25 @@ var TextureFrameSeriesAnimator;
|
|
|
41053
41372
|
this.frameCache[idx] = decoded.pixels;
|
|
41054
41373
|
this.frameDims[idx] = { width: decoded.width, height: decoded.height };
|
|
41055
41374
|
this.valueCache[idx] = decoded.valuePixels || null;
|
|
41056
|
-
if (idx
|
|
41375
|
+
if (this.shouldPresent(idx, isTarget)) {
|
|
41057
41376
|
this.beginCrossfadeTo(idx);
|
|
41058
41377
|
}
|
|
41059
41378
|
}
|
|
41379
|
+
/*
|
|
41380
|
+
* Whether a frame that has just decoded is worth putting on screen.
|
|
41381
|
+
*/
|
|
41382
|
+
shouldPresent(idx, isTarget) {
|
|
41383
|
+
if (idx === this.currentFrameIndex) {
|
|
41384
|
+
return true;
|
|
41385
|
+
}
|
|
41386
|
+
// A prefetch is for a frame nobody asked to see, so it stays in the cache.
|
|
41387
|
+
if (!isTarget) {
|
|
41388
|
+
return false;
|
|
41389
|
+
}
|
|
41390
|
+
// Dragging the timeline retargets faster than a frame can be fetched, so the frame that
|
|
41391
|
+
// lands is rarely the one now under the playhead.
|
|
41392
|
+
return !this.frameCache[this.currentFrameIndex];
|
|
41393
|
+
}
|
|
41060
41394
|
/*
|
|
41061
41395
|
* Draws every tile of one frame into a single raster covering the drape extent.
|
|
41062
41396
|
*/
|
|
@@ -45619,7 +45953,7 @@ var StyleUtils;
|
|
|
45619
45953
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
45620
45954
|
})(StyleUtils || (StyleUtils = {}));
|
|
45621
45955
|
|
|
45622
|
-
const VERSION = "7.2.
|
|
45956
|
+
const VERSION = "7.2.6";
|
|
45623
45957
|
/**
|
|
45624
45958
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
45625
45959
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|