bruce-cesium 7.1.9 → 7.2.1
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 +679 -300
- package/dist/bruce-cesium.es5.js.map +1 -1
- package/dist/bruce-cesium.umd.js +678 -297
- package/dist/bruce-cesium.umd.js.map +1 -1
- package/dist/lib/bruce-cesium.js +1 -1
- package/dist/lib/rendering/entity-render-engine-model3d.js +2 -2
- package/dist/lib/rendering/entity-render-engine-model3d.js.map +1 -1
- package/dist/lib/rendering/render-managers/common/historic-utils.js +471 -0
- package/dist/lib/rendering/render-managers/common/historic-utils.js.map +1 -0
- package/dist/lib/rendering/render-managers/entities/entities-ids-render-manager.js +14 -124
- 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 +16 -13
- package/dist/lib/rendering/render-managers/entities/entities-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/other/assembly-render-manager.js +1 -1
- package/dist/lib/rendering/render-managers/other/assembly-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js +31 -109
- package/dist/lib/rendering/render-managers/tilesets/tileset-cad-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-entities-render-manager.js +23 -7
- package/dist/lib/rendering/render-managers/tilesets/tileset-entities-render-manager.js.map +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-google-photos-render-manager.js +1 -1
- package/dist/lib/rendering/render-managers/tilesets/tileset-google-photos-render-manager.js.map +1 -1
- package/dist/lib/rendering/tileset-render-engine.js +1 -1
- package/dist/lib/rendering/tileset-render-engine.js.map +1 -1
- package/dist/lib/rendering/tileset-styler.js +28 -24
- package/dist/lib/rendering/tileset-styler.js.map +1 -1
- package/dist/lib/utils/view-utils.js +100 -15
- package/dist/lib/utils/view-utils.js.map +1 -1
- package/dist/types/bruce-cesium.d.ts +1 -1
- package/dist/types/rendering/render-managers/common/historic-utils.d.ts +159 -0
- package/dist/types/rendering/render-managers/entities/entities-ids-render-manager.d.ts +1 -0
- package/dist/types/rendering/render-managers/entities/entities-render-manager.d.ts +5 -0
- package/dist/types/rendering/render-managers/tilesets/tileset-cad-render-manager.d.ts +1 -0
- package/dist/types/rendering/render-managers/tilesets/tileset-entities-render-manager.d.ts +2 -0
- package/dist/types/rendering/tileset-styler.d.ts +2 -0
- package/dist/types/utils/view-utils.d.ts +30 -7
- package/package.json +2 -2
package/dist/bruce-cesium.umd.js
CHANGED
|
@@ -2969,9 +2969,30 @@
|
|
|
2969
2969
|
const CESIUM_TIMELINE_INTERVAL_KEY = "_nextspace_timeline_interval";
|
|
2970
2970
|
const CESIUM_MODEL_SPACE_KEY = "_nextspace_model_space";
|
|
2971
2971
|
const DEFAULT_LIVE_PADDING_SECONDS = 30 * 60;
|
|
2972
|
-
|
|
2973
|
-
|
|
2972
|
+
// Atmosphere shifts are left alone by default. Tuning against a CAD scene showed the lift washing the
|
|
2973
|
+
// sky without helping models, which are lit by the environment map rather than by the atmosphere.
|
|
2974
|
+
const DEFAULT_BRIGHTNESS_SHIFT = 0;
|
|
2975
|
+
/*
|
|
2976
|
+
* Environment lighting defaults, arrived at by tuning against a white CAD model on CesiumJS 1.143.
|
|
2977
|
+
*/
|
|
2978
|
+
function neutralEnvironmentMapOptions() {
|
|
2979
|
+
return {
|
|
2980
|
+
groundColor: Cesium.Color.WHITE.clone(),
|
|
2981
|
+
groundAlbedo: 0.26,
|
|
2982
|
+
brightness: 1.5,
|
|
2983
|
+
atmosphereScatteringIntensity: 3.2
|
|
2984
|
+
};
|
|
2985
|
+
}
|
|
2986
|
+
// Sun intensity used when the bookmark's lighting settings name none.
|
|
2987
|
+
const DEFAULT_LIGHT_INTENSITY = 2;
|
|
2988
|
+
// Current shape of a bookmark's lighting settings.
|
|
2974
2989
|
const LIGHTING_SETTINGS_VERSION = 2;
|
|
2990
|
+
// Settings we apply when version is unset or <=1 to compensate for newer Cesium looking darker and more yellow.
|
|
2991
|
+
const LIGHT_INTENSITY_COMPENSATION = 1.2;
|
|
2992
|
+
const MAX_COMPENSATED_LIGHT_INTENSITY = 3;
|
|
2993
|
+
// Set by a host that wants something other than the defaults above. Undefined means "not overridden".
|
|
2994
|
+
let overriddenEnvironmentMapOptions;
|
|
2995
|
+
let overriddenImageBasedLighting;
|
|
2975
2996
|
(function (ViewUtils) {
|
|
2976
2997
|
function GatherLegacyMapTiles(params) {
|
|
2977
2998
|
const viewer = params.viewer;
|
|
@@ -3339,33 +3360,97 @@
|
|
|
3339
3360
|
SCENE.skyAtmosphere.brightnessShift = shift;
|
|
3340
3361
|
}
|
|
3341
3362
|
}
|
|
3363
|
+
// The environment map is built from the atmosphere, and lighting it from the scene's own light
|
|
3364
|
+
// rather than from straight above is what stops it reading flat.
|
|
3365
|
+
const CESIUM = Cesium;
|
|
3366
|
+
if (EngineShadesModelsDarker() && SCENE.atmosphere && CESIUM.DynamicAtmosphereLightingType) {
|
|
3367
|
+
SCENE.atmosphere.dynamicLighting = CESIUM.DynamicAtmosphereLightingType.SCENE_LIGHT;
|
|
3368
|
+
}
|
|
3342
3369
|
}
|
|
3343
3370
|
ViewUtils.ApplyDefaultBrightness = ApplyDefaultBrightness;
|
|
3371
|
+
/**
|
|
3372
|
+
* Options applied to the environment based lighting of every tileset and model this library creates.
|
|
3373
|
+
* Null leaves CesiumJS's own defaults in place.
|
|
3374
|
+
* @param options eg { enabled: false } to switch the lighting off, or { saturation: 0 } to keep the
|
|
3375
|
+
* lift without the ground bounce tinting untextured geometry.
|
|
3376
|
+
*/
|
|
3377
|
+
function SetDefaultEnvironmentMapOptions(options) {
|
|
3378
|
+
overriddenEnvironmentMapOptions = options;
|
|
3379
|
+
}
|
|
3380
|
+
ViewUtils.SetDefaultEnvironmentMapOptions = SetDefaultEnvironmentMapOptions;
|
|
3381
|
+
/**
|
|
3382
|
+
* Whether the host app's CesiumJS is a build that shades models darker than the ones these bookmarks were set up against.
|
|
3383
|
+
* DynamicEnvironmentMapManager arrived with that change, so its presence marks
|
|
3384
|
+
*/
|
|
3385
|
+
function GetDefaultEnvironmentMapOptions(
|
|
3386
|
+
// Overridable so the tuned values can be asserted without swapping out CesiumJS.
|
|
3387
|
+
engineShadesDarker = EngineShadesModelsDarker()) {
|
|
3388
|
+
if (overriddenEnvironmentMapOptions !== undefined) {
|
|
3389
|
+
return overriddenEnvironmentMapOptions ? { ...overriddenEnvironmentMapOptions } : null;
|
|
3390
|
+
}
|
|
3391
|
+
if (!engineShadesDarker) {
|
|
3392
|
+
return null;
|
|
3393
|
+
}
|
|
3394
|
+
return neutralEnvironmentMapOptions();
|
|
3395
|
+
}
|
|
3396
|
+
ViewUtils.GetDefaultEnvironmentMapOptions = GetDefaultEnvironmentMapOptions;
|
|
3397
|
+
/**
|
|
3398
|
+
* The lighting options every tileset and model this library creates is built with.
|
|
3399
|
+
* Spread into the construction options, since both are read once when a primitive is made.
|
|
3400
|
+
*/
|
|
3401
|
+
function DefaultLightingProps(engineShadesDarker = EngineShadesModelsDarker()) {
|
|
3402
|
+
const props = {};
|
|
3403
|
+
const environmentMapOptions = GetDefaultEnvironmentMapOptions(engineShadesDarker);
|
|
3404
|
+
if (environmentMapOptions) {
|
|
3405
|
+
props.environmentMapOptions = environmentMapOptions;
|
|
3406
|
+
}
|
|
3407
|
+
const imageBasedLighting = GetDefaultImageBasedLighting();
|
|
3408
|
+
if (imageBasedLighting) {
|
|
3409
|
+
props.imageBasedLighting = imageBasedLighting;
|
|
3410
|
+
}
|
|
3411
|
+
return props;
|
|
3412
|
+
}
|
|
3413
|
+
ViewUtils.DefaultLightingProps = DefaultLightingProps;
|
|
3414
|
+
/**
|
|
3415
|
+
* ImageBasedLighting applied to every tileset and model this library creates. Null, the default,
|
|
3416
|
+
* leaves CesiumJS's own in place.
|
|
3417
|
+
* @param imageBasedLighting a Cesium.ImageBasedLighting, shared across primitives.
|
|
3418
|
+
*/
|
|
3419
|
+
function SetDefaultImageBasedLighting(imageBasedLighting) {
|
|
3420
|
+
overriddenImageBasedLighting = imageBasedLighting;
|
|
3421
|
+
}
|
|
3422
|
+
ViewUtils.SetDefaultImageBasedLighting = SetDefaultImageBasedLighting;
|
|
3423
|
+
function GetDefaultImageBasedLighting() {
|
|
3424
|
+
return overriddenImageBasedLighting || null;
|
|
3425
|
+
}
|
|
3426
|
+
ViewUtils.GetDefaultImageBasedLighting = GetDefaultImageBasedLighting;
|
|
3427
|
+
function EngineShadesModelsDarker() {
|
|
3428
|
+
return typeof Cesium.DynamicEnvironmentMapManager !== "undefined";
|
|
3429
|
+
}
|
|
3430
|
+
ViewUtils.EngineShadesModelsDarker = EngineShadesModelsDarker;
|
|
3344
3431
|
/**
|
|
3345
3432
|
* Resolves the sun colour and intensity to apply for a bookmark's lighting settings.
|
|
3346
3433
|
* @param lighting the bookmark's lighting settings, or null when it carries none.
|
|
3347
3434
|
* @returns the colour and intensity to put on the scene light.
|
|
3348
3435
|
*/
|
|
3349
|
-
function ResolveLightSettings(lighting
|
|
3436
|
+
function ResolveLightSettings(lighting,
|
|
3437
|
+
// Overridable so both branches can be exercised without swapping out CesiumJS.
|
|
3438
|
+
engineShadesDarker = EngineShadesModelsDarker()) {
|
|
3350
3439
|
const raw = lighting === null || lighting === void 0 ? void 0 : lighting.color;
|
|
3351
|
-
// An unreadable or missing colour would otherwise leave the light undefined.
|
|
3352
3440
|
const parsed = raw ? Cesium.Color.fromCssColorString(raw) : null;
|
|
3353
|
-
const version = Number(lighting === null || lighting === void 0 ? void 0 : lighting.lightingVer);
|
|
3354
|
-
const stale = !Number.isFinite(version) || version <= 1;
|
|
3355
3441
|
const intensity = Number(lighting === null || lighting === void 0 ? void 0 : lighting.intensity);
|
|
3442
|
+
const named = Number.isFinite(intensity) ? intensity : DEFAULT_LIGHT_INTENSITY;
|
|
3443
|
+
// No settings at all means nothing was carried over from the older engine, so there is nothing
|
|
3444
|
+
// to compensate. A settings object with no version in it is the case that predates the field.
|
|
3445
|
+
const version = Number(lighting === null || lighting === void 0 ? void 0 : lighting.lightingVer);
|
|
3446
|
+
const legacy = lighting != null && (!Number.isFinite(version) || version <= 1);
|
|
3447
|
+
const compensated = Math.min(named * LIGHT_INTENSITY_COMPENSATION, MAX_COMPENSATED_LIGHT_INTENSITY);
|
|
3356
3448
|
return {
|
|
3357
3449
|
color: parsed || Cesium.Color.WHITE,
|
|
3358
|
-
intensity:
|
|
3450
|
+
intensity: legacy && engineShadesDarker ? compensated : named
|
|
3359
3451
|
};
|
|
3360
3452
|
}
|
|
3361
3453
|
ViewUtils.ResolveLightSettings = ResolveLightSettings;
|
|
3362
|
-
/**
|
|
3363
|
-
* Options handed to every tileset and model this library creates.
|
|
3364
|
-
*/
|
|
3365
|
-
function DefaultEnvironmentMapOptions() {
|
|
3366
|
-
return { enabled: false };
|
|
3367
|
-
}
|
|
3368
|
-
ViewUtils.DefaultEnvironmentMapOptions = DefaultEnvironmentMapOptions;
|
|
3369
3454
|
function SetGlobeDetails(params) {
|
|
3370
3455
|
let { viewer, hidden, baseColor } = params;
|
|
3371
3456
|
const scene = viewer === null || viewer === void 0 ? void 0 : viewer.scene;
|
|
@@ -10615,6 +10700,468 @@
|
|
|
10615
10700
|
}
|
|
10616
10701
|
}
|
|
10617
10702
|
|
|
10703
|
+
/**
|
|
10704
|
+
* How often a historic refresh is worth running, and which Entities it should ask about first.
|
|
10705
|
+
*
|
|
10706
|
+
* A handful of tracked vehicles can afford to re-read on almost every clock tick. Thousands of
|
|
10707
|
+
* parcels cannot, and refreshing them that often was never buying anything since the answer barely
|
|
10708
|
+
* changes between ticks.
|
|
10709
|
+
*/
|
|
10710
|
+
var HistoricFetchOrder;
|
|
10711
|
+
(function (HistoricFetchOrder) {
|
|
10712
|
+
// The cadence for a set small enough that latency is what the user notices.
|
|
10713
|
+
HistoricFetchOrder.MIN_INTERVAL_MS = 250;
|
|
10714
|
+
// The cadence for a set large enough that the request itself is what the user notices.
|
|
10715
|
+
HistoricFetchOrder.MAX_INTERVAL_MS = 10000;
|
|
10716
|
+
// Below this many Entities the cadence stays at its fastest.
|
|
10717
|
+
HistoricFetchOrder.SMALL_SET = 30;
|
|
10718
|
+
// At and above this many it stays at its slowest.
|
|
10719
|
+
HistoricFetchOrder.LARGE_SET = 5000;
|
|
10720
|
+
/**
|
|
10721
|
+
* Returns how long to wait between historic refreshes for a set of this size.
|
|
10722
|
+
*/
|
|
10723
|
+
function IntervalFor(entityCount, minMs = HistoricFetchOrder.MIN_INTERVAL_MS, maxMs = HistoricFetchOrder.MAX_INTERVAL_MS) {
|
|
10724
|
+
if (!(entityCount > HistoricFetchOrder.SMALL_SET)) {
|
|
10725
|
+
return minMs;
|
|
10726
|
+
}
|
|
10727
|
+
if (entityCount >= HistoricFetchOrder.LARGE_SET) {
|
|
10728
|
+
return maxMs;
|
|
10729
|
+
}
|
|
10730
|
+
// Log scaled, so going from 30 to 300 Entities costs more than going from 3000 to 5000.
|
|
10731
|
+
const progress = Math.log(entityCount / HistoricFetchOrder.SMALL_SET) / Math.log(HistoricFetchOrder.LARGE_SET / HistoricFetchOrder.SMALL_SET);
|
|
10732
|
+
return Math.round(minMs + ((maxMs - minMs) * progress));
|
|
10733
|
+
}
|
|
10734
|
+
HistoricFetchOrder.IntervalFor = IntervalFor;
|
|
10735
|
+
/**
|
|
10736
|
+
* Returns the Entities grouped into bands by distance from the camera, nearest band first.
|
|
10737
|
+
*
|
|
10738
|
+
* Bands rather than a true sort, so a small camera move does not reshuffle the whole queue and
|
|
10739
|
+
* restart it. What the user is looking at resolves first either way.
|
|
10740
|
+
*/
|
|
10741
|
+
function ByCameraDistance(params) {
|
|
10742
|
+
var _a;
|
|
10743
|
+
const { viewer, entities } = params;
|
|
10744
|
+
const bands = params.bands || [500, 2000, 10000, 50000];
|
|
10745
|
+
if (!(entities === null || entities === void 0 ? void 0 : entities.length)) {
|
|
10746
|
+
return [];
|
|
10747
|
+
}
|
|
10748
|
+
const cameraPos = (_a = viewer === null || viewer === void 0 ? void 0 : viewer.camera) === null || _a === void 0 ? void 0 : _a.position;
|
|
10749
|
+
if (!cameraPos) {
|
|
10750
|
+
return [entities];
|
|
10751
|
+
}
|
|
10752
|
+
// One band past the named bounds, for everything beyond the last of them.
|
|
10753
|
+
const banded = bands.map(() => []).concat([[]]);
|
|
10754
|
+
for (const entity of entities) {
|
|
10755
|
+
const pos = SafePos(entity, viewer);
|
|
10756
|
+
if (!pos) {
|
|
10757
|
+
banded[banded.length - 1].push(entity);
|
|
10758
|
+
continue;
|
|
10759
|
+
}
|
|
10760
|
+
const distance = Cesium.Cartesian3.distance(cameraPos, pos);
|
|
10761
|
+
let index = bands.findIndex(bound => distance <= bound);
|
|
10762
|
+
if (index < 0) {
|
|
10763
|
+
index = banded.length - 1;
|
|
10764
|
+
}
|
|
10765
|
+
banded[index].push(entity);
|
|
10766
|
+
}
|
|
10767
|
+
return banded.filter(band => band.length > 0);
|
|
10768
|
+
}
|
|
10769
|
+
HistoricFetchOrder.ByCameraDistance = ByCameraDistance;
|
|
10770
|
+
/*
|
|
10771
|
+
* Returns an Entity's world position, or null when it has none to place it by.
|
|
10772
|
+
*/
|
|
10773
|
+
function SafePos(entity, viewer) {
|
|
10774
|
+
try {
|
|
10775
|
+
const pos = exports.EntityUtils.GetPos({
|
|
10776
|
+
entity: entity,
|
|
10777
|
+
viewer: viewer,
|
|
10778
|
+
allowRendered: true
|
|
10779
|
+
});
|
|
10780
|
+
if (!pos || isNaN(pos.x) || isNaN(pos.y) || isNaN(pos.z)) {
|
|
10781
|
+
return null;
|
|
10782
|
+
}
|
|
10783
|
+
return pos;
|
|
10784
|
+
}
|
|
10785
|
+
catch {
|
|
10786
|
+
return null;
|
|
10787
|
+
}
|
|
10788
|
+
}
|
|
10789
|
+
})(HistoricFetchOrder || (HistoricFetchOrder = {}));
|
|
10790
|
+
/**
|
|
10791
|
+
* Decides what slice of history is worth fetching for the clock as it is currently moving.
|
|
10792
|
+
*/
|
|
10793
|
+
var HistoricFetchPlan;
|
|
10794
|
+
(function (HistoricFetchPlan) {
|
|
10795
|
+
// How many seconds of playback the detail window tries to stay ahead by.
|
|
10796
|
+
HistoricFetchPlan.DEFAULT_LEAD_SECONDS = 10;
|
|
10797
|
+
// The detail window never shrinks below this, so a paused clock still has something around it.
|
|
10798
|
+
HistoricFetchPlan.DEFAULT_MIN_DETAIL_MS = 60 * 1000;
|
|
10799
|
+
// Nor grows past it, which is what stops a fast scrub asking for the whole archive.
|
|
10800
|
+
HistoricFetchPlan.DEFAULT_MAX_DETAIL_MS = 6 * 60 * 60 * 1000;
|
|
10801
|
+
// Records the coarse pass may spend describing the whole range.
|
|
10802
|
+
HistoricFetchPlan.DEFAULT_SAMPLE = 200;
|
|
10803
|
+
/*
|
|
10804
|
+
* Returns how wide the detail window should be for the rate the clock is moving at.
|
|
10805
|
+
*/
|
|
10806
|
+
function DetailSpanFor(trajectory, leadSeconds, minMs, maxMs) {
|
|
10807
|
+
const rate = Math.abs((trajectory === null || trajectory === void 0 ? void 0 : trajectory.ratePerSecondMs) || 0);
|
|
10808
|
+
const span = rate * leadSeconds;
|
|
10809
|
+
if (!(span > minMs)) {
|
|
10810
|
+
return minMs;
|
|
10811
|
+
}
|
|
10812
|
+
return Math.min(span, maxMs);
|
|
10813
|
+
}
|
|
10814
|
+
HistoricFetchPlan.DetailSpanFor = DetailSpanFor;
|
|
10815
|
+
/**
|
|
10816
|
+
* Returns the detail window and the coarse pass for the clock as it stands.
|
|
10817
|
+
*/
|
|
10818
|
+
function Plan(params) {
|
|
10819
|
+
var _a;
|
|
10820
|
+
const { currentTime, windowStart, windowStop, trajectory, leadSeconds = HistoricFetchPlan.DEFAULT_LEAD_SECONDS, minDetailMs = HistoricFetchPlan.DEFAULT_MIN_DETAIL_MS, maxDetailMs = HistoricFetchPlan.DEFAULT_MAX_DETAIL_MS, sample = HistoricFetchPlan.DEFAULT_SAMPLE } = params;
|
|
10821
|
+
if (!(windowStop > windowStart)) {
|
|
10822
|
+
return { detail: null, coarse: null };
|
|
10823
|
+
}
|
|
10824
|
+
// A range that fits the detail budget has nothing worth sampling: reading it whole is both
|
|
10825
|
+
// cheaper than two requests and better than an approximation of it.
|
|
10826
|
+
if ((windowStop - windowStart) <= maxDetailMs) {
|
|
10827
|
+
return { detail: { start: windowStart, stop: windowStop }, coarse: null };
|
|
10828
|
+
}
|
|
10829
|
+
const span = DetailSpanFor(trajectory, leadSeconds, minDetailMs, maxDetailMs);
|
|
10830
|
+
const direction = (_a = trajectory === null || trajectory === void 0 ? void 0 : trajectory.direction) !== null && _a !== void 0 ? _a : 0;
|
|
10831
|
+
// Time running forward only ever reveals what is ahead, so the window leads rather than centres.
|
|
10832
|
+
// A little is still kept behind so a record just passed can still be interpolated from.
|
|
10833
|
+
const behind = direction === 0 ? span / 2 : span * 0.2;
|
|
10834
|
+
const ahead = direction === 0 ? span / 2 : span * 0.8;
|
|
10835
|
+
let start = direction < 0 ? currentTime - ahead : currentTime - behind;
|
|
10836
|
+
let stop = direction < 0 ? currentTime + behind : currentTime + ahead;
|
|
10837
|
+
start = Math.max(windowStart, start);
|
|
10838
|
+
stop = Math.min(windowStop, stop);
|
|
10839
|
+
if (!(stop > start)) {
|
|
10840
|
+
return { detail: null, coarse: { start: windowStart, stop: windowStop, sample } };
|
|
10841
|
+
}
|
|
10842
|
+
const detail = { start, stop };
|
|
10843
|
+
// Nothing to be coarse about once the detail window is the whole range.
|
|
10844
|
+
if (start <= windowStart && stop >= windowStop) {
|
|
10845
|
+
return { detail, coarse: null };
|
|
10846
|
+
}
|
|
10847
|
+
return { detail, coarse: { start: windowStart, stop: windowStop, sample } };
|
|
10848
|
+
}
|
|
10849
|
+
HistoricFetchPlan.Plan = Plan;
|
|
10850
|
+
/**
|
|
10851
|
+
* Tracks which way the clock is moving and how fast, from the times it is observed at.
|
|
10852
|
+
* Playback and a user dragging the timeline both look the same here, which is the point.
|
|
10853
|
+
*/
|
|
10854
|
+
class TrajectoryTracker {
|
|
10855
|
+
// Smooths the rate so one slow frame does not collapse the window.
|
|
10856
|
+
constructor(smoothing = 0.4) {
|
|
10857
|
+
this.smoothing = smoothing;
|
|
10858
|
+
this.lastTime = null;
|
|
10859
|
+
this.lastObservedAt = null;
|
|
10860
|
+
this.direction = 0;
|
|
10861
|
+
this.ratePerSecondMs = 0;
|
|
10862
|
+
}
|
|
10863
|
+
/**
|
|
10864
|
+
* Records where the clock is now. observedAt is the wall clock, in milliseconds.
|
|
10865
|
+
*/
|
|
10866
|
+
Observe(sceneTime, observedAt) {
|
|
10867
|
+
if (this.lastTime == null) {
|
|
10868
|
+
this.lastTime = sceneTime;
|
|
10869
|
+
this.lastObservedAt = observedAt;
|
|
10870
|
+
return;
|
|
10871
|
+
}
|
|
10872
|
+
const elapsed = observedAt - this.lastObservedAt;
|
|
10873
|
+
const moved = sceneTime - this.lastTime;
|
|
10874
|
+
this.lastTime = sceneTime;
|
|
10875
|
+
this.lastObservedAt = observedAt;
|
|
10876
|
+
if (!(elapsed > 0)) {
|
|
10877
|
+
return;
|
|
10878
|
+
}
|
|
10879
|
+
if (moved === 0) {
|
|
10880
|
+
this.direction = 0;
|
|
10881
|
+
this.ratePerSecondMs = 0;
|
|
10882
|
+
return;
|
|
10883
|
+
}
|
|
10884
|
+
this.direction = moved > 0 ? 1 : -1;
|
|
10885
|
+
const rate = Math.abs(moved) / (elapsed / 1000);
|
|
10886
|
+
this.ratePerSecondMs = this.ratePerSecondMs === 0
|
|
10887
|
+
? rate
|
|
10888
|
+
: (this.ratePerSecondMs * (1 - this.smoothing)) + (rate * this.smoothing);
|
|
10889
|
+
}
|
|
10890
|
+
Get() {
|
|
10891
|
+
return { direction: this.direction, ratePerSecondMs: this.ratePerSecondMs };
|
|
10892
|
+
}
|
|
10893
|
+
Reset() {
|
|
10894
|
+
this.lastTime = null;
|
|
10895
|
+
this.lastObservedAt = null;
|
|
10896
|
+
this.direction = 0;
|
|
10897
|
+
this.ratePerSecondMs = 0;
|
|
10898
|
+
}
|
|
10899
|
+
}
|
|
10900
|
+
HistoricFetchPlan.TrajectoryTracker = TrajectoryTracker;
|
|
10901
|
+
})(HistoricFetchPlan || (HistoricFetchPlan = {}));
|
|
10902
|
+
/**
|
|
10903
|
+
* Tracks which time ranges of historic data have already been requested, and the records they
|
|
10904
|
+
* returned, so moving the clock only fetches the part that is genuinely new.
|
|
10905
|
+
*
|
|
10906
|
+
* Coverage is tracked by the ranges that were asked for, not by the timestamps that came back. A
|
|
10907
|
+
* window holding no records is still covered, otherwise an empty stretch is re-requested forever.
|
|
10908
|
+
*/
|
|
10909
|
+
class HistoricRangeCache {
|
|
10910
|
+
// Ranges this far apart are treated as one, so a scrub does not leave a trail of slivers.
|
|
10911
|
+
constructor(mergeToleranceMs = 60000) {
|
|
10912
|
+
this.mergeToleranceMs = mergeToleranceMs;
|
|
10913
|
+
// Requested ranges, kept sorted and non-overlapping.
|
|
10914
|
+
this.held = [];
|
|
10915
|
+
// Ranges covered only by a sampled read, which describe their span without holding every record.
|
|
10916
|
+
this.heldCoarse = [];
|
|
10917
|
+
this.records = {};
|
|
10918
|
+
}
|
|
10919
|
+
/**
|
|
10920
|
+
* Returns the parts of the window that have not been requested yet.
|
|
10921
|
+
*/
|
|
10922
|
+
MissingRanges(start, stop) {
|
|
10923
|
+
if (!(stop > start)) {
|
|
10924
|
+
return [];
|
|
10925
|
+
}
|
|
10926
|
+
const missing = [];
|
|
10927
|
+
let cursor = start;
|
|
10928
|
+
for (const range of this.held) {
|
|
10929
|
+
if (range.stop <= cursor) {
|
|
10930
|
+
continue;
|
|
10931
|
+
}
|
|
10932
|
+
if (range.start >= stop) {
|
|
10933
|
+
break;
|
|
10934
|
+
}
|
|
10935
|
+
if (range.start > cursor) {
|
|
10936
|
+
missing.push({ start: cursor, stop: Math.min(range.start, stop) });
|
|
10937
|
+
}
|
|
10938
|
+
cursor = Math.max(cursor, range.stop);
|
|
10939
|
+
if (cursor >= stop) {
|
|
10940
|
+
break;
|
|
10941
|
+
}
|
|
10942
|
+
}
|
|
10943
|
+
if (cursor < stop) {
|
|
10944
|
+
missing.push({ start: cursor, stop: stop });
|
|
10945
|
+
}
|
|
10946
|
+
return this.mergeAdjacent(missing);
|
|
10947
|
+
}
|
|
10948
|
+
/**
|
|
10949
|
+
* Marks a range as requested and merges the records it returned into what is already held.
|
|
10950
|
+
*/
|
|
10951
|
+
Absorb(start, stop, recordsByIds, coarse = false) {
|
|
10952
|
+
if (stop > start) {
|
|
10953
|
+
if (coarse) {
|
|
10954
|
+
this.heldCoarse = this.mergeAdjacent([...this.heldCoarse, { start, stop }].sort((a, b) => a.start - b.start));
|
|
10955
|
+
}
|
|
10956
|
+
else {
|
|
10957
|
+
this.held = this.mergeAdjacent([...this.held, { start, stop }].sort((a, b) => a.start - b.start));
|
|
10958
|
+
}
|
|
10959
|
+
}
|
|
10960
|
+
if (!recordsByIds) {
|
|
10961
|
+
return;
|
|
10962
|
+
}
|
|
10963
|
+
for (const entityId of Object.keys(recordsByIds)) {
|
|
10964
|
+
const incoming = recordsByIds[entityId] || [];
|
|
10965
|
+
const current = this.records[entityId] || [];
|
|
10966
|
+
// Keyed by instant so a range fetched twice cannot double up its records.
|
|
10967
|
+
const byInstant = new Map();
|
|
10968
|
+
for (const record of current) {
|
|
10969
|
+
byInstant.set(new Date(record.dateTime).getTime(), record);
|
|
10970
|
+
}
|
|
10971
|
+
for (const record of incoming) {
|
|
10972
|
+
byInstant.set(new Date(record.dateTime).getTime(), record);
|
|
10973
|
+
}
|
|
10974
|
+
this.records[entityId] = Array.from(byInstant.values())
|
|
10975
|
+
.sort((a, b) => new Date(a.dateTime).getTime() - new Date(b.dateTime).getTime());
|
|
10976
|
+
}
|
|
10977
|
+
}
|
|
10978
|
+
GetRecords() {
|
|
10979
|
+
return this.records;
|
|
10980
|
+
}
|
|
10981
|
+
/**
|
|
10982
|
+
* Returns whether the window is already covered in full.
|
|
10983
|
+
*/
|
|
10984
|
+
Covers(start, stop) {
|
|
10985
|
+
return this.MissingRanges(start, stop).length === 0;
|
|
10986
|
+
}
|
|
10987
|
+
/**
|
|
10988
|
+
* Returns whether a sampled pass already describes the window.
|
|
10989
|
+
*/
|
|
10990
|
+
CoversCoarse(start, stop) {
|
|
10991
|
+
if (!(stop > start)) {
|
|
10992
|
+
return true;
|
|
10993
|
+
}
|
|
10994
|
+
return this.heldCoarse.some(range => range.start <= start && range.stop >= stop);
|
|
10995
|
+
}
|
|
10996
|
+
Clear() {
|
|
10997
|
+
this.held = [];
|
|
10998
|
+
this.heldCoarse = [];
|
|
10999
|
+
this.records = {};
|
|
11000
|
+
}
|
|
11001
|
+
mergeAdjacent(ranges) {
|
|
11002
|
+
if (ranges.length <= 1) {
|
|
11003
|
+
return ranges;
|
|
11004
|
+
}
|
|
11005
|
+
const sorted = [...ranges].sort((a, b) => a.start - b.start);
|
|
11006
|
+
const merged = [];
|
|
11007
|
+
let current = { ...sorted[0] };
|
|
11008
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
11009
|
+
const next = sorted[i];
|
|
11010
|
+
if (next.start - current.stop <= this.mergeToleranceMs) {
|
|
11011
|
+
current.stop = Math.max(current.stop, next.stop);
|
|
11012
|
+
}
|
|
11013
|
+
else {
|
|
11014
|
+
merged.push(current);
|
|
11015
|
+
current = { ...next };
|
|
11016
|
+
}
|
|
11017
|
+
}
|
|
11018
|
+
merged.push(current);
|
|
11019
|
+
return merged;
|
|
11020
|
+
}
|
|
11021
|
+
}
|
|
11022
|
+
/**
|
|
11023
|
+
* Pulls historic records for the visible clock range: what to ask for, in what order, and what has
|
|
11024
|
+
* already been asked for.
|
|
11025
|
+
*/
|
|
11026
|
+
class HistoricGatherer {
|
|
11027
|
+
constructor(params) {
|
|
11028
|
+
this.params = params;
|
|
11029
|
+
this.trajectory = new HistoricFetchPlan.TrajectoryTracker();
|
|
11030
|
+
// Range key to the request in flight for it, so the same range is never asked for twice at once.
|
|
11031
|
+
this.inFlight = new Map();
|
|
11032
|
+
this.disposed = false;
|
|
11033
|
+
this.cache = new HistoricRangeCache();
|
|
11034
|
+
}
|
|
11035
|
+
get Records() {
|
|
11036
|
+
return this.cache.GetRecords();
|
|
11037
|
+
}
|
|
11038
|
+
Clear() {
|
|
11039
|
+
this.cache.Clear();
|
|
11040
|
+
this.trajectory.Reset();
|
|
11041
|
+
this.inFlight.clear();
|
|
11042
|
+
}
|
|
11043
|
+
Dispose() {
|
|
11044
|
+
this.disposed = true;
|
|
11045
|
+
this.Clear();
|
|
11046
|
+
}
|
|
11047
|
+
/**
|
|
11048
|
+
* Returns how long to wait between refreshes for a set of this size.
|
|
11049
|
+
*/
|
|
11050
|
+
IntervalFor(entityCount) {
|
|
11051
|
+
return HistoricFetchOrder.IntervalFor(entityCount);
|
|
11052
|
+
}
|
|
11053
|
+
/**
|
|
11054
|
+
* Fetches whatever the current clock range needs that is not already held.
|
|
11055
|
+
* Returns whether anything was requested, alongside every record held for these Entities.
|
|
11056
|
+
*/
|
|
11057
|
+
async Gather(entities) {
|
|
11058
|
+
var _a;
|
|
11059
|
+
if (this.disposed || !(entities === null || entities === void 0 ? void 0 : entities.length)) {
|
|
11060
|
+
return { fetched: false, recordsByIds: this.cache.GetRecords() };
|
|
11061
|
+
}
|
|
11062
|
+
const { viewer } = this.params;
|
|
11063
|
+
const windowStart = new Date(viewer.clock.startTime.toString()).getTime();
|
|
11064
|
+
const windowStop = new Date(viewer.clock.stopTime.toString()).getTime();
|
|
11065
|
+
const currentTime = new Date(viewer.clock.currentTime.toString()).getTime();
|
|
11066
|
+
this.trajectory.Observe(currentTime, Date.now());
|
|
11067
|
+
const liveEdge = exports.ViewUtils.GetTimeDetails({ viewer }).isLive ? currentTime : null;
|
|
11068
|
+
const liveTail = (_a = this.params.liveTailMs) !== null && _a !== void 0 ? _a : HistoricGatherer.LIVE_TAIL_MS;
|
|
11069
|
+
const plan = HistoricFetchPlan.Plan({
|
|
11070
|
+
currentTime,
|
|
11071
|
+
windowStart,
|
|
11072
|
+
windowStop,
|
|
11073
|
+
trajectory: this.trajectory.Get(),
|
|
11074
|
+
sample: this.params.sample
|
|
11075
|
+
});
|
|
11076
|
+
let fetched = false;
|
|
11077
|
+
if (plan.coarse && !this.cache.CoversCoarse(plan.coarse.start, plan.coarse.stop)) {
|
|
11078
|
+
const records = await this.request(plan.coarse.start, plan.coarse.stop, entities, plan.coarse.sample);
|
|
11079
|
+
if (this.disposed) {
|
|
11080
|
+
return { fetched, recordsByIds: this.cache.GetRecords() };
|
|
11081
|
+
}
|
|
11082
|
+
this.cache.Absorb(plan.coarse.start, this.holdTo(plan.coarse.stop, liveEdge, liveTail), records, true);
|
|
11083
|
+
fetched = true;
|
|
11084
|
+
}
|
|
11085
|
+
if (plan.detail) {
|
|
11086
|
+
const bands = entities.length > HistoricFetchOrder.SMALL_SET
|
|
11087
|
+
? HistoricFetchOrder.ByCameraDistance({ viewer, entities })
|
|
11088
|
+
: [entities];
|
|
11089
|
+
for (const range of this.cache.MissingRanges(plan.detail.start, plan.detail.stop)) {
|
|
11090
|
+
if (this.disposed) {
|
|
11091
|
+
break;
|
|
11092
|
+
}
|
|
11093
|
+
for (const band of bands) {
|
|
11094
|
+
if (this.disposed) {
|
|
11095
|
+
break;
|
|
11096
|
+
}
|
|
11097
|
+
const records = await this.request(range.start, range.stop, band, 0);
|
|
11098
|
+
if (this.disposed) {
|
|
11099
|
+
break;
|
|
11100
|
+
}
|
|
11101
|
+
// Records land as each band arrives, while the range is only marked held once
|
|
11102
|
+
// every band has been asked for.
|
|
11103
|
+
this.cache.Absorb(0, 0, records);
|
|
11104
|
+
fetched = true;
|
|
11105
|
+
}
|
|
11106
|
+
if (this.disposed) {
|
|
11107
|
+
break;
|
|
11108
|
+
}
|
|
11109
|
+
const heldTo = this.holdTo(range.stop, liveEdge, liveTail);
|
|
11110
|
+
if (heldTo > range.start) {
|
|
11111
|
+
this.cache.Absorb(range.start, heldTo, {});
|
|
11112
|
+
}
|
|
11113
|
+
}
|
|
11114
|
+
}
|
|
11115
|
+
return { fetched, recordsByIds: this.cache.GetRecords() };
|
|
11116
|
+
}
|
|
11117
|
+
/*
|
|
11118
|
+
* Returns how much of a range that was just read may be marked as held.
|
|
11119
|
+
*/
|
|
11120
|
+
holdTo(stop, liveEdge, liveTailMs) {
|
|
11121
|
+
if (liveEdge == null) {
|
|
11122
|
+
return stop;
|
|
11123
|
+
}
|
|
11124
|
+
return Math.min(stop, liveEdge - liveTailMs);
|
|
11125
|
+
}
|
|
11126
|
+
/*
|
|
11127
|
+
* Reads one range, joining a request already in flight for it rather than repeating it.
|
|
11128
|
+
*/
|
|
11129
|
+
request(start, stop, entities, sample) {
|
|
11130
|
+
var _a;
|
|
11131
|
+
const padding = (_a = this.params.paddingMs) !== null && _a !== void 0 ? _a : 0;
|
|
11132
|
+
const dateTimeFrom = new Date(start - padding).toISOString();
|
|
11133
|
+
const dateTimeTo = new Date(stop + padding).toISOString();
|
|
11134
|
+
const entityIds = entities.map(x => { var _a; return (_a = x.Bruce) === null || _a === void 0 ? void 0 : _a.ID; }).filter(x => !!x);
|
|
11135
|
+
const key = `${dateTimeFrom}|${dateTimeTo}|${sample}|${entityIds.join(",")}`;
|
|
11136
|
+
const existing = this.inFlight.get(key);
|
|
11137
|
+
if (existing) {
|
|
11138
|
+
return existing;
|
|
11139
|
+
}
|
|
11140
|
+
const prom = BModels.EntityHistoricData.GetRecordsByEntity({
|
|
11141
|
+
attrKey: this.params.getAttrKey(),
|
|
11142
|
+
dateTimeFrom,
|
|
11143
|
+
dateTimeTo,
|
|
11144
|
+
entityIds,
|
|
11145
|
+
sample: sample > 0 ? sample : undefined,
|
|
11146
|
+
api: this.params.getApi()
|
|
11147
|
+
}).then((res) => {
|
|
11148
|
+
const records = res.recordsByIds || {};
|
|
11149
|
+
if (!this.disposed && this.params.onRecords) {
|
|
11150
|
+
this.params.onRecords(records);
|
|
11151
|
+
}
|
|
11152
|
+
return records;
|
|
11153
|
+
}).finally(() => {
|
|
11154
|
+
this.inFlight.delete(key);
|
|
11155
|
+
});
|
|
11156
|
+
this.inFlight.set(key, prom);
|
|
11157
|
+
return prom;
|
|
11158
|
+
}
|
|
11159
|
+
}
|
|
11160
|
+
// How far back from the live edge is left unheld, so a record written moments ago still falls in
|
|
11161
|
+
// something that gets asked for again. It has to outlast a write, a commit and a refresh, plus
|
|
11162
|
+
// whatever the writer's clock and this one disagree by.
|
|
11163
|
+
HistoricGatherer.LIVE_TAIL_MS = 15000;
|
|
11164
|
+
|
|
10618
11165
|
const BATCH_SIZE = 500;
|
|
10619
11166
|
const CHECK_BATCH_SIZE = 250;
|
|
10620
11167
|
function getValue$2(viewer, obj) {
|
|
@@ -10699,6 +11246,13 @@
|
|
|
10699
11246
|
this.item = item;
|
|
10700
11247
|
this.visualsManager = visualsManager;
|
|
10701
11248
|
this.onSeriesDiscovered = onSeriesDiscovered;
|
|
11249
|
+
this.historicGatherer = new HistoricGatherer({
|
|
11250
|
+
viewer: this.viewer,
|
|
11251
|
+
getApi: () => this.apiGetter.getApi(),
|
|
11252
|
+
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
11253
|
+
// A second either side, to take in records sitting exactly on the boundary.
|
|
11254
|
+
paddingMs: 1000
|
|
11255
|
+
});
|
|
10702
11256
|
this.useGeojson = item.renderAsGeojson == true;
|
|
10703
11257
|
if (item.enableClustering) {
|
|
10704
11258
|
this.clustering = new PointClustering(this.visualsManager, this.item.id);
|
|
@@ -11662,6 +12216,13 @@
|
|
|
11662
12216
|
this.renderAsIndividualsChain = next;
|
|
11663
12217
|
return next;
|
|
11664
12218
|
}
|
|
12219
|
+
/**
|
|
12220
|
+
* Returns the historic records to interpolate between, fetching only what is not already held.
|
|
12221
|
+
*/
|
|
12222
|
+
async gatherHistoric(entities) {
|
|
12223
|
+
const { recordsByIds } = await this.historicGatherer.Gather(entities);
|
|
12224
|
+
return recordsByIds;
|
|
12225
|
+
}
|
|
11665
12226
|
async doRenderAsIndividuals(entities, force = false) {
|
|
11666
12227
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
11667
12228
|
// When live we just want to show the latest pos.
|
|
@@ -11676,19 +12237,7 @@
|
|
|
11676
12237
|
const isHistoric = ((_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historic) || ((_b = this.item.BruceEntity) === null || _b === void 0 ? void 0 : _b.historicAttrKey);
|
|
11677
12238
|
// If we're interpolating then we request additional records to quickly swap between.
|
|
11678
12239
|
if (!isLive && isHistoric && entities.length && this.item.historicInterpolation) {
|
|
11679
|
-
|
|
11680
|
-
const startTmp = Cesium.JulianDate.toDate(this.viewer.clock.startTime);
|
|
11681
|
-
const stopTmp = Cesium.JulianDate.toDate(this.viewer.clock.stopTime);
|
|
11682
|
-
const startStr = new Date(startTmp.getTime() - 1000).toISOString();
|
|
11683
|
-
const stopStr = new Date(stopTmp.getTime() + 1000).toISOString();
|
|
11684
|
-
const historicData = await BModels.EntityHistoricData.GetList({
|
|
11685
|
-
attrKey: this.item.BruceEntity.historicAttrKey,
|
|
11686
|
-
dateTimeFrom: startStr,
|
|
11687
|
-
dateTimeTo: stopStr,
|
|
11688
|
-
entityIds: entities.map(x => x.Bruce.ID),
|
|
11689
|
-
api: this.apiGetter.getApi()
|
|
11690
|
-
});
|
|
11691
|
-
entitiesHistoric = historicData.recordsByIds;
|
|
12240
|
+
entitiesHistoric = await this.gatherHistoric(entities);
|
|
11692
12241
|
}
|
|
11693
12242
|
if (this.disposed) {
|
|
11694
12243
|
this.doDispose();
|
|
@@ -12802,6 +13351,13 @@
|
|
|
12802
13351
|
this.monitor = monitor;
|
|
12803
13352
|
this.item = item;
|
|
12804
13353
|
this.visualsManager = visualsManager;
|
|
13354
|
+
this.historicGatherer = new HistoricGatherer({
|
|
13355
|
+
viewer: this.viewer,
|
|
13356
|
+
getApi: () => this.apiGetter.getApi(),
|
|
13357
|
+
getAttrKey: () => { var _a; return (_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historicAttrKey; },
|
|
13358
|
+
// Padding either side of a requested range, for clock desync between us and the server.
|
|
13359
|
+
paddingMs: 15000
|
|
13360
|
+
});
|
|
12805
13361
|
if (this.item.enableClustering) {
|
|
12806
13362
|
this.clustering = new PointClustering(visualsManager, this.item.id, (_a = this.item) === null || _a === void 0 ? void 0 : _a.clustering);
|
|
12807
13363
|
}
|
|
@@ -13151,138 +13707,22 @@
|
|
|
13151
13707
|
* @param entities
|
|
13152
13708
|
*/
|
|
13153
13709
|
async getHistoricInfo(entities) {
|
|
13154
|
-
|
|
13155
|
-
// Helps account for desync between client and server.
|
|
13156
|
-
const TIME_PADDING_MS = 15000;
|
|
13157
|
-
const minDateTimeStr = this.viewer.clock.startTime.toString();
|
|
13158
|
-
const maxDateTimeStr = this.viewer.clock.stopTime.toString();
|
|
13159
|
-
const minDateTime = new Date(minDateTimeStr).getTime();
|
|
13160
|
-
const maxDateTime = new Date(maxDateTimeStr).getTime();
|
|
13161
|
-
const tDetails = exports.ViewUtils.GetTimeDetails({
|
|
13162
|
-
viewer: this.viewer,
|
|
13163
|
-
});
|
|
13164
|
-
const isLive = tDetails.isLive;
|
|
13165
|
-
let rangesToRequest = [{
|
|
13166
|
-
start: minDateTime,
|
|
13167
|
-
stop: maxDateTime
|
|
13168
|
-
}];
|
|
13169
|
-
// If we already have cached data, determine what ranges we're missing.
|
|
13170
|
-
if (Object.keys(this.entitiesHistoric).length >= entities.length) {
|
|
13171
|
-
let foundMinDateTime = null;
|
|
13172
|
-
let foundMaxDateTime = null;
|
|
13173
|
-
// Find the min/max based on cached data.
|
|
13174
|
-
// Since we set the values sorted, we only have to check the first and last records for each entity.
|
|
13175
|
-
for (const entityId of Object.keys(this.entitiesHistoric)) {
|
|
13176
|
-
const records = this.entitiesHistoric[entityId] || [];
|
|
13177
|
-
if (records.length) {
|
|
13178
|
-
const dateTime = new Date(records[0].dateTime).getTime();
|
|
13179
|
-
if (foundMinDateTime == null || dateTime < foundMinDateTime) {
|
|
13180
|
-
foundMinDateTime = dateTime;
|
|
13181
|
-
}
|
|
13182
|
-
const dateTime2 = new Date(records[records.length - 1].dateTime).getTime();
|
|
13183
|
-
if (foundMaxDateTime == null || dateTime2 > foundMaxDateTime) {
|
|
13184
|
-
foundMaxDateTime = dateTime2;
|
|
13185
|
-
}
|
|
13186
|
-
}
|
|
13187
|
-
}
|
|
13188
|
-
// Complete overlap - we already have all the data.
|
|
13189
|
-
if (foundMinDateTime != null && foundMaxDateTime != null && foundMinDateTime <= minDateTime && foundMaxDateTime >= maxDateTime) {
|
|
13190
|
-
return [false, this.entitiesHistoric];
|
|
13191
|
-
}
|
|
13192
|
-
// Calculate missing ranges.
|
|
13193
|
-
rangesToRequest = [];
|
|
13194
|
-
// Check if we need data before our cached range.
|
|
13195
|
-
if (foundMinDateTime != null && foundMinDateTime > minDateTime) {
|
|
13196
|
-
// When live we focus on getting the next range rather than old data.
|
|
13197
|
-
// Ends up being one less request to perform every second.
|
|
13198
|
-
if (!isLive || foundMinDateTime == null) {
|
|
13199
|
-
rangesToRequest.push({
|
|
13200
|
-
start: minDateTime,
|
|
13201
|
-
stop: new Date(foundMinDateTime).getTime()
|
|
13202
|
-
});
|
|
13203
|
-
}
|
|
13204
|
-
}
|
|
13205
|
-
// Check if we need data after our cached range.
|
|
13206
|
-
if (foundMaxDateTime != null && foundMaxDateTime < maxDateTime) {
|
|
13207
|
-
rangesToRequest.push({
|
|
13208
|
-
start: new Date(foundMaxDateTime).getTime(),
|
|
13209
|
-
stop: maxDateTime
|
|
13210
|
-
});
|
|
13211
|
-
}
|
|
13212
|
-
// If the ranges to request are within a tolerance, combine them.
|
|
13213
|
-
if (rangesToRequest.length > 1) {
|
|
13214
|
-
const TOLERANCE_MS = 60000; // 1 minute.
|
|
13215
|
-
let currentRange = rangesToRequest[0];
|
|
13216
|
-
for (let i = 1; i < rangesToRequest.length; i++) {
|
|
13217
|
-
const nextRange = rangesToRequest[i];
|
|
13218
|
-
if (nextRange.start - currentRange.stop <= TOLERANCE_MS) {
|
|
13219
|
-
currentRange.stop = nextRange.stop;
|
|
13220
|
-
}
|
|
13221
|
-
else {
|
|
13222
|
-
currentRange = nextRange;
|
|
13223
|
-
}
|
|
13224
|
-
}
|
|
13225
|
-
}
|
|
13226
|
-
}
|
|
13227
|
-
const entityIds = entities.map(x => x.Bruce.ID);
|
|
13228
|
-
const combined = { ...this.entitiesHistoric };
|
|
13229
|
-
// Make requests for each missing range
|
|
13230
|
-
for (const range of rangesToRequest) {
|
|
13231
|
-
if (this.disposed) {
|
|
13232
|
-
break;
|
|
13233
|
-
}
|
|
13234
|
-
const start = new Date(range.start - TIME_PADDING_MS);
|
|
13235
|
-
const stop = new Date(range.stop + TIME_PADDING_MS);
|
|
13236
|
-
const historicData = await BModels.EntityHistoricData.GetList({
|
|
13237
|
-
attrKey: this.item.BruceEntity.historicAttrKey,
|
|
13238
|
-
dateTimeFrom: start.toISOString(),
|
|
13239
|
-
dateTimeTo: stop.toISOString(),
|
|
13240
|
-
entityIds: entityIds,
|
|
13241
|
-
api: this.apiGetter.getApi()
|
|
13242
|
-
});
|
|
13243
|
-
if (this.disposed) {
|
|
13244
|
-
break;
|
|
13245
|
-
}
|
|
13246
|
-
// Merge the new data with existing data
|
|
13247
|
-
const records = historicData.recordsByIds;
|
|
13248
|
-
const recordsIds = Object.keys(records);
|
|
13249
|
-
for (let i = 0; i < recordsIds.length; i++) {
|
|
13250
|
-
const entityId = recordsIds[i];
|
|
13251
|
-
const latest = records[entityId] || [];
|
|
13252
|
-
const current = combined[entityId] || [];
|
|
13253
|
-
// Use a Map to de-duplicate by timestamp.
|
|
13254
|
-
const tmp = new Map();
|
|
13255
|
-
for (let j = 0; j < current.length; j++) {
|
|
13256
|
-
const record = current[j];
|
|
13257
|
-
const dateTime = new Date(record.dateTime).getTime();
|
|
13258
|
-
tmp.set(dateTime, record);
|
|
13259
|
-
}
|
|
13260
|
-
for (let j = 0; j < latest.length; j++) {
|
|
13261
|
-
const record = latest[j];
|
|
13262
|
-
const dateTime = new Date(record.dateTime).getTime();
|
|
13263
|
-
tmp.set(dateTime, record);
|
|
13264
|
-
}
|
|
13265
|
-
// Convert to array and sort by date.
|
|
13266
|
-
const sorted = Array.from(tmp.values()).sort((a, b) => {
|
|
13267
|
-
return new Date(a.dateTime).getTime() - new Date(b.dateTime).getTime();
|
|
13268
|
-
});
|
|
13269
|
-
combined[entityId] = sorted;
|
|
13270
|
-
}
|
|
13271
|
-
}
|
|
13710
|
+
const { fetched, recordsByIds } = await this.historicGatherer.Gather(entities);
|
|
13272
13711
|
if (!this.disposed) {
|
|
13273
|
-
this.entitiesHistoric =
|
|
13712
|
+
this.entitiesHistoric = recordsByIds;
|
|
13274
13713
|
}
|
|
13275
|
-
return [
|
|
13714
|
+
return [fetched, recordsByIds];
|
|
13276
13715
|
}
|
|
13277
13716
|
viewerDateTimeSub() {
|
|
13278
13717
|
var _a, _b;
|
|
13279
13718
|
if ((!((_a = this.item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historic) && !((_b = this.item.BruceEntity) === null || _b === void 0 ? void 0 : _b.historicAttrKey)) || this.viewerDateTimeChangeRemoval) {
|
|
13280
13719
|
return;
|
|
13281
13720
|
}
|
|
13282
|
-
|
|
13721
|
+
// Scaled by how many Entities are on screen rather than fixed, since the cost of a refresh
|
|
13722
|
+
// is the set size and a large set barely changes between ticks anyway.
|
|
13283
13723
|
let queue = new BModels.DelayQueue(() => {
|
|
13284
13724
|
this.onGetterUpdate(Object.keys(this.renderedEntities));
|
|
13285
|
-
},
|
|
13725
|
+
}, this.historicGatherer.IntervalFor(Object.keys(this.renderedEntities).length), true);
|
|
13286
13726
|
let clockTickRemoval;
|
|
13287
13727
|
let prevTick = this.viewer.clock.currentTime.toString();
|
|
13288
13728
|
clockTickRemoval = this.viewer.clock.onTick.addEventListener(() => {
|
|
@@ -13970,6 +14410,9 @@
|
|
|
13970
14410
|
// Indicates that we are retrieving historic records.
|
|
13971
14411
|
// This means that the current scene's time is included in the request.
|
|
13972
14412
|
this.historic = false;
|
|
14413
|
+
// When false the Entity data is still gathered and the regos still updated, but no colour is
|
|
14414
|
+
// applied. A historic item that did not ask for styling needs the first without the second.
|
|
14415
|
+
this.applyStyles = true;
|
|
13973
14416
|
this.reRenderState = new EntityReRenderMaintainState();
|
|
13974
14417
|
// More expensive process.
|
|
13975
14418
|
// When an Entity is styled, the rego is reviewed and updated if needed.
|
|
@@ -14006,13 +14449,16 @@
|
|
|
14006
14449
|
}
|
|
14007
14450
|
Init(params) {
|
|
14008
14451
|
var _a, _b;
|
|
14009
|
-
let { viewer, api, cTileset, fallbackStyleId, styleMapping, expandSources, menuItemId, register, scenario, historic } = params;
|
|
14452
|
+
let { viewer, api, cTileset, fallbackStyleId, styleMapping, expandSources, menuItemId, register, scenario, historic, applyStyles } = params;
|
|
14010
14453
|
this.viewer = viewer;
|
|
14011
14454
|
this.api = api;
|
|
14012
14455
|
this.cTileset = cTileset;
|
|
14013
14456
|
this.register = register;
|
|
14014
14457
|
this.menuItemId = menuItemId;
|
|
14015
14458
|
this.historic = Boolean(historic);
|
|
14459
|
+
if (applyStyles != null) {
|
|
14460
|
+
this.applyStyles = Boolean(applyStyles);
|
|
14461
|
+
}
|
|
14016
14462
|
if (expandSources != null) {
|
|
14017
14463
|
this.expandSources = expandSources;
|
|
14018
14464
|
}
|
|
@@ -14506,33 +14952,31 @@
|
|
|
14506
14952
|
return;
|
|
14507
14953
|
}
|
|
14508
14954
|
const { settings: style, styleId: resolvedStyleId } = this.getTilesetFeatureStyleWithId(rego.entityTypeId);
|
|
14509
|
-
const fillColorTrace = (style && ((_a = style.modelStyle) === null || _a === void 0 ? void 0 : _a.fillColor)) ? BModels.Calculator.TraceGetColor(style.modelStyle.fillColor, data, tags) : { value: null, effective: null };
|
|
14510
|
-
|
|
14511
|
-
|
|
14512
|
-
if (bColor == null) {
|
|
14513
|
-
cColor = Cesium.Color.WHITE;
|
|
14514
|
-
}
|
|
14515
|
-
else {
|
|
14516
|
-
cColor = colorToCColor$3(bColor);
|
|
14517
|
-
}
|
|
14955
|
+
const fillColorTrace = (this.applyStyles && style && ((_a = style.modelStyle) === null || _a === void 0 ? void 0 : _a.fillColor)) ? BModels.Calculator.TraceGetColor(style.modelStyle.fillColor, data, tags) : { value: null, effective: null };
|
|
14956
|
+
// Without styling the feature keeps whatever the tileset baked in. Falling through would paint
|
|
14957
|
+
// it the default white, which is a visible change for an item that only asked for historic.
|
|
14518
14958
|
const override = this.overrideFeatureColor.get(rego.entityId) == true;
|
|
14519
|
-
|
|
14520
|
-
|
|
14521
|
-
|
|
14522
|
-
|
|
14523
|
-
|
|
14524
|
-
|
|
14525
|
-
|
|
14526
|
-
|
|
14959
|
+
if (this.applyStyles) {
|
|
14960
|
+
const bColor = fillColorTrace.value;
|
|
14961
|
+
const cColor = bColor == null ? Cesium.Color.WHITE : colorToCColor$3(bColor);
|
|
14962
|
+
exports.CesiumEntityStyler.SetDefaultColor({
|
|
14963
|
+
color: cColor,
|
|
14964
|
+
entity: visual,
|
|
14965
|
+
viewer: this.viewer,
|
|
14966
|
+
override: override
|
|
14967
|
+
});
|
|
14968
|
+
this.overrideFeatureColor.set(rego.entityId, true);
|
|
14969
|
+
if (resolvedStyleId != null) {
|
|
14970
|
+
rego.styleId = resolvedStyleId;
|
|
14971
|
+
}
|
|
14972
|
+
rego.styleEffective = (_b = exports.StyleEffective.Combine([
|
|
14973
|
+
{ key: "color", effective: fillColorTrace.effective }
|
|
14974
|
+
])) !== null && _b !== void 0 ? _b : rego.styleEffective;
|
|
14975
|
+
}
|
|
14976
|
+
if (((_c = data === null || data === void 0 ? void 0 : data.Bruce) === null || _c === void 0 ? void 0 : _c.InternalID) != null) {
|
|
14527
14977
|
rego.internalId = data.Bruce.InternalID;
|
|
14528
14978
|
this.styledByInternalId.set(data.Bruce.InternalID, rego.entityId);
|
|
14529
14979
|
}
|
|
14530
|
-
if (resolvedStyleId != null) {
|
|
14531
|
-
rego.styleId = resolvedStyleId;
|
|
14532
|
-
}
|
|
14533
|
-
rego.styleEffective = (_c = exports.StyleEffective.Combine([
|
|
14534
|
-
{ key: "color", effective: fillColorTrace.effective }
|
|
14535
|
-
])) !== null && _c !== void 0 ? _c : rego.styleEffective;
|
|
14536
14980
|
this.styledEntityIds.set(rego.entityId, true);
|
|
14537
14981
|
this._styleProgressQueue.Call();
|
|
14538
14982
|
// Since we only need to update it for scenarios right now.
|
|
@@ -14690,8 +15134,8 @@
|
|
|
14690
15134
|
const defaultProps = {
|
|
14691
15135
|
// "Optimization option. Reduce the screen space error for tiles that are further away from the camera.".
|
|
14692
15136
|
dynamicScreenSpaceError: true,
|
|
14693
|
-
environmentMapOptions: exports.ViewUtils.DefaultEnvironmentMapOptions()
|
|
14694
15137
|
};
|
|
15138
|
+
Object.assign(defaultProps, exports.ViewUtils.DefaultLightingProps());
|
|
14695
15139
|
if (noMemoryLimit != true) {
|
|
14696
15140
|
// "The maximum amount of memory in MB that can be used by the tileset.".
|
|
14697
15141
|
defaultProps.maximumMemoryUsage = 512;
|
|
@@ -15497,6 +15941,7 @@
|
|
|
15497
15941
|
// Series of points to help interpolate movement when the timeline changes.
|
|
15498
15942
|
this.historicPossesInitialLoaded = false;
|
|
15499
15943
|
this.historicAnimation = null;
|
|
15944
|
+
this.historicGatherer = null;
|
|
15500
15945
|
this.historicPossesLoadingProm = null;
|
|
15501
15946
|
// Queue of loaded in features that we haven't processed yet.
|
|
15502
15947
|
this.featureQueue = [];
|
|
@@ -16534,120 +16979,41 @@
|
|
|
16534
16979
|
const api = this.getters.GetBruceApi({
|
|
16535
16980
|
accountId: accountId
|
|
16536
16981
|
});
|
|
16537
|
-
//
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
// Helps us avoid repeated requests that are the same.
|
|
16542
|
-
const pendingRequests = new Map();
|
|
16543
|
-
/**
|
|
16544
|
-
* Returns a list of historic positions for a given time range.
|
|
16545
|
-
* @param startStr
|
|
16546
|
-
* @param stopStr
|
|
16547
|
-
* @returns
|
|
16982
|
+
// The root Entity is the only one here, so nothing is banded and the plan sees a set of one.
|
|
16983
|
+
const rootEntity = { Bruce: { ID: this.rootId } };
|
|
16984
|
+
/*
|
|
16985
|
+
* Turns historic records into the animated positions this tileset moves along.
|
|
16548
16986
|
*/
|
|
16549
|
-
const
|
|
16550
|
-
|
|
16551
|
-
if (pendingRequests.has(requestKey)) {
|
|
16552
|
-
return pendingRequests.get(requestKey);
|
|
16553
|
-
}
|
|
16554
|
-
const requestPromise = new Promise(async (res) => {
|
|
16555
|
-
try {
|
|
16556
|
-
const historicData = await BModels.EntityHistoricData.GetList({
|
|
16557
|
-
attrKey: null,
|
|
16558
|
-
dateTimeFrom: startStr,
|
|
16559
|
-
dateTimeTo: stopStr,
|
|
16560
|
-
entityIds: [this.rootId],
|
|
16561
|
-
api: api
|
|
16562
|
-
});
|
|
16563
|
-
const posses = exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(this.viewer, Cesium.HeightReference.NONE, Cesium.HeightReference.CLAMP_TO_GROUND, historicData.recordsByIds[this.rootId]);
|
|
16564
|
-
res(posses);
|
|
16565
|
-
}
|
|
16566
|
-
catch (e) {
|
|
16567
|
-
console.error(e);
|
|
16568
|
-
res([]);
|
|
16569
|
-
}
|
|
16570
|
-
finally {
|
|
16571
|
-
pendingRequests.delete(requestKey);
|
|
16572
|
-
}
|
|
16573
|
-
});
|
|
16574
|
-
pendingRequests.set(requestKey, requestPromise);
|
|
16575
|
-
return requestPromise;
|
|
16987
|
+
const toPosses = (records) => {
|
|
16988
|
+
return exports.CesiumAnimatedProperty.GetSeriesPossesForHistoricEntity(this.viewer, Cesium.HeightReference.NONE, Cesium.HeightReference.CLAMP_TO_GROUND, records);
|
|
16576
16989
|
};
|
|
16990
|
+
this.historicGatherer = new HistoricGatherer({
|
|
16991
|
+
viewer: this.viewer,
|
|
16992
|
+
getApi: () => api,
|
|
16993
|
+
// The assembly root snapshots the whole Entity, so no key narrows it.
|
|
16994
|
+
getAttrKey: () => null,
|
|
16995
|
+
// Time padding in milliseconds (15 seconds).
|
|
16996
|
+
// Helps account for desync between client and server.
|
|
16997
|
+
paddingMs: 15000,
|
|
16998
|
+
onRecords: (recordsByIds) => {
|
|
16999
|
+
var _a;
|
|
17000
|
+
const records = recordsByIds[this.rootId];
|
|
17001
|
+
if (!(records === null || records === void 0 ? void 0 : records.length) || !((_a = this.historicAnimation) === null || _a === void 0 ? void 0 : _a.addPositions)) {
|
|
17002
|
+
return;
|
|
17003
|
+
}
|
|
17004
|
+
this.historicAnimation.addPositions(toPosses(records));
|
|
17005
|
+
}
|
|
17006
|
+
});
|
|
16577
17007
|
/**
|
|
16578
|
-
*
|
|
16579
|
-
*
|
|
17008
|
+
* Fetches whatever the current timeline range needs that is not already held.
|
|
17009
|
+
* Positions reach the animation through the gatherer's callback as each batch lands.
|
|
16580
17010
|
* @returns
|
|
16581
17011
|
*/
|
|
16582
17012
|
const checkTimelineRange = async () => {
|
|
16583
|
-
|
|
16584
|
-
const minDateTime = new Date(this.viewer.clock.startTime.toString()).getTime();
|
|
16585
|
-
const maxDateTime = new Date(this.viewer.clock.stopTime.toString()).getTime();
|
|
16586
|
-
// What we have loaded.
|
|
16587
|
-
const range = this.historicAnimation.getDateRange();
|
|
16588
|
-
const foundMinDateTime = (range === null || range === void 0 ? void 0 : range.minDate) ? range.minDate.getTime() : null;
|
|
16589
|
-
const foundMaxDateTime = (range === null || range === void 0 ? void 0 : range.maxDate) ? range.maxDate.getTime() : null;
|
|
16590
|
-
// See if the current range is within the range we already have.
|
|
16591
|
-
if (this.historicPossesInitialLoaded &&
|
|
16592
|
-
foundMinDateTime &&
|
|
16593
|
-
foundMaxDateTime &&
|
|
16594
|
-
minDateTime >= foundMinDateTime &&
|
|
16595
|
-
maxDateTime <= foundMaxDateTime) {
|
|
16596
|
-
return;
|
|
16597
|
-
}
|
|
16598
|
-
const tDetails = exports.ViewUtils.GetTimeDetails({
|
|
16599
|
-
viewer: this.viewer,
|
|
16600
|
-
});
|
|
16601
|
-
const isLive = tDetails.isLive;
|
|
16602
|
-
// See if the requested range is before or after the range we have.
|
|
16603
|
-
const fetchBefore = !foundMinDateTime || (!isLive && minDateTime < foundMinDateTime);
|
|
16604
|
-
const fetchAfter = !foundMaxDateTime || maxDateTime > foundMaxDateTime;
|
|
16605
|
-
if (!fetchBefore && !fetchAfter) {
|
|
16606
|
-
// Already have the data we need.
|
|
17013
|
+
if (this.disposed) {
|
|
16607
17014
|
return;
|
|
16608
17015
|
}
|
|
16609
|
-
|
|
16610
|
-
if (!foundMinDateTime || !foundMaxDateTime) {
|
|
16611
|
-
const startStr = new Date(minDateTime - TIME_PADDING_MS).toISOString();
|
|
16612
|
-
const stopStr = new Date(maxDateTime + TIME_PADDING_MS).toISOString();
|
|
16613
|
-
const newPositions = await getPossesForRange(startStr, stopStr);
|
|
16614
|
-
if (this.disposed) {
|
|
16615
|
-
return;
|
|
16616
|
-
}
|
|
16617
|
-
if (this.historicAnimation && this.historicAnimation.addPositions) {
|
|
16618
|
-
this.historicAnimation.addPositions(newPositions);
|
|
16619
|
-
}
|
|
16620
|
-
}
|
|
16621
|
-
else {
|
|
16622
|
-
// The data we want is before the range we've currently loaded.
|
|
16623
|
-
if (fetchBefore) {
|
|
16624
|
-
// Calculate the missing difference and request it.
|
|
16625
|
-
const startStr = new Date(minDateTime - TIME_PADDING_MS).toISOString();
|
|
16626
|
-
const stopStr = new Date(foundMinDateTime + TIME_PADDING_MS).toISOString();
|
|
16627
|
-
getPossesForRange(startStr, stopStr).then((newPositions) => {
|
|
16628
|
-
if (this.disposed) {
|
|
16629
|
-
return;
|
|
16630
|
-
}
|
|
16631
|
-
if (this.historicAnimation && this.historicAnimation.addPositions) {
|
|
16632
|
-
this.historicAnimation.addPositions(newPositions);
|
|
16633
|
-
}
|
|
16634
|
-
});
|
|
16635
|
-
}
|
|
16636
|
-
// The data we want is after the range we've currently loaded.
|
|
16637
|
-
if (fetchAfter) {
|
|
16638
|
-
// Calculate the missing difference and request it.
|
|
16639
|
-
const startStr = new Date(foundMaxDateTime - TIME_PADDING_MS).toISOString();
|
|
16640
|
-
const stopStr = new Date(maxDateTime + TIME_PADDING_MS).toISOString();
|
|
16641
|
-
getPossesForRange(startStr, stopStr).then((newPositions) => {
|
|
16642
|
-
if (this.disposed) {
|
|
16643
|
-
return;
|
|
16644
|
-
}
|
|
16645
|
-
if (this.historicAnimation && this.historicAnimation.addPositions) {
|
|
16646
|
-
this.historicAnimation.addPositions(newPositions);
|
|
16647
|
-
}
|
|
16648
|
-
});
|
|
16649
|
-
}
|
|
16650
|
-
}
|
|
17016
|
+
await this.historicGatherer.Gather([rootEntity]);
|
|
16651
17017
|
};
|
|
16652
17018
|
/**
|
|
16653
17019
|
* Requests the initial set of historic positions for the timeline range.
|
|
@@ -16661,11 +17027,8 @@
|
|
|
16661
17027
|
res(false);
|
|
16662
17028
|
return;
|
|
16663
17029
|
}
|
|
16664
|
-
const
|
|
16665
|
-
const
|
|
16666
|
-
const startStr = new Date(startTmp.getTime() - 1000).toISOString();
|
|
16667
|
-
const stopStr = new Date(stopTmp.getTime() + 1000).toISOString();
|
|
16668
|
-
const positions = await getPossesForRange(startStr, stopStr);
|
|
17030
|
+
const { recordsByIds } = await this.historicGatherer.Gather([rootEntity]);
|
|
17031
|
+
const positions = toPosses(recordsByIds[this.rootId] || []);
|
|
16669
17032
|
if (this.disposed) {
|
|
16670
17033
|
res(false);
|
|
16671
17034
|
return;
|
|
@@ -19446,12 +19809,11 @@
|
|
|
19446
19809
|
}
|
|
19447
19810
|
this.viewer.scene.requestRender();
|
|
19448
19811
|
exports.TilesetRenderEngine.OnTilesetReady(this.cTileset).then(() => {
|
|
19449
|
-
var _a;
|
|
19450
19812
|
try {
|
|
19451
19813
|
if (this.disposed || this.viewer.isDestroyed()) {
|
|
19452
19814
|
return;
|
|
19453
19815
|
}
|
|
19454
|
-
if (this.item
|
|
19816
|
+
if (Manager.NeedsStyler(this.item)) {
|
|
19455
19817
|
const api = this.getters.GetBruceApi();
|
|
19456
19818
|
this.styler.Init({
|
|
19457
19819
|
viewer: this.viewer,
|
|
@@ -19462,7 +19824,8 @@
|
|
|
19462
19824
|
expandSources: false,
|
|
19463
19825
|
menuItemId: this.item.id,
|
|
19464
19826
|
register: this.visualsManager,
|
|
19465
|
-
historic: (
|
|
19827
|
+
historic: Manager.IsHistoric(this.item),
|
|
19828
|
+
applyStyles: Boolean(this.item.ApplyStyles)
|
|
19466
19829
|
});
|
|
19467
19830
|
}
|
|
19468
19831
|
this.onCTilesetLoad();
|
|
@@ -19669,6 +20032,19 @@
|
|
|
19669
20032
|
get HandoffKey() {
|
|
19670
20033
|
return Manager.GetHandoffKey(this.item);
|
|
19671
20034
|
}
|
|
20035
|
+
/*
|
|
20036
|
+
* Returns whether the item asks for Entities as they were at the scene time.
|
|
20037
|
+
*/
|
|
20038
|
+
static IsHistoric(item) {
|
|
20039
|
+
var _a, _b;
|
|
20040
|
+
return Boolean(((_a = item === null || item === void 0 ? void 0 : item.BruceEntity) === null || _a === void 0 ? void 0 : _a.historic) || ((_b = item === null || item === void 0 ? void 0 : item.BruceEntity) === null || _b === void 0 ? void 0 : _b.historicAttrKey));
|
|
20041
|
+
}
|
|
20042
|
+
/*
|
|
20043
|
+
* Returns whether the styler has to run, which it does for historic even without styling.
|
|
20044
|
+
*/
|
|
20045
|
+
static NeedsStyler(item) {
|
|
20046
|
+
return Boolean(item === null || item === void 0 ? void 0 : item.ApplyStyles) || Manager.IsHistoric(item);
|
|
20047
|
+
}
|
|
19672
20048
|
static GetHandoffKey(item) {
|
|
19673
20049
|
var _a, _b;
|
|
19674
20050
|
const tilesetId = (_a = item === null || item === void 0 ? void 0 : item.tileset) === null || _a === void 0 ? void 0 : _a.TilesetID;
|
|
@@ -19678,7 +20054,10 @@
|
|
|
19678
20054
|
const accountId = ((_b = item.tileset) === null || _b === void 0 ? void 0 : _b.ClientAccountID) || "";
|
|
19679
20055
|
// Styled <-> unstyled has no cheap revert path, force a reload instead.
|
|
19680
20056
|
const applyStyles = Boolean(item.ApplyStyles);
|
|
19681
|
-
|
|
20057
|
+
// Historic drives a different gather,
|
|
20058
|
+
// so a handoff must not reuse a styler set up for the other mode.
|
|
20059
|
+
const historic = Manager.IsHistoric(item);
|
|
20060
|
+
return `${accountId}:${tilesetId}:${applyStyles}:${historic}`;
|
|
19682
20061
|
}
|
|
19683
20062
|
// Returns null (fall back to a normal Dispose()) if the tileset hasn't finished loading yet.
|
|
19684
20063
|
PrepareHandoff() {
|
|
@@ -19718,7 +20097,6 @@
|
|
|
19718
20097
|
// Takes ownership of a PrepareHandoff() payload instead of loading via Init().
|
|
19719
20098
|
// Then re-parents every already-registered rego to this menu item and re-runs styling.
|
|
19720
20099
|
AdoptHandoff(payload) {
|
|
19721
|
-
var _a;
|
|
19722
20100
|
this.cTileset = payload.cTileset;
|
|
19723
20101
|
this.tileset = payload.tileset;
|
|
19724
20102
|
this.typeId = payload.typeId;
|
|
@@ -19750,7 +20128,7 @@
|
|
|
19750
20128
|
toPriority: this.renderPriority,
|
|
19751
20129
|
requestRender: false
|
|
19752
20130
|
});
|
|
19753
|
-
if (this.item
|
|
20131
|
+
if (Manager.NeedsStyler(this.item)) {
|
|
19754
20132
|
this.styler.Init({
|
|
19755
20133
|
viewer: this.viewer,
|
|
19756
20134
|
api: this.getters.GetBruceApi(),
|
|
@@ -19760,7 +20138,8 @@
|
|
|
19760
20138
|
expandSources: false,
|
|
19761
20139
|
menuItemId: this.item.id,
|
|
19762
20140
|
register: this.visualsManager,
|
|
19763
|
-
historic: (
|
|
20141
|
+
historic: Manager.IsHistoric(this.item),
|
|
20142
|
+
applyStyles: Boolean(this.item.ApplyStyles)
|
|
19764
20143
|
});
|
|
19765
20144
|
this.queueHandoffRestyle(this.visualsManager.GetRegos({ menuItemId: this.item.id }));
|
|
19766
20145
|
}
|
|
@@ -21407,7 +21786,7 @@
|
|
|
21407
21786
|
}
|
|
21408
21787
|
this.cTileset = await CESIUM.Cesium3DTileset.fromUrl(proxyRootUrl, {
|
|
21409
21788
|
showCreditsOnScreen: true,
|
|
21410
|
-
|
|
21789
|
+
...exports.ViewUtils.DefaultLightingProps()
|
|
21411
21790
|
});
|
|
21412
21791
|
}
|
|
21413
21792
|
else {
|
|
@@ -22943,7 +23322,7 @@
|
|
|
22943
23322
|
const cEntity = this.viewer.entities.add({
|
|
22944
23323
|
model: {
|
|
22945
23324
|
uri: lod["ClientFile"].URL,
|
|
22946
|
-
|
|
23325
|
+
...exports.ViewUtils.DefaultLightingProps(),
|
|
22947
23326
|
heightReference: Cesium.HeightReference.NONE
|
|
22948
23327
|
},
|
|
22949
23328
|
// point: {
|
|
@@ -38660,7 +39039,7 @@
|
|
|
38660
39039
|
id: BModels.ObjectUtils.UId(15),
|
|
38661
39040
|
model: {
|
|
38662
39041
|
uri: params.lodUrl,
|
|
38663
|
-
|
|
39042
|
+
...exports.ViewUtils.DefaultLightingProps(),
|
|
38664
39043
|
heightReference: heightRef,
|
|
38665
39044
|
scale: new Cesium.CallbackProperty(() => scale * styleScale, true),
|
|
38666
39045
|
shadows: Cesium.ShadowMode.ENABLED,
|
|
@@ -39303,7 +39682,7 @@
|
|
|
39303
39682
|
url: url,
|
|
39304
39683
|
asynchronous: true,
|
|
39305
39684
|
scale: scale,
|
|
39306
|
-
|
|
39685
|
+
...exports.ViewUtils.DefaultLightingProps()
|
|
39307
39686
|
});
|
|
39308
39687
|
}
|
|
39309
39688
|
// Older versions of Cesium have a fromGltf method.
|
|
@@ -43440,7 +43819,7 @@ void main() {
|
|
|
43440
43819
|
StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
|
|
43441
43820
|
})(exports.StyleUtils || (exports.StyleUtils = {}));
|
|
43442
43821
|
|
|
43443
|
-
const VERSION = "7.1
|
|
43822
|
+
const VERSION = "7.2.1";
|
|
43444
43823
|
/**
|
|
43445
43824
|
* Updates the environment instance used by bruce-cesium to one specified.
|
|
43446
43825
|
* This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.
|
|
@@ -43474,6 +43853,8 @@ void main() {
|
|
|
43474
43853
|
exports.DEFAULT_BRIGHTNESS_SHIFT = DEFAULT_BRIGHTNESS_SHIFT;
|
|
43475
43854
|
exports.DEFAULT_LIGHT_INTENSITY = DEFAULT_LIGHT_INTENSITY;
|
|
43476
43855
|
exports.LIGHTING_SETTINGS_VERSION = LIGHTING_SETTINGS_VERSION;
|
|
43856
|
+
exports.LIGHT_INTENSITY_COMPENSATION = LIGHT_INTENSITY_COMPENSATION;
|
|
43857
|
+
exports.MAX_COMPENSATED_LIGHT_INTENSITY = MAX_COMPENSATED_LIGHT_INTENSITY;
|
|
43477
43858
|
exports.Draw3dPolygon = Draw3dPolygon;
|
|
43478
43859
|
exports.Draw3dPolyline = Draw3dPolyline;
|
|
43479
43860
|
exports.WidgetControlViewBarSearch = WidgetControlViewBarSearch;
|