@vcmap/core 5.2.1 → 5.3.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.
@@ -0,0 +1,304 @@
1
+ import { check, oneOf } from '@vcsuite/check';
2
+ import VcsApp from '../../vcsApp.js';
3
+ import FeatureStoreLayer from '../../layer/featureStoreLayer.js';
4
+ import CesiumMap from '../../map/cesiumMap.js';
5
+ import { isMobile } from '../isMobile.js';
6
+ import CesiumTilesetLayer from '../../layer/cesiumTilesetLayer.js';
7
+ import VcsEvent from '../../vcsEvent.js';
8
+
9
+ export enum DisplayQualityLevel {
10
+ LOW = 'low',
11
+ MEDIUM = 'medium',
12
+ HIGH = 'high',
13
+ }
14
+
15
+ export type DisplayQualityViewModelOptions = {
16
+ sse?: number;
17
+ fxaa?: boolean;
18
+ fogEnabled?: boolean;
19
+ fogDensity?: number;
20
+ fogScreenSpaceErrorFactor?: number;
21
+ resolutionScale?: number;
22
+ layerSSEFactor?: number;
23
+ };
24
+
25
+ export type DisplayQualityLayerModel = {
26
+ layerName: string;
27
+ defaultSse: number;
28
+ };
29
+
30
+ export type DisplayQualityOptions = {
31
+ startingQualityLevel?: DisplayQualityLevel;
32
+ startingMobileQualityLevel?: DisplayQualityLevel;
33
+ low?: DisplayQualityViewModelOptions;
34
+ medium?: DisplayQualityViewModelOptions;
35
+ high?: DisplayQualityViewModelOptions;
36
+ };
37
+
38
+ /**
39
+ * DisplayQuality Class
40
+ */
41
+ class DisplayQuality {
42
+ static get className(): string {
43
+ return 'DisplayQuality';
44
+ }
45
+
46
+ static getDefaultOptions(): DisplayQualityOptions {
47
+ return {
48
+ startingQualityLevel: DisplayQualityLevel.MEDIUM,
49
+ startingMobileQualityLevel: DisplayQualityLevel.LOW,
50
+ low: {
51
+ sse: 4,
52
+ fxaa: false,
53
+ fogEnabled: true,
54
+ fogDensity: 0.0009,
55
+ fogScreenSpaceErrorFactor: 6,
56
+ resolutionScale: 0.9,
57
+ layerSSEFactor: 2,
58
+ },
59
+ medium: {
60
+ sse: 2.333,
61
+ fxaa: false,
62
+ fogEnabled: true,
63
+ fogDensity: 0.0005,
64
+ fogScreenSpaceErrorFactor: 4,
65
+ resolutionScale: 1,
66
+ layerSSEFactor: 1.1,
67
+ },
68
+ high: {
69
+ sse: 4 / 3,
70
+ fxaa: true,
71
+ fogEnabled: false,
72
+ fogDensity: 0,
73
+ fogScreenSpaceErrorFactor: 0,
74
+ resolutionScale: 1,
75
+ layerSSEFactor: 0.5,
76
+ },
77
+ };
78
+ }
79
+
80
+ private _app: VcsApp;
81
+
82
+ private _layerSettingsCache: DisplayQualityLayerModel[];
83
+
84
+ private _viewModelSettings: DisplayQualityOptions;
85
+
86
+ private _currentQualityLevel: DisplayQualityLevel | undefined;
87
+
88
+ private _listeners: (() => void)[];
89
+
90
+ /**
91
+ * An event raised when the current quality level has been changed
92
+ */
93
+ qualityLevelChanged = new VcsEvent<void>();
94
+
95
+ constructor(app: VcsApp) {
96
+ this._app = app;
97
+ this._layerSettingsCache = [];
98
+ this._viewModelSettings = DisplayQuality.getDefaultOptions();
99
+ this._currentQualityLevel = undefined;
100
+ this._listeners = [
101
+ this._app.maps.mapActivated.addEventListener(() => {
102
+ if (
103
+ this._app.maps.activeMap instanceof CesiumMap &&
104
+ !this.currentQualityLevel
105
+ ) {
106
+ if (isMobile()) {
107
+ this.setLevel(this._viewModelSettings.startingMobileQualityLevel!);
108
+ } else {
109
+ this.setLevel(this._viewModelSettings.startingQualityLevel!);
110
+ }
111
+ }
112
+ }),
113
+ this._app.layers.stateChanged.addEventListener((layer) => {
114
+ if (layer.active && this._app.maps.activeMap instanceof CesiumMap) {
115
+ this._setLayerQuality(layer.name);
116
+ }
117
+ }),
118
+ this._app.layers.removed.addEventListener((layer) => {
119
+ const index = this._layerSettingsCache.findIndex(
120
+ (config) => config.layerName === layer.name,
121
+ );
122
+ if (index > -1) {
123
+ this._layerSettingsCache.splice(index, 1);
124
+ }
125
+ }),
126
+ ];
127
+ }
128
+
129
+ /**
130
+ * The starting quality level
131
+ */
132
+ get startingQualityLevel(): DisplayQualityLevel {
133
+ return this._viewModelSettings.startingQualityLevel!;
134
+ }
135
+
136
+ /**
137
+ * The current quality level
138
+ */
139
+ get currentQualityLevel(): DisplayQualityLevel | undefined {
140
+ return this._currentQualityLevel;
141
+ }
142
+
143
+ /**
144
+ * The current quality view model
145
+ * @private
146
+ */
147
+ get _viewModel(): DisplayQualityViewModelOptions | undefined {
148
+ if (this._currentQualityLevel) {
149
+ return this._viewModelSettings[this._currentQualityLevel]!;
150
+ }
151
+
152
+ return undefined;
153
+ }
154
+
155
+ /**
156
+ * Update the display quality options
157
+ * @param options
158
+ * @param silent
159
+ */
160
+ updateOptions(options: DisplayQualityOptions, silent?: boolean): void {
161
+ check(options, Object);
162
+ const filteredOptions: DisplayQualityOptions = Object.fromEntries(
163
+ Object.entries(options as Record<string, unknown>)
164
+ .filter(([, value]) => value != null)
165
+ .map(([key, value]) => {
166
+ if (
167
+ key === DisplayQualityLevel.LOW ||
168
+ key === DisplayQualityLevel.MEDIUM ||
169
+ key === DisplayQualityLevel.HIGH
170
+ ) {
171
+ return [
172
+ key,
173
+ Object.fromEntries(
174
+ Object.entries(value as Record<string, unknown>).filter(
175
+ ([, v]) => v != null,
176
+ ),
177
+ ),
178
+ ];
179
+ }
180
+ return [key, value];
181
+ }),
182
+ );
183
+ const defaultOptions = DisplayQuality.getDefaultOptions();
184
+ this._viewModelSettings = {
185
+ ...defaultOptions,
186
+ ...filteredOptions,
187
+ low: { ...defaultOptions.low, ...filteredOptions.low },
188
+ medium: { ...defaultOptions.medium, ...filteredOptions.medium },
189
+ high: { ...defaultOptions.high, ...filteredOptions.high },
190
+ };
191
+ if (!silent) {
192
+ if (this.currentQualityLevel) {
193
+ this.setLevel(this.currentQualityLevel);
194
+ } else if (isMobile()) {
195
+ this.setLevel(this._viewModelSettings.startingMobileQualityLevel!);
196
+ } else {
197
+ this.setLevel(this._viewModelSettings.startingQualityLevel!);
198
+ }
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Set display quality level for 3D map and layers
204
+ * @param level
205
+ */
206
+ setLevel(level: DisplayQualityLevel): void {
207
+ check(
208
+ level,
209
+ oneOf(
210
+ DisplayQualityLevel.LOW,
211
+ DisplayQualityLevel.MEDIUM,
212
+ DisplayQualityLevel.HIGH,
213
+ ),
214
+ );
215
+
216
+ if (!(this._app.maps.activeMap instanceof CesiumMap)) {
217
+ this._currentQualityLevel = undefined;
218
+ this._viewModelSettings.startingQualityLevel = level;
219
+ this._viewModelSettings.startingMobileQualityLevel = level;
220
+ return;
221
+ }
222
+
223
+ const previousLevel = this._currentQualityLevel;
224
+ this._currentQualityLevel = level;
225
+
226
+ [...this._app.layers]
227
+ .filter(
228
+ (layer) =>
229
+ layer.active &&
230
+ (layer instanceof CesiumTilesetLayer ||
231
+ layer instanceof FeatureStoreLayer),
232
+ )
233
+ .forEach((layer) => {
234
+ this._setLayerQuality(layer.name);
235
+ });
236
+
237
+ const viewer = this._app.maps.activeMap.getCesiumWidget();
238
+ if (viewer && this._viewModel) {
239
+ viewer.scene.globe.maximumScreenSpaceError = this._viewModel.sse!;
240
+ if (viewer.scene.postProcessStages) {
241
+ viewer.scene.postProcessStages.fxaa.enabled = this._viewModel.fxaa!;
242
+ }
243
+ viewer.resolutionScale = this._viewModel.resolutionScale!;
244
+ viewer.scene.fog.enabled = this._viewModel.fogEnabled!;
245
+ viewer.scene.fog.density = this._viewModel.fogDensity!;
246
+ viewer.scene.fog.screenSpaceErrorFactor =
247
+ this._viewModel.fogScreenSpaceErrorFactor!;
248
+ }
249
+
250
+ if (this._currentQualityLevel !== previousLevel) {
251
+ this.qualityLevelChanged.raiseEvent();
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Set layer quality
257
+ * @param layerName
258
+ * @private
259
+ */
260
+ _setLayerQuality(layerName: string | undefined): void {
261
+ check(layerName, String);
262
+
263
+ const layer = this._app.layers.getByKey(layerName);
264
+ if (
265
+ (layer instanceof CesiumTilesetLayer ||
266
+ layer instanceof FeatureStoreLayer) &&
267
+ layer.active
268
+ ) {
269
+ let config = this._layerSettingsCache.find(
270
+ (layerConfig) => layerConfig.layerName === layerName,
271
+ );
272
+ let sse;
273
+ if (!config) {
274
+ sse = isMobile()
275
+ ? layer.screenSpaceErrorMobile
276
+ : layer.screenSpaceError;
277
+ if (sse) {
278
+ config = {
279
+ layerName: layer.name,
280
+ defaultSse: sse,
281
+ };
282
+ this._layerSettingsCache.push(config);
283
+ }
284
+ }
285
+ if (config && this._viewModel) {
286
+ layer.setMaximumScreenSpaceError(
287
+ config.defaultSse * this._viewModel.layerSSEFactor!,
288
+ );
289
+ }
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Destroys the display quality, clearing its event listeners
295
+ */
296
+ destroy(): void {
297
+ this._listeners.forEach((cb) => {
298
+ cb();
299
+ });
300
+ this.qualityLevelChanged.destroy();
301
+ }
302
+ }
303
+
304
+ export default DisplayQuality;
package/src/vcsApp.ts CHANGED
@@ -50,6 +50,7 @@ import FlightInstance, {
50
50
  FlightInstanceOptions,
51
51
  } from './util/flight/flightInstance.js';
52
52
  import FlightCollection from './util/flight/flightCollection.js';
53
+ import DisplayQuality from './util/displayQuality/displayQuality.js';
53
54
 
54
55
  function getLogger(): Logger {
55
56
  return getLoggerByName('init');
@@ -120,6 +121,8 @@ class VcsApp {
120
121
 
121
122
  private _categories: CategoryCollection;
122
123
 
124
+ private _displayQuality: DisplayQuality;
125
+
123
126
  private _destroyed: VcsEvent<void>;
124
127
 
125
128
  private _moduleMutationChain: {
@@ -223,6 +226,7 @@ class VcsApp {
223
226
  categoryClassRegistry,
224
227
  );
225
228
  this._categories = new CategoryCollection(this);
229
+ this._displayQuality = new DisplayQuality(this);
226
230
  this._destroyed = new VcsEvent();
227
231
  this._moduleMutationChain = { running: false, items: [] };
228
232
  this._categoryItemClassRegistry = new OverrideClassRegistry(
@@ -303,6 +307,10 @@ class VcsApp {
303
307
  return this._flights;
304
308
  }
305
309
 
310
+ get displayQuality(): DisplayQuality {
311
+ return this._displayQuality;
312
+ }
313
+
306
314
  get destroyed(): VcsEvent<void> {
307
315
  return this._destroyed;
308
316
  }
@@ -601,6 +609,7 @@ class VcsApp {
601
609
  this._categoryItemClassRegistry.destroy();
602
610
  this._tileProviderClassRegistry.destroy();
603
611
  this._featureProviderClassRegistry.destroy();
612
+ this._displayQuality.destroy();
604
613
  this.destroyed.raiseEvent();
605
614
  this.destroyed.destroy();
606
615
  this.localeChanged.destroy();