@honua/app-platform 0.1.1-beta.0 → 0.1.4-beta.0
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/collaboration/client.d.ts.map +1 -1
- package/connect-url-safety.d.ts +53 -0
- package/connect-url-safety.js +189 -0
- package/contract/discovery.d.ts +34 -0
- package/contract/discovery.d.ts.map +1 -1
- package/contract/index.d.ts +7 -5
- package/contract/index.d.ts.map +1 -1
- package/contract/index.js +3 -2
- package/contract/pmtiles.d.ts +10 -1
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +10 -2
- package/contract/protocol-module.d.ts +84 -9
- package/contract/protocol-module.d.ts.map +1 -1
- package/contract/query-filter-fes.d.ts +18 -0
- package/contract/query-filter-fes.d.ts.map +1 -0
- package/contract/query-filter-fes.js +122 -0
- package/contract/query-filter.d.ts +300 -0
- package/contract/query-filter.d.ts.map +1 -0
- package/contract/query-filter.js +883 -0
- package/contract/schema.d.ts +12 -0
- package/contract/schema.d.ts.map +1 -1
- package/contract/schema.js +34 -0
- package/contract/source-capability-support.d.ts.map +1 -1
- package/contract/source-capability-support.js +15 -3
- package/contract/source.d.ts +45 -25
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +719 -479
- package/contract/types.d.ts +87 -18
- package/contract/types.d.ts.map +1 -1
- package/contract/widget-source.d.ts.map +1 -1
- package/controls/basemap-switcher.d.ts +19 -11
- package/controls/basemap-switcher.d.ts.map +1 -1
- package/controls/basemap-switcher.js +58 -25
- package/controls/catalog.d.ts +105 -0
- package/controls/catalog.d.ts.map +1 -0
- package/controls/catalog.js +341 -0
- package/controls/element-utils.d.ts +9 -0
- package/controls/element-utils.d.ts.map +1 -1
- package/controls/element-utils.js +17 -0
- package/controls/index.d.ts +29 -8
- package/controls/index.d.ts.map +1 -1
- package/controls/index.js +26 -8
- package/controls/layer-list.d.ts +13 -5
- package/controls/layer-list.d.ts.map +1 -1
- package/controls/layer-list.js +72 -15
- package/controls/legend.d.ts +32 -5
- package/controls/legend.d.ts.map +1 -1
- package/controls/legend.js +95 -25
- package/controls/qualification.d.ts +152 -0
- package/controls/qualification.d.ts.map +1 -0
- package/controls/qualification.js +1265 -0
- package/controls/registry.d.ts +104 -0
- package/controls/registry.d.ts.map +1 -0
- package/controls/registry.js +150 -0
- package/controls/swipe-control.d.ts +6 -1
- package/controls/swipe-control.d.ts.map +1 -1
- package/controls/swipe-control.js +82 -20
- package/core/client.d.ts +45 -21
- package/core/client.d.ts.map +1 -1
- package/core/client.js +224 -46
- package/core/error-classifications.d.ts +6 -0
- package/core/error-classifications.d.ts.map +1 -1
- package/core/error-classifications.js +6 -0
- package/core/error-code-registry.d.ts +6 -0
- package/core/error-code-registry.d.ts.map +1 -1
- package/core/error-code-registry.js +6 -0
- package/core/error-envelope.js +2 -0
- package/core/errors.d.ts +1 -1
- package/core/errors.js +1 -1
- package/core/geoparquet-sql.d.ts +68 -4
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +325 -8
- package/core/odata-write-codec.d.ts.map +1 -1
- package/core/odata-write-codec.js +0 -1
- package/core/odata.d.ts +6 -0
- package/core/odata.d.ts.map +1 -1
- package/core/odata.js +6 -1
- package/core/ogc-processes.d.ts +182 -25
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +602 -30
- package/core/process-runner.d.ts +8 -1
- package/core/process-runner.d.ts.map +1 -1
- package/core/process-runner.js +1 -0
- package/core/protocol-transport.d.ts +2 -0
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/stac.d.ts +31 -0
- package/core/stac.d.ts.map +1 -1
- package/core/stac.js +136 -19
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +273 -68
- package/core/types.d.ts +123 -9
- package/core/types.d.ts.map +1 -1
- package/core/wfs-axis-order.d.ts +18 -0
- package/core/wfs-axis-order.d.ts.map +1 -0
- package/core/wfs-axis-order.js +108 -0
- package/core/wfs-capabilities.d.ts +65 -24
- package/core/wfs-capabilities.d.ts.map +1 -1
- package/core/wfs-capabilities.js +237 -27
- package/core/wfs-filter.d.ts +26 -3
- package/core/wfs-filter.d.ts.map +1 -1
- package/core/wfs-filter.js +48 -53
- package/core/wfs-protocol-error.d.ts +12 -0
- package/core/wfs-protocol-error.d.ts.map +1 -0
- package/core/wfs-protocol-error.js +13 -0
- package/core/wfs.d.ts +53 -1
- package/core/wfs.d.ts.map +1 -1
- package/core/wfs.js +251 -29
- package/core/wms-feature-info.d.ts +92 -0
- package/core/wms-feature-info.d.ts.map +1 -0
- package/core/wms-feature-info.js +285 -0
- package/core/wms.d.ts +9 -0
- package/core/wms.d.ts.map +1 -1
- package/core/wms.js +17 -5
- package/esri-compat/event-bus.d.ts +20 -0
- package/esri-compat/event-bus.d.ts.map +1 -1
- package/esri-compat/feature-filter.d.ts +46 -1
- package/esri-compat/feature-filter.d.ts.map +1 -1
- package/esri-compat/feature-filter.js +49 -0
- package/esri-compat/geojson-layer.d.ts +4 -2
- package/esri-compat/geojson-layer.d.ts.map +1 -1
- package/esri-compat/geojson-layer.js +4 -2
- package/esri-compat/identity-manager.js +2 -2
- package/esri-compat/imagery-layer.d.ts +2 -1
- package/esri-compat/imagery-layer.d.ts.map +1 -1
- package/esri-compat/imagery-layer.js +2 -1
- package/esri-compat/layer-list.d.ts +8 -1
- package/esri-compat/layer-list.d.ts.map +1 -1
- package/esri-compat/layer-list.js +11 -4
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +1 -1
- package/esri-compat/locator.d.ts +297 -0
- package/esri-compat/locator.d.ts.map +1 -0
- package/esri-compat/locator.js +579 -0
- package/esri-compat/map-image-layer.d.ts.map +1 -1
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +1 -1
- package/esri-compat/scene-view.d.ts.map +1 -1
- package/esri-compat/time-slider.d.ts +29 -0
- package/esri-compat/time-slider.d.ts.map +1 -1
- package/esri-compat/time-slider.js +117 -0
- package/esri-compat/wfs-layer.d.ts +2 -1
- package/esri-compat/wfs-layer.d.ts.map +1 -1
- package/esri-compat/wfs-layer.js +2 -1
- package/esri-compat/widget-host.d.ts +42 -6
- package/esri-compat/widget-host.d.ts.map +1 -1
- package/esri-compat/widget-host.js +99 -10
- package/generated-app/projection.d.ts.map +1 -1
- package/generated-app/runtime.d.ts.map +1 -1
- package/map/data-to-map-bridge.d.ts +1 -1
- package/map/data-to-map-bridge.d.ts.map +1 -1
- package/map/data-to-map-bridge.js +1 -2
- package/map/honua-map.d.ts.map +1 -1
- package/map/honua-map.js +1 -1
- package/map/index.d.ts +2 -0
- package/map/index.d.ts.map +1 -1
- package/map/index.js +2 -0
- package/map/realtime-reconciliation-adapter.d.ts +98 -0
- package/map/realtime-reconciliation-adapter.d.ts.map +1 -0
- package/map/realtime-reconciliation-adapter.js +84 -0
- package/map/temporal-playback.d.ts +25 -0
- package/map/temporal-playback.d.ts.map +1 -1
- package/map/temporal-playback.js +29 -1
- package/operator/workspace/workspace.d.ts.map +1 -1
- package/operator/workspace/workspace.js +0 -2
- package/package.json +4 -3
- package/query-planner/canonical-filter.d.ts +30 -0
- package/query-planner/canonical-filter.d.ts.map +1 -0
- package/query-planner/canonical-filter.js +30 -0
- package/query-planner/columnar-plan.d.ts +63 -0
- package/query-planner/columnar-plan.d.ts.map +1 -0
- package/query-planner/columnar-plan.js +94 -0
- package/query-planner/diagnostics.d.ts +3 -3
- package/query-planner/diagnostics.d.ts.map +1 -1
- package/query-planner/diagnostics.js +17 -4
- package/query-planner/duckdb.d.ts.map +1 -1
- package/query-planner/duckdb.js +16 -2
- package/query-planner/execution-context.d.ts.map +1 -1
- package/query-planner/execution-context.js +3 -1
- package/query-planner/executor.d.ts.map +1 -1
- package/query-planner/executor.js +7 -1
- package/query-planner/geoservices.d.ts.map +1 -1
- package/query-planner/geoservices.js +24 -5
- package/query-planner/grpc.d.ts.map +1 -1
- package/query-planner/grpc.js +29 -5
- package/query-planner/index.d.ts +20 -5
- package/query-planner/index.d.ts.map +1 -1
- package/query-planner/index.js +16 -3
- package/query-planner/ir.d.ts +6 -1
- package/query-planner/ir.d.ts.map +1 -1
- package/query-planner/ir.js +63 -1
- package/query-planner/odata-protocol-module.d.ts +54 -0
- package/query-planner/odata-protocol-module.d.ts.map +1 -0
- package/query-planner/odata-protocol-module.js +199 -0
- package/query-planner/odata-v1.d.ts +23 -0
- package/query-planner/odata-v1.d.ts.map +1 -0
- package/query-planner/odata-v1.js +202 -0
- package/query-planner/odata.d.ts +0 -3
- package/query-planner/odata.d.ts.map +1 -1
- package/query-planner/odata.js +0 -143
- package/query-planner/ogc-features.d.ts.map +1 -1
- package/query-planner/ogc-features.js +23 -1
- package/query-planner/planner.d.ts +2 -2
- package/query-planner/planner.d.ts.map +1 -1
- package/query-planner/planner.js +146 -27
- package/query-planner/representation.d.ts +59 -0
- package/query-planner/representation.d.ts.map +1 -0
- package/query-planner/representation.js +140 -0
- package/query-planner/types.d.ts +153 -3
- package/query-planner/types.d.ts.map +1 -1
- package/query-planner/wfs-protocol-module.d.ts +57 -0
- package/query-planner/wfs-protocol-module.d.ts.map +1 -0
- package/query-planner/wfs-protocol-module.js +731 -0
- package/query-planner/wfs-v1.d.ts +41 -0
- package/query-planner/wfs-v1.d.ts.map +1 -0
- package/query-planner/wfs-v1.js +366 -0
- package/query-planner/wfs.d.ts +1 -3
- package/query-planner/wfs.d.ts.map +1 -1
- package/query-planner/wfs.js +1 -70
- package/realtime/checkpoint-store.d.ts +206 -0
- package/realtime/checkpoint-store.d.ts.map +1 -0
- package/realtime/checkpoint-store.js +504 -0
- package/realtime/honua-server.d.ts +8 -0
- package/realtime/honua-server.d.ts.map +1 -1
- package/realtime/honua-server.js +123 -14
- package/realtime/index.d.ts +4 -0
- package/realtime/index.d.ts.map +1 -1
- package/realtime/index.js +2 -0
- package/realtime/reconciliation.d.ts +245 -0
- package/realtime/reconciliation.d.ts.map +1 -0
- package/realtime/reconciliation.js +377 -0
- package/realtime/resumable-transport.d.ts.map +1 -1
- package/realtime/sse.d.ts.map +1 -1
- package/realtime/websocket.d.ts.map +1 -1
- package/realtime/wire.d.ts +2 -1
- package/realtime/wire.d.ts.map +1 -1
- package/realtime/wire.js +24 -8
- package/replica-sync/errors.d.ts +19 -1
- package/replica-sync/errors.d.ts.map +1 -1
- package/replica-sync/errors.js +16 -0
- package/replica-sync/geoservices.d.ts +260 -0
- package/replica-sync/geoservices.d.ts.map +1 -0
- package/replica-sync/geoservices.js +1093 -0
- package/replica-sync/index.d.ts +5 -1
- package/replica-sync/index.d.ts.map +1 -1
- package/replica-sync/index.js +3 -1
- package/replica-sync/transport-conformance.d.ts +58 -0
- package/replica-sync/transport-conformance.d.ts.map +1 -0
- package/replica-sync/transport-conformance.js +265 -0
- package/replica-sync/types.d.ts +22 -0
- package/replica-sync/types.d.ts.map +1 -1
- package/runtime/index.d.ts +6 -2
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +3 -1
- package/runtime/load-package.d.ts +24 -0
- package/runtime/load-package.d.ts.map +1 -1
- package/runtime/load-package.js +45 -1
- package/runtime/maplibre-renderer.d.ts +11 -0
- package/runtime/maplibre-renderer.d.ts.map +1 -1
- package/runtime/maplibre-renderer.js +32 -7
- package/runtime/offline-region-protocol.d.ts +73 -0
- package/runtime/offline-region-protocol.d.ts.map +1 -0
- package/runtime/offline-region-protocol.js +63 -0
- package/runtime/offline-region-style.d.ts +78 -0
- package/runtime/offline-region-style.d.ts.map +1 -0
- package/runtime/offline-region-style.js +147 -0
- package/runtime/pmtiles-protocol.d.ts +7 -8
- package/runtime/pmtiles-protocol.d.ts.map +1 -1
- package/runtime/pmtiles-protocol.js +19 -66
- package/runtime/protocol-registry.d.ts +55 -0
- package/runtime/protocol-registry.d.ts.map +1 -0
- package/runtime/protocol-registry.js +103 -0
- package/runtime/runtime.d.ts +2 -0
- package/runtime/runtime.d.ts.map +1 -1
- package/runtime/runtime.js +6 -1
- package/scene-workspace/analysis-widgets.d.ts +4 -2
- package/scene-workspace/analysis-widgets.d.ts.map +1 -1
- package/scene-workspace/analysis-widgets.js +4 -2
- package/scene-workspace/camera-correspondence.d.ts +151 -0
- package/scene-workspace/camera-correspondence.d.ts.map +1 -0
- package/scene-workspace/camera-correspondence.js +220 -0
- package/scene-workspace/cesium-adapter.d.ts +230 -29
- package/scene-workspace/cesium-adapter.d.ts.map +1 -1
- package/scene-workspace/cesium-adapter.js +741 -56
- package/scene-workspace/cesium-mount.d.ts +205 -0
- package/scene-workspace/cesium-mount.d.ts.map +1 -0
- package/scene-workspace/cesium-mount.js +392 -0
- package/scene-workspace/cesium-scene-owner.d.ts +160 -0
- package/scene-workspace/cesium-scene-owner.d.ts.map +1 -0
- package/scene-workspace/cesium-scene-owner.js +205 -0
- package/scene-workspace/cesium-state-sync.d.ts +101 -0
- package/scene-workspace/cesium-state-sync.d.ts.map +1 -0
- package/scene-workspace/cesium-state-sync.js +432 -0
- package/scene-workspace/cesium-time.d.ts +346 -0
- package/scene-workspace/cesium-time.d.ts.map +1 -0
- package/scene-workspace/cesium-time.js +403 -0
- package/scene-workspace/index.d.ts +42 -10
- package/scene-workspace/index.d.ts.map +1 -1
- package/scene-workspace/index.js +32 -7
- package/scene-workspace/maplibre-state-sync.d.ts +112 -0
- package/scene-workspace/maplibre-state-sync.d.ts.map +1 -0
- package/scene-workspace/maplibre-state-sync.js +400 -0
- package/scene-workspace/primitives.d.ts +237 -3
- package/scene-workspace/primitives.d.ts.map +1 -1
- package/scene-workspace/primitives.js +1087 -17
- package/scene-workspace/scene-discovery.d.ts +5 -2
- package/scene-workspace/scene-discovery.d.ts.map +1 -1
- package/scene-workspace/scene-discovery.js +5 -2
- package/scene-workspace/scene-view.d.ts +5 -2
- package/scene-workspace/scene-view.d.ts.map +1 -1
- package/scene-workspace/scene-view.js +5 -2
- package/scene-workspace/source-to-cesium.d.ts +141 -8
- package/scene-workspace/source-to-cesium.d.ts.map +1 -1
- package/scene-workspace/source-to-cesium.js +497 -72
- package/scene-workspace/state-sync-port-kit.d.ts +156 -0
- package/scene-workspace/state-sync-port-kit.d.ts.map +1 -0
- package/scene-workspace/state-sync-port-kit.js +319 -0
- package/scene-workspace/state-sync.d.ts +34 -1
- package/scene-workspace/state-sync.d.ts.map +1 -1
- package/scene-workspace/state-sync.js +48 -0
- package/scene-workspace/types.d.ts +8 -0
- package/scene-workspace/types.d.ts.map +1 -1
- package/scene-workspace/types.js +2 -0
- package/scene-workspace/workspace.d.ts +12 -1
- package/scene-workspace/workspace.d.ts.map +1 -1
- package/scene-workspace/workspace.js +13 -0
- package/studio/index.d.ts +24 -7
- package/studio/index.d.ts.map +1 -1
- package/studio/index.js +21 -7
- package/studio/lifecycle-client.d.ts +164 -0
- package/studio/lifecycle-client.d.ts.map +1 -0
- package/studio/lifecycle-client.js +299 -0
- package/studio/lifecycle-errors.d.ts +91 -0
- package/studio/lifecycle-errors.d.ts.map +1 -0
- package/studio/lifecycle-errors.js +77 -0
- package/studio/lifecycle-types.d.ts +321 -0
- package/studio/lifecycle-types.d.ts.map +1 -0
- package/studio/lifecycle-types.js +22 -0
- package/web-components/controller.d.ts.map +1 -1
- package/web-components/csp-styles.d.ts +6 -0
- package/web-components/csp-styles.d.ts.map +1 -0
- package/web-components/csp-styles.js +53 -0
- package/web-components/elements.d.ts +158 -2
- package/web-components/elements.d.ts.map +1 -1
- package/web-components/elements.js +1302 -215
- package/web-components/export-redaction.d.ts +252 -0
- package/web-components/export-redaction.d.ts.map +1 -0
- package/web-components/export-redaction.js +588 -0
- package/web-components/export.d.ts +417 -0
- package/web-components/export.d.ts.map +1 -0
- package/web-components/export.js +719 -0
- package/web-components/feature-editor-model.d.ts +265 -0
- package/web-components/feature-editor-model.d.ts.map +1 -0
- package/web-components/feature-editor-model.js +438 -0
- package/web-components/feature-editor-sketch.d.ts +125 -0
- package/web-components/feature-editor-sketch.d.ts.map +1 -0
- package/web-components/feature-editor-sketch.js +194 -0
- package/web-components/feature-editor-workflow.d.ts +286 -0
- package/web-components/feature-editor-workflow.d.ts.map +1 -0
- package/web-components/feature-editor-workflow.js +889 -0
- package/web-components/feature-editor.d.ts +83 -0
- package/web-components/feature-editor.d.ts.map +1 -0
- package/web-components/feature-editor.js +829 -0
- package/web-components/feature-table-engine.d.ts +465 -0
- package/web-components/feature-table-engine.d.ts.map +1 -0
- package/web-components/feature-table-engine.js +1360 -0
- package/web-components/feature-table-view.d.ts +95 -0
- package/web-components/feature-table-view.d.ts.map +1 -0
- package/web-components/feature-table-view.js +343 -0
- package/web-components/index.d.ts +34 -3
- package/web-components/index.d.ts.map +1 -1
- package/web-components/index.js +35 -2
- package/web-components/maplibre-renderer.d.ts.map +1 -1
- package/web-components/maplibre-renderer.js +13 -4
- package/web-components/measurement.d.ts +3 -1
- package/web-components/measurement.d.ts.map +1 -1
- package/web-components/measurement.js +62 -18
- package/web-components/time-slider.d.ts +122 -0
- package/web-components/time-slider.d.ts.map +1 -0
- package/web-components/time-slider.js +740 -0
- package/web-components/types.d.ts +310 -0
- package/web-components/types.d.ts.map +1 -1
- package/webmap/convert-label.js +0 -1
- package/webmap/convert-symbol.d.ts.map +1 -1
|
@@ -7,20 +7,30 @@
|
|
|
7
7
|
* when a live {@link CesiumSceneRuntimeTarget} is actually driven.
|
|
8
8
|
*
|
|
9
9
|
* As of honua-server#1197 the adapter renders Honua 3D content end-to-end:
|
|
10
|
-
* 3D-Tiles tilesets (add/remove/visibility
|
|
11
|
-
* via `CesiumTerrainProvider`, with
|
|
12
|
-
*
|
|
13
|
-
* 3D-Tiles feature's
|
|
10
|
+
* 3D-Tiles tilesets (add/remove/visibility, including point clouds with bounded
|
|
11
|
+
* shading), terrain providers (quantized-mesh via `CesiumTerrainProvider`, with
|
|
12
|
+
* vertical exaggeration), imagery providers, and glTF/GLB model layers placed
|
|
13
|
+
* with heading/pitch/roll + scale. It also resolves a picked 3D-Tiles feature's
|
|
14
|
+
* attributes (batch properties / `EXT_structural_metadata`).
|
|
15
|
+
*
|
|
16
|
+
* Every model/imagery binding is validated before the peer loads, so an
|
|
17
|
+
* unrenderable primitive fails closed with a stable diagnostic instead of
|
|
18
|
+
* reaching a Cesium factory or silently rendering nothing.
|
|
14
19
|
*
|
|
15
20
|
* The provider wiring is still kept Cesium-mockable: every CesiumJS symbol the
|
|
16
21
|
* adapter touches is read off the lazily-imported module, so the wiring is
|
|
17
22
|
* exercised against a `vi.mock("cesium")` stub without a live WebGL `Viewer`.
|
|
18
23
|
*
|
|
19
|
-
* @
|
|
20
|
-
*
|
|
24
|
+
* @beta Part of the beta `@honua/app-platform/scene-workspace` surface: the
|
|
25
|
+
* adapter's exports are not renamed or removed through 0.1.x, and diagnostic
|
|
26
|
+
* codes and renderer capability flags grow additively. The `cesium` peer floor
|
|
27
|
+
* may rise within 0.1.x, and the server-authored 3D style types track the
|
|
28
|
+
* Honua Server styling contract. See the surface tiers table in
|
|
29
|
+
* `docs/standalone-capability-matrix.md`.
|
|
21
30
|
* @module
|
|
22
31
|
*/
|
|
23
|
-
import {
|
|
32
|
+
import { applyCesiumSceneTime, restoreCesiumClock, } from "./cesium-time.js";
|
|
33
|
+
import { RENDERER_WGS84_SPATIAL_CAPABILITIES, createSceneRuntimeAdapter, diagnoseScenePrimitives, summarizeDiagnosticStatus, } from "./primitives.js";
|
|
24
34
|
/**
|
|
25
35
|
* Capabilities advertised by the Cesium adapter. Unlike the MapLibre 2.5D
|
|
26
36
|
* adapter, Cesium is a true globe renderer: full 3D camera with
|
|
@@ -35,15 +45,25 @@ export const CESIUM_SCENE_CAPABILITIES = {
|
|
|
35
45
|
protocols: ["quantized-mesh", "terrain-rgb", "raster-dem", "image-service", "custom"],
|
|
36
46
|
supportsExaggeration: true,
|
|
37
47
|
},
|
|
48
|
+
imagery: {
|
|
49
|
+
protocols: ["url-template", "wms", "wmts", "single-tile", "arcgis-imagery"],
|
|
50
|
+
},
|
|
38
51
|
extrusion: true,
|
|
39
52
|
modelLayer: {
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
53
|
+
// CesiumJS itself can consume all four formats. `materializedFormats` is the
|
|
54
|
+
// narrower set this adapter actually attaches to a live scene: glTF/GLB
|
|
55
|
+
// single models and 3D-Tiles tilesets (point clouds ride the tileset path).
|
|
56
|
+
// I3S stays declared-capable but unmaterialized, so an i3s primitive fails
|
|
57
|
+
// closed with `scene-primitive-model-format-not-materialized` instead of
|
|
58
|
+
// reporting `supported` and then rendering nothing.
|
|
44
59
|
formats: ["gltf", "glb", "3d-tiles", "i3s"],
|
|
60
|
+
materializedFormats: ["gltf", "glb", "3d-tiles"],
|
|
45
61
|
},
|
|
46
62
|
sceneLayerMetadata: true,
|
|
63
|
+
// The globe is the WGS84 ellipsoid. Web Mercator bindings are accepted
|
|
64
|
+
// because Cesium reprojects them onto that globe itself; nothing else is,
|
|
65
|
+
// because this adapter never reinterprets coordinates or heights.
|
|
66
|
+
spatial: RENDERER_WGS84_SPATIAL_CAPABILITIES,
|
|
47
67
|
};
|
|
48
68
|
const DEG2RAD = Math.PI / 180;
|
|
49
69
|
const RAD2DEG = 180 / Math.PI;
|
|
@@ -147,6 +167,16 @@ export function modelLayerToCesiumPlacement(primitive) {
|
|
|
147
167
|
scale: resolveCesiumModelScale(primitive.scale),
|
|
148
168
|
};
|
|
149
169
|
}
|
|
170
|
+
const ownedCesiumTerrainProviders = new WeakSet();
|
|
171
|
+
function disposeOwnedCesiumTerrainProvider(resource) {
|
|
172
|
+
if (resource && typeof resource === "object" && ownedCesiumTerrainProviders.has(resource)) {
|
|
173
|
+
const destroy = resource.destroy;
|
|
174
|
+
if (typeof destroy === "function") {
|
|
175
|
+
destroy.call(resource);
|
|
176
|
+
ownedCesiumTerrainProviders.delete(resource);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
150
180
|
/**
|
|
151
181
|
* Lazily import the CesiumJS runtime. Kept in its own function so the dynamic
|
|
152
182
|
* `import("cesium")` is the *only* reference to the package in `src/`, which is
|
|
@@ -302,23 +332,53 @@ export async function applyTilesetServerStyle(tileset, tilesetUrl, cesium, fetch
|
|
|
302
332
|
* (no fetch), so existing callers are unaffected.
|
|
303
333
|
*/
|
|
304
334
|
export async function addCesium3DTileset(scene, primitive, cesium, options = {}) {
|
|
335
|
+
assertRenderableModelLayer(primitive);
|
|
336
|
+
options.signal?.throwIfAborted();
|
|
305
337
|
const mod = cesium ?? (await loadCesium());
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
338
|
+
const pointCloudShading = normalizePointCloudShading(primitive.pointCloudShading);
|
|
339
|
+
// Attribution reaches every materialized asset, not just imagery (#1049
|
|
340
|
+
// REQ-005): a tileset drawn without its credit is an attribution gap the user
|
|
341
|
+
// cannot see, and Cesium's `CreditDisplay` is the only place it can land.
|
|
342
|
+
const tilesetOptions = {
|
|
343
|
+
...(pointCloudShading ? { pointCloudShading } : {}),
|
|
344
|
+
...(primitive.attribution ? { credit: primitive.attribution } : {}),
|
|
345
|
+
};
|
|
346
|
+
const tileset = await (Object.keys(tilesetOptions).length > 0
|
|
347
|
+
? mod.Cesium3DTileset.fromUrl(primitive.uri, tilesetOptions)
|
|
348
|
+
: mod.Cesium3DTileset.fromUrl(primitive.uri));
|
|
349
|
+
// From here on the tileset is adapter-owned. A placement, style-sidecar, or
|
|
350
|
+
// collection failure must not strand it: nothing else holds a reference, so
|
|
351
|
+
// it would otherwise retain its GPU/worker resources for the process lifetime.
|
|
352
|
+
// An abort settled while the load was in flight lands here too, which is what
|
|
353
|
+
// keeps a cancelled tileset out of the scene entirely rather than attached and
|
|
354
|
+
// then detached.
|
|
355
|
+
try {
|
|
356
|
+
options.signal?.throwIfAborted();
|
|
357
|
+
if (primitive.position) {
|
|
358
|
+
tileset.modelMatrix = placementToModelMatrix(mod, modelLayerToCesiumPlacement(primitive));
|
|
359
|
+
}
|
|
360
|
+
if (options.applyServerStyle !== false) {
|
|
361
|
+
await applyTilesetServerStyle(tileset, primitive.uri, mod, options.fetchImpl ?? fetch.bind(globalThis));
|
|
362
|
+
options.signal?.throwIfAborted();
|
|
363
|
+
}
|
|
364
|
+
scene.primitives.add(tileset);
|
|
309
365
|
}
|
|
310
|
-
|
|
311
|
-
|
|
366
|
+
catch (error) {
|
|
367
|
+
if (scene.primitives.contains(tileset))
|
|
368
|
+
scene.primitives.remove(tileset);
|
|
369
|
+
destroyOwnedCesiumPrimitive(tileset);
|
|
370
|
+
throw error;
|
|
312
371
|
}
|
|
313
|
-
scene.
|
|
314
|
-
return makeLayerHandle(scene, primitive.id, tileset, "model-layer", primitive.format);
|
|
372
|
+
return makeLayerHandle(scene, primitive.id, tileset, primitive.format);
|
|
315
373
|
}
|
|
316
374
|
/**
|
|
317
375
|
* Materialize a glTF/GLB model from a model-layer primitive, placing it at the
|
|
318
376
|
* primitive's position/rotation/scale, and add it to the scene. Returns a
|
|
319
|
-
* handle for visibility / teardown.
|
|
377
|
+
* handle for visibility / opacity / teardown.
|
|
320
378
|
*/
|
|
321
|
-
export async function addCesiumModel(scene, primitive, cesium) {
|
|
379
|
+
export async function addCesiumModel(scene, primitive, cesium, options = {}) {
|
|
380
|
+
assertRenderableModelLayer(primitive);
|
|
381
|
+
options.signal?.throwIfAborted();
|
|
322
382
|
const mod = cesium ?? (await loadCesium());
|
|
323
383
|
const placement = modelLayerToCesiumPlacement(primitive);
|
|
324
384
|
// `placementToModelMatrix` already folds the uniform scale into the model
|
|
@@ -328,9 +388,363 @@ export async function addCesiumModel(scene, primitive, cesium) {
|
|
|
328
388
|
const model = await mod.Model.fromGltfAsync({
|
|
329
389
|
url: primitive.uri,
|
|
330
390
|
modelMatrix: placementToModelMatrix(mod, placement),
|
|
391
|
+
...(primitive.attribution ? { credit: primitive.attribution } : {}),
|
|
331
392
|
});
|
|
332
|
-
|
|
333
|
-
|
|
393
|
+
try {
|
|
394
|
+
options.signal?.throwIfAborted();
|
|
395
|
+
scene.primitives.add(model);
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
destroyOwnedCesiumPrimitive(model);
|
|
399
|
+
throw error;
|
|
400
|
+
}
|
|
401
|
+
return makeLayerHandle(scene, primitive.id, model, primitive.format, mod);
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Destroy an adapter-owned tileset/model exactly once. Cesium's
|
|
405
|
+
* `PrimitiveCollection.remove` normally destroys what it removes, but a
|
|
406
|
+
* collection configured with `destroyPrimitives = false` — and any failure
|
|
407
|
+
* before the primitive reaches a collection at all — would otherwise leak it.
|
|
408
|
+
*/
|
|
409
|
+
function destroyOwnedCesiumPrimitive(primitive) {
|
|
410
|
+
if (typeof primitive.destroy === "function" && primitive.isDestroyed?.() !== true)
|
|
411
|
+
primitive.destroy();
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Fail closed on an unrenderable model layer *before* the optional Cesium peer
|
|
415
|
+
* is loaded, mirroring {@link addCesiumImageryLayer}. A missing/invalid/signed
|
|
416
|
+
* asset URI, an impossible placement, or out-of-range point-cloud shading must
|
|
417
|
+
* never reach a Cesium factory: `Cesium3DTileset.fromUrl("")` throws opaquely
|
|
418
|
+
* and `Cartesian3.fromDegrees(NaN, …)` produces a silently broken model matrix.
|
|
419
|
+
*/
|
|
420
|
+
function assertRenderableModelLayer(primitive) {
|
|
421
|
+
const validation = diagnoseScenePrimitives([primitive], CESIUM_SCENE_CAPABILITIES).find((diagnostic) => diagnostic.status === "unsupported");
|
|
422
|
+
if (validation)
|
|
423
|
+
throw new Error(`${validation.code}: ${validation.message}`);
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Fail closed on an unrenderable elevation source *before* the scene's terrain
|
|
427
|
+
* provider or vertical exaggeration is touched, mirroring
|
|
428
|
+
* {@link assertRenderableModelLayer}.
|
|
429
|
+
*
|
|
430
|
+
* Every terrain protocol reaches Cesium through `CesiumTerrainProvider.fromUrl`,
|
|
431
|
+
* which rejects opaquely on a missing or malformed endpoint — and an elevation
|
|
432
|
+
* source in an unhonorable CRS or vertical datum would place the whole globe's
|
|
433
|
+
* heights wrong while reporting success. Neither may reach a live scene.
|
|
434
|
+
*/
|
|
435
|
+
function assertRenderableTerrain(primitive) {
|
|
436
|
+
const validation = diagnoseScenePrimitives([primitive], CESIUM_SCENE_CAPABILITIES).find((diagnostic) => diagnostic.status === "unsupported");
|
|
437
|
+
if (validation)
|
|
438
|
+
throw new Error(`${validation.code}: ${validation.message}`);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Project validated point-cloud shading onto Cesium's `PointCloudShading`
|
|
442
|
+
* option bag, dropping absent fields so Cesium keeps its own defaults instead
|
|
443
|
+
* of receiving explicit `undefined`s. Returns `undefined` when nothing is set.
|
|
444
|
+
*/
|
|
445
|
+
function normalizePointCloudShading(shading) {
|
|
446
|
+
if (!shading)
|
|
447
|
+
return undefined;
|
|
448
|
+
const options = {};
|
|
449
|
+
if (shading.attenuation !== undefined)
|
|
450
|
+
options.attenuation = shading.attenuation;
|
|
451
|
+
if (shading.maximumAttenuation !== undefined)
|
|
452
|
+
options.maximumAttenuation = shading.maximumAttenuation;
|
|
453
|
+
if (shading.geometricErrorScale !== undefined)
|
|
454
|
+
options.geometricErrorScale = shading.geometricErrorScale;
|
|
455
|
+
if (shading.eyeDomeLighting !== undefined)
|
|
456
|
+
options.eyeDomeLighting = shading.eyeDomeLighting;
|
|
457
|
+
if (shading.eyeDomeLightingStrength !== undefined) {
|
|
458
|
+
options.eyeDomeLightingStrength = shading.eyeDomeLightingStrength;
|
|
459
|
+
}
|
|
460
|
+
if (shading.eyeDomeLightingRadius !== undefined)
|
|
461
|
+
options.eyeDomeLightingRadius = shading.eyeDomeLightingRadius;
|
|
462
|
+
return Object.keys(options).length > 0 ? options : undefined;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Materialize one renderer-neutral imagery primitive through Cesium's matching
|
|
466
|
+
* provider and add it to the scene's imagery collection.
|
|
467
|
+
*
|
|
468
|
+
* The returned handle owns the provider and layer it creates. Removal is
|
|
469
|
+
* idempotent, releases the layer's GPU resources through Cesium, and calls an
|
|
470
|
+
* optional provider `destroy()` exactly once.
|
|
471
|
+
*/
|
|
472
|
+
export async function addCesiumImageryLayer(scene, primitive, cesium, options = {}) {
|
|
473
|
+
const validation = diagnoseScenePrimitives([primitive], CESIUM_SCENE_CAPABILITIES).find((diagnostic) => diagnostic.status === "unsupported");
|
|
474
|
+
if (validation)
|
|
475
|
+
throw new Error(`${validation.code}: ${validation.message}`);
|
|
476
|
+
if (!scene.imageryLayers) {
|
|
477
|
+
throw new Error("scene-primitive-imagery-target-missing: Cesium imageryLayers unavailable.");
|
|
478
|
+
}
|
|
479
|
+
options.signal?.throwIfAborted();
|
|
480
|
+
const mod = cesium ?? (await loadCesium());
|
|
481
|
+
const provider = await createCesiumImageryProvider(primitive, mod);
|
|
482
|
+
let layer;
|
|
483
|
+
try {
|
|
484
|
+
options.signal?.throwIfAborted();
|
|
485
|
+
layer = scene.imageryLayers.addImageryProvider(provider);
|
|
486
|
+
layer.alpha = primitive.opacity ?? 1;
|
|
487
|
+
}
|
|
488
|
+
catch (error) {
|
|
489
|
+
if (layer && scene.imageryLayers.contains(layer))
|
|
490
|
+
scene.imageryLayers.remove(layer, true);
|
|
491
|
+
disposeCesiumImageryProvider(provider);
|
|
492
|
+
throw error;
|
|
493
|
+
}
|
|
494
|
+
let removed = false;
|
|
495
|
+
return {
|
|
496
|
+
id: primitive.id,
|
|
497
|
+
kind: "imagery-layer",
|
|
498
|
+
protocol: primitive.protocol,
|
|
499
|
+
setVisible(visible) {
|
|
500
|
+
if (!removed)
|
|
501
|
+
layer.show = visible;
|
|
502
|
+
},
|
|
503
|
+
setOpacity(opacity) {
|
|
504
|
+
if (!Number.isFinite(opacity) || opacity < 0 || opacity > 1) {
|
|
505
|
+
throw new RangeError("Imagery opacity must be a finite number between 0 and 1.");
|
|
506
|
+
}
|
|
507
|
+
if (!removed)
|
|
508
|
+
layer.alpha = opacity;
|
|
509
|
+
},
|
|
510
|
+
remove() {
|
|
511
|
+
if (removed)
|
|
512
|
+
return;
|
|
513
|
+
removed = true;
|
|
514
|
+
try {
|
|
515
|
+
if (scene.imageryLayers?.contains(layer))
|
|
516
|
+
scene.imageryLayers.remove(layer, true);
|
|
517
|
+
}
|
|
518
|
+
finally {
|
|
519
|
+
disposeCesiumImageryProvider(provider);
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
function disposeCesiumImageryProvider(provider) {
|
|
525
|
+
if (typeof provider.destroy === "function" && provider.isDestroyed?.() !== true)
|
|
526
|
+
provider.destroy();
|
|
527
|
+
}
|
|
528
|
+
async function createCesiumImageryProvider(primitive, cesium) {
|
|
529
|
+
const commonOptions = {
|
|
530
|
+
...(primitive.attribution ? { credit: primitive.attribution } : {}),
|
|
531
|
+
...(primitive.minimumLevel !== undefined ? { minimumLevel: primitive.minimumLevel } : {}),
|
|
532
|
+
...(primitive.maximumLevel !== undefined ? { maximumLevel: primitive.maximumLevel } : {}),
|
|
533
|
+
};
|
|
534
|
+
switch (primitive.protocol) {
|
|
535
|
+
case "url-template":
|
|
536
|
+
return new cesium.UrlTemplateImageryProvider({
|
|
537
|
+
url: urlWithServiceParameters(primitive.url, primitive.parameters),
|
|
538
|
+
...commonOptions,
|
|
539
|
+
...(primitive.subdomains ? { subdomains: primitive.subdomains } : {}),
|
|
540
|
+
});
|
|
541
|
+
case "wms":
|
|
542
|
+
return new cesium.WebMapServiceImageryProvider({
|
|
543
|
+
url: normalizedWmsUrl(primitive.url, primitive.parameters),
|
|
544
|
+
layers: primitive.layer,
|
|
545
|
+
...commonOptions,
|
|
546
|
+
...(primitive.subdomains ? { subdomains: primitive.subdomains } : {}),
|
|
547
|
+
...(primitive.parameters || primitive.format || primitive.style
|
|
548
|
+
? {
|
|
549
|
+
parameters: normalizedWmsParameters(primitive.parameters, primitive.format, primitive.style),
|
|
550
|
+
}
|
|
551
|
+
: {}),
|
|
552
|
+
});
|
|
553
|
+
case "wmts":
|
|
554
|
+
return new cesium.WebMapTileServiceImageryProvider({
|
|
555
|
+
url: normalizedWmtsUrl(primitive.url, primitive.parameters),
|
|
556
|
+
layer: primitive.layer,
|
|
557
|
+
style: primitive.style,
|
|
558
|
+
tileMatrixSetID: primitive.tileMatrixSetId,
|
|
559
|
+
format: primitive.format ?? "image/png",
|
|
560
|
+
...commonOptions,
|
|
561
|
+
...(primitive.subdomains ? { subdomains: primitive.subdomains } : {}),
|
|
562
|
+
...(primitive.parameters ? { dimensions: primitive.parameters } : {}),
|
|
563
|
+
});
|
|
564
|
+
case "single-tile":
|
|
565
|
+
return cesium.SingleTileImageryProvider.fromUrl(urlWithServiceParameters(resolveConfiguredSubdomainUrl(primitive), primitive.parameters), {
|
|
566
|
+
...(primitive.attribution ? { credit: primitive.attribution } : {}),
|
|
567
|
+
});
|
|
568
|
+
case "arcgis-imagery":
|
|
569
|
+
if (isArcGisImageServerUrl(primitive.url)) {
|
|
570
|
+
return new cesium.UrlTemplateImageryProvider({
|
|
571
|
+
url: arcGisImageServerExportUrl(primitive.url, primitive.parameters),
|
|
572
|
+
...commonOptions,
|
|
573
|
+
...(primitive.subdomains ? { subdomains: primitive.subdomains } : {}),
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
return cesium.ArcGisMapServerImageryProvider.fromUrl(urlWithoutQueryKeys(resolveConfiguredSubdomainUrl(primitive), [...ARCGIS_IMAGE_SERVER_RESERVED_PARAMETERS, "layers", ...Object.keys(primitive.parameters ?? {})], true), {
|
|
577
|
+
...commonOptions,
|
|
578
|
+
...arcGisMapServerOptions(primitive.parameters),
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
function resolveConfiguredSubdomainUrl(primitive) {
|
|
583
|
+
const subdomain = primitive.subdomains?.[0];
|
|
584
|
+
return subdomain === undefined ? primitive.url : primitive.url.replaceAll("{s}", subdomain);
|
|
585
|
+
}
|
|
586
|
+
function normalizedWmsUrl(url, parameters) {
|
|
587
|
+
return urlWithoutQueryKeys(url, [...WMS_PROVIDER_QUERY_KEYS, ...Object.keys(parameters ?? {})]);
|
|
588
|
+
}
|
|
589
|
+
function normalizedWmtsUrl(url, parameters) {
|
|
590
|
+
return urlWithoutQueryKeys(url, [...WMTS_PROVIDER_QUERY_KEYS, ...Object.keys(parameters ?? {})]);
|
|
591
|
+
}
|
|
592
|
+
function urlWithServiceParameters(url, parameters) {
|
|
593
|
+
const entries = Object.entries(parameters ?? {});
|
|
594
|
+
if (entries.length === 0)
|
|
595
|
+
return url;
|
|
596
|
+
const normalizedUrl = urlWithoutQueryKeys(url, entries.map(([key]) => key));
|
|
597
|
+
const hashIndex = normalizedUrl.indexOf("#");
|
|
598
|
+
const withoutFragment = hashIndex === -1 ? normalizedUrl : normalizedUrl.slice(0, hashIndex);
|
|
599
|
+
const fragment = hashIndex === -1 ? "" : normalizedUrl.slice(hashIndex);
|
|
600
|
+
const encodedParameters = entries
|
|
601
|
+
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`)
|
|
602
|
+
.join("&");
|
|
603
|
+
return `${withoutFragment}${withoutFragment.includes("?") ? "&" : "?"}${encodedParameters}${fragment}`;
|
|
604
|
+
}
|
|
605
|
+
function urlWithoutQueryKeys(url, keys, canonical = false) {
|
|
606
|
+
const overriddenKeys = new Set(keys.map((key) => (canonical ? key.toLowerCase().replaceAll(/[^a-z0-9]/g, "") : key.toLowerCase())));
|
|
607
|
+
const hashIndex = url.indexOf("#");
|
|
608
|
+
const withoutFragment = hashIndex === -1 ? url : url.slice(0, hashIndex);
|
|
609
|
+
const fragment = hashIndex === -1 ? "" : url.slice(hashIndex);
|
|
610
|
+
const queryIndex = withoutFragment.indexOf("?");
|
|
611
|
+
if (queryIndex === -1)
|
|
612
|
+
return url;
|
|
613
|
+
const endpoint = withoutFragment.slice(0, queryIndex);
|
|
614
|
+
const query = withoutFragment.slice(queryIndex + 1);
|
|
615
|
+
const preserved = query.split("&").filter((entry) => {
|
|
616
|
+
if (entry === "")
|
|
617
|
+
return false;
|
|
618
|
+
const separatorIndex = entry.indexOf("=");
|
|
619
|
+
const rawKey = separatorIndex === -1 ? entry : entry.slice(0, separatorIndex);
|
|
620
|
+
try {
|
|
621
|
+
const decodedKey = decodeURIComponent(rawKey.replaceAll("+", " ")).toLowerCase();
|
|
622
|
+
return !overriddenKeys.has(canonical ? decodedKey.replaceAll(/[^a-z0-9]/g, "") : decodedKey);
|
|
623
|
+
}
|
|
624
|
+
catch {
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
return `${endpoint}${preserved.length > 0 ? `?${preserved.join("&")}` : ""}${fragment}`;
|
|
629
|
+
}
|
|
630
|
+
function arcGisMapServerOptions(parameters) {
|
|
631
|
+
const options = {};
|
|
632
|
+
for (const [key, value] of Object.entries(parameters ?? {})) {
|
|
633
|
+
switch (key.toLowerCase().replaceAll(/[^a-z0-9]/g, "")) {
|
|
634
|
+
case "layers":
|
|
635
|
+
options.layers = normalizeArcGisMapServerLayers(value);
|
|
636
|
+
break;
|
|
637
|
+
case "enablepickfeatures":
|
|
638
|
+
options.enablePickFeatures = value;
|
|
639
|
+
break;
|
|
640
|
+
case "useprecachedtilesifavailable":
|
|
641
|
+
options.usePreCachedTilesIfAvailable = value;
|
|
642
|
+
break;
|
|
643
|
+
case "tilewidth":
|
|
644
|
+
options.tileWidth = value;
|
|
645
|
+
break;
|
|
646
|
+
case "tileheight":
|
|
647
|
+
options.tileHeight = value;
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return options;
|
|
652
|
+
}
|
|
653
|
+
function normalizeArcGisMapServerLayers(value) {
|
|
654
|
+
const trimmed = String(value).trim();
|
|
655
|
+
const layerList = trimmed.toLowerCase().startsWith("show:") ? trimmed.slice(5) : trimmed;
|
|
656
|
+
return layerList
|
|
657
|
+
.split(",")
|
|
658
|
+
.map((layerId) => layerId.trim())
|
|
659
|
+
.join(",");
|
|
660
|
+
}
|
|
661
|
+
function normalizedWmsParameters(parameters, format, style) {
|
|
662
|
+
const entries = Object.entries(parameters ?? {}).filter(([key]) => key.toLowerCase() !== "layers" &&
|
|
663
|
+
(format === undefined || key.toLowerCase() !== "format") &&
|
|
664
|
+
(style === undefined || key.toLowerCase() !== "styles"));
|
|
665
|
+
return {
|
|
666
|
+
...Object.fromEntries(entries),
|
|
667
|
+
...(format !== undefined ? { format } : {}),
|
|
668
|
+
...(style !== undefined ? { styles: style } : {}),
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
function isArcGisImageServerUrl(url) {
|
|
672
|
+
const endpoint = url.split(/[?#]/, 1)[0] ?? "";
|
|
673
|
+
return trimTrailingSlashes(endpoint).toLowerCase().endsWith("/imageserver");
|
|
674
|
+
}
|
|
675
|
+
function arcGisImageServerExportUrl(url, parameters) {
|
|
676
|
+
const [withoutFragment] = url.split("#", 1);
|
|
677
|
+
const queryIndex = withoutFragment.indexOf("?");
|
|
678
|
+
const endpoint = trimTrailingSlashes(queryIndex === -1 ? withoutFragment : withoutFragment.slice(0, queryIndex));
|
|
679
|
+
const existingQuery = queryIndex === -1 ? "" : withoutFragment.slice(queryIndex + 1);
|
|
680
|
+
const primitiveParameters = new Map();
|
|
681
|
+
for (const [key, value] of Object.entries(parameters ?? {})) {
|
|
682
|
+
if (!ARCGIS_IMAGE_SERVER_RESERVED_PARAMETERS.has(key.toLowerCase())) {
|
|
683
|
+
primitiveParameters.set(key.toLowerCase(), [key, String(value)]);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
const preservedParameters = new URLSearchParams();
|
|
687
|
+
for (const [key, value] of new URLSearchParams(existingQuery)) {
|
|
688
|
+
const normalizedKey = key.toLowerCase();
|
|
689
|
+
if (!ARCGIS_IMAGE_SERVER_RESERVED_PARAMETERS.has(normalizedKey) && !primitiveParameters.has(normalizedKey)) {
|
|
690
|
+
preservedParameters.append(key, value);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
for (const [key, value] of primitiveParameters.values())
|
|
694
|
+
preservedParameters.set(key, value);
|
|
695
|
+
const requestParameters = [
|
|
696
|
+
"f=image",
|
|
697
|
+
"bbox={westProjected}%2C{southProjected}%2C{eastProjected}%2C{northProjected}",
|
|
698
|
+
"bboxSR=3857",
|
|
699
|
+
"imageSR=3857",
|
|
700
|
+
"size={width}%2C{height}",
|
|
701
|
+
"format=png32",
|
|
702
|
+
"transparent=true",
|
|
703
|
+
];
|
|
704
|
+
const preservedQuery = preservedParameters.toString();
|
|
705
|
+
return `${endpoint}/exportImage?${preservedQuery ? `${preservedQuery}&` : ""}${requestParameters.join("&")}`;
|
|
706
|
+
}
|
|
707
|
+
const ARCGIS_IMAGE_SERVER_RESERVED_PARAMETERS = new Set([
|
|
708
|
+
"f",
|
|
709
|
+
"bbox",
|
|
710
|
+
"bboxsr",
|
|
711
|
+
"imagesr",
|
|
712
|
+
"size",
|
|
713
|
+
"format",
|
|
714
|
+
"transparent",
|
|
715
|
+
]);
|
|
716
|
+
const WMS_PROVIDER_QUERY_KEYS = [
|
|
717
|
+
"bbox",
|
|
718
|
+
"crs",
|
|
719
|
+
"format",
|
|
720
|
+
"height",
|
|
721
|
+
"layers",
|
|
722
|
+
"request",
|
|
723
|
+
"service",
|
|
724
|
+
"srs",
|
|
725
|
+
"styles",
|
|
726
|
+
"transparent",
|
|
727
|
+
"version",
|
|
728
|
+
"width",
|
|
729
|
+
];
|
|
730
|
+
const WMTS_PROVIDER_QUERY_KEYS = [
|
|
731
|
+
"format",
|
|
732
|
+
"layer",
|
|
733
|
+
"request",
|
|
734
|
+
"service",
|
|
735
|
+
"style",
|
|
736
|
+
"tilecol",
|
|
737
|
+
"tilematrix",
|
|
738
|
+
"tilematrixset",
|
|
739
|
+
"tilematrixsetid",
|
|
740
|
+
"tilerow",
|
|
741
|
+
"version",
|
|
742
|
+
];
|
|
743
|
+
function trimTrailingSlashes(value) {
|
|
744
|
+
let end = value.length;
|
|
745
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47)
|
|
746
|
+
end -= 1;
|
|
747
|
+
return value.slice(0, end);
|
|
334
748
|
}
|
|
335
749
|
/**
|
|
336
750
|
* Wire a terrain provider from an elevation-source primitive onto the scene.
|
|
@@ -343,6 +757,11 @@ export async function addCesiumModel(scene, primitive, cesium) {
|
|
|
343
757
|
* is applied via the scene's `verticalExaggeration`.
|
|
344
758
|
*/
|
|
345
759
|
export async function applyCesiumTerrain(scene, primitive, cesium) {
|
|
760
|
+
return applyCesiumTerrainInternal(scene, primitive, cesium, true);
|
|
761
|
+
}
|
|
762
|
+
async function applyCesiumTerrainInternal(scene, primitive, cesium, disposePreviousProvider, signal) {
|
|
763
|
+
signal?.throwIfAborted();
|
|
764
|
+
assertRenderableTerrain(primitive);
|
|
346
765
|
const url = typeof primitive.url === "string" && primitive.url.trim() !== "" ? primitive.url : undefined;
|
|
347
766
|
if (primitive.exaggeration !== undefined && Number.isFinite(primitive.exaggeration)) {
|
|
348
767
|
scene.verticalExaggeration = primitive.exaggeration;
|
|
@@ -350,8 +769,21 @@ export async function applyCesiumTerrain(scene, primitive, cesium) {
|
|
|
350
769
|
if (!url)
|
|
351
770
|
return undefined;
|
|
352
771
|
const mod = cesium ?? (await loadCesium());
|
|
353
|
-
const provider = await mod.CesiumTerrainProvider.fromUrl(url);
|
|
772
|
+
const provider = await mod.CesiumTerrainProvider.fromUrl(url, primitive.attribution ? { credit: primitive.attribution } : {});
|
|
773
|
+
if (provider && typeof provider === "object")
|
|
774
|
+
ownedCesiumTerrainProviders.add(provider);
|
|
775
|
+
if (signal?.aborted) {
|
|
776
|
+
// The provider resolved into a scene the host has already abandoned. Release
|
|
777
|
+
// it here rather than installing it and relying on a rollback to notice.
|
|
778
|
+
disposeOwnedCesiumTerrainProvider(provider);
|
|
779
|
+
signal.throwIfAborted();
|
|
780
|
+
}
|
|
781
|
+
const previousProvider = scene.terrainProvider;
|
|
354
782
|
scene.terrainProvider = provider;
|
|
783
|
+
if (disposePreviousProvider && previousProvider && previousProvider !== provider) {
|
|
784
|
+
disposeOwnedCesiumTerrainProvider(previousProvider);
|
|
785
|
+
}
|
|
786
|
+
let removed = false;
|
|
355
787
|
return {
|
|
356
788
|
id: primitive.id,
|
|
357
789
|
kind: "elevation-source",
|
|
@@ -359,28 +791,69 @@ export async function applyCesiumTerrain(scene, primitive, cesium) {
|
|
|
359
791
|
/* terrain is always on once set; visibility is a no-op for the provider. */
|
|
360
792
|
},
|
|
361
793
|
remove() {
|
|
794
|
+
if (removed)
|
|
795
|
+
return;
|
|
362
796
|
// Only tear down if *this* handle's provider is still the active one. If a
|
|
363
797
|
// newer elevation source has since replaced `scene.terrainProvider`,
|
|
364
798
|
// removing this (now-stale) handle must be a no-op so we don't clobber the
|
|
365
799
|
// active terrain/exaggeration.
|
|
366
|
-
if (scene.terrainProvider !== provider)
|
|
800
|
+
if (scene.terrainProvider !== provider) {
|
|
801
|
+
disposeOwnedCesiumTerrainProvider(provider);
|
|
802
|
+
removed = true;
|
|
367
803
|
return;
|
|
804
|
+
}
|
|
368
805
|
scene.terrainProvider = undefined;
|
|
369
806
|
scene.verticalExaggeration = 1;
|
|
807
|
+
disposeOwnedCesiumTerrainProvider(provider);
|
|
808
|
+
removed = true;
|
|
370
809
|
},
|
|
371
810
|
};
|
|
372
811
|
}
|
|
373
|
-
|
|
812
|
+
/**
|
|
813
|
+
* Wrap an adapter-owned tileset/model in a bounded handle.
|
|
814
|
+
*
|
|
815
|
+
* Ownership rules mirror {@link addCesiumImageryLayer}: `remove()` is idempotent
|
|
816
|
+
* and destroys the object exactly once (see
|
|
817
|
+
* {@link destroyOwnedCesiumPrimitive}), and post-removal control calls are
|
|
818
|
+
* no-ops rather than mutations of a destroyed object.
|
|
819
|
+
*
|
|
820
|
+
* `setOpacity` is only wired for glTF/GLB models, where `Model.color`'s alpha is
|
|
821
|
+
* the adapter-owned opacity channel. Tilesets omit it — see
|
|
822
|
+
* {@link CesiumLayerHandle}.
|
|
823
|
+
*/
|
|
824
|
+
function makeLayerHandle(scene, id, primitive, format, cesium) {
|
|
825
|
+
let removed = false;
|
|
826
|
+
const model = cesium && (format === "gltf" || format === "glb") ? primitive : undefined;
|
|
374
827
|
return {
|
|
375
828
|
id,
|
|
376
|
-
kind,
|
|
829
|
+
kind: "model-layer",
|
|
377
830
|
format,
|
|
378
831
|
setVisible(visible) {
|
|
379
|
-
|
|
832
|
+
if (!removed)
|
|
833
|
+
primitive.show = visible;
|
|
380
834
|
},
|
|
835
|
+
...(model && cesium
|
|
836
|
+
? {
|
|
837
|
+
setOpacity(opacity) {
|
|
838
|
+
if (!Number.isFinite(opacity) || opacity < 0 || opacity > 1) {
|
|
839
|
+
throw new RangeError("Model opacity must be a finite number between 0 and 1.");
|
|
840
|
+
}
|
|
841
|
+
if (!removed)
|
|
842
|
+
model.color = cesium.Color.WHITE.withAlpha(opacity);
|
|
843
|
+
},
|
|
844
|
+
}
|
|
845
|
+
: {}),
|
|
381
846
|
remove() {
|
|
382
|
-
if (
|
|
383
|
-
|
|
847
|
+
if (removed)
|
|
848
|
+
return;
|
|
849
|
+
removed = true;
|
|
850
|
+
try {
|
|
851
|
+
if (scene.primitives.contains(primitive))
|
|
852
|
+
scene.primitives.remove(primitive);
|
|
853
|
+
}
|
|
854
|
+
finally {
|
|
855
|
+
destroyOwnedCesiumPrimitive(primitive);
|
|
856
|
+
}
|
|
384
857
|
},
|
|
385
858
|
};
|
|
386
859
|
}
|
|
@@ -421,60 +894,272 @@ export function pickCesiumFeatureAttributes(scene, windowPosition) {
|
|
|
421
894
|
* As of #1197 this lands the full 3D stack against `target.scene`:
|
|
422
895
|
* - `camera` → `Camera.setView` (via the lazily-loaded `Cartesian3`).
|
|
423
896
|
* - `elevation-source` → `scene.terrainProvider` + `verticalExaggeration`.
|
|
897
|
+
* - `imagery-layer` → a protocol-specific provider added to `scene.imageryLayers`.
|
|
424
898
|
* - `model-layer` (`3d-tiles`) → `Cesium3DTileset.fromUrl` added to
|
|
425
899
|
* `scene.primitives`; (`gltf`/`glb`) → `Model.fromGltfAsync` placed by
|
|
426
900
|
* position/rotation/scale.
|
|
427
901
|
*
|
|
428
902
|
* Returns the diagnostics plus the live layer handles keyed by primitive id so
|
|
429
903
|
* callers can toggle visibility / tear layers down. Layer rendering is skipped
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
904
|
+
* when no `scene` is attached or when a primitive diagnoses as unsupported —
|
|
905
|
+
* and every skip is accounted for by a diagnostic, so nothing is silently
|
|
906
|
+
* dropped. Point clouds ride the 3D-Tiles path with optional
|
|
907
|
+
* `pointCloudShading`. I3S is declared-capable but unmaterialized, so it
|
|
908
|
+
* diagnoses `scene-primitive-model-format-not-materialized`; extrusions remain
|
|
909
|
+
* a MapLibre-path concern.
|
|
910
|
+
*
|
|
911
|
+
* As of #1048 `state` is load-bearing: its `timeline` slice is bound to the
|
|
912
|
+
* target's clock when the host opted into one (see
|
|
913
|
+
* {@link CesiumSceneRuntimeTarget}), and every arm — applied, host-owned,
|
|
914
|
+
* unbound, uninterpretable — reports itself as a `scene-time-*` diagnostic.
|
|
915
|
+
* Binding time constructs no renderer resource, so it never displaces a
|
|
916
|
+
* primitive: the mount's reuse diff is untouched by a moving clock.
|
|
434
917
|
*/
|
|
435
|
-
export async function applyCesiumScenePrimitives(target, primitives,
|
|
436
|
-
const
|
|
918
|
+
export async function applyCesiumScenePrimitives(target, primitives, state) {
|
|
919
|
+
const application = await applyCesiumScenePrimitivesInternal(target, primitives, {
|
|
920
|
+
...(state ? { state } : {}),
|
|
921
|
+
});
|
|
922
|
+
return {
|
|
923
|
+
status: application.status,
|
|
924
|
+
diagnostics: application.diagnostics,
|
|
925
|
+
layers: application.layers,
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Stable identity of a scene primitive within one mount: its kind and id.
|
|
930
|
+
*
|
|
931
|
+
* Identity is deliberately kind-qualified. Two primitives of different kinds may
|
|
932
|
+
* legitimately share an id (a terrain source and the imagery draped over it, for
|
|
933
|
+
* instance), and they own different renderer resources, so they must never be
|
|
934
|
+
* treated as revisions of one another.
|
|
935
|
+
*
|
|
936
|
+
* @internal
|
|
937
|
+
*/
|
|
938
|
+
export function scenePrimitiveMountKey(primitive) {
|
|
939
|
+
return `${primitive.kind}${primitive.id}`;
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* A stable, order-independent fingerprint of a primitive's configuration, used
|
|
943
|
+
* to decide whether a revised plan's primitive is the *same* binding as the one
|
|
944
|
+
* already mounted.
|
|
945
|
+
*
|
|
946
|
+
* Returns `undefined` when the primitive cannot be fingerprinted deterministically
|
|
947
|
+
* (a cycle, or a non-serializable value smuggled through `metadata`). An absent
|
|
948
|
+
* fingerprint means "assume changed": the binding is rebuilt rather than reused,
|
|
949
|
+
* which costs a rebuild but can never leave a stale renderer resource claiming to
|
|
950
|
+
* satisfy a plan it no longer matches.
|
|
951
|
+
*
|
|
952
|
+
* @internal
|
|
953
|
+
*/
|
|
954
|
+
export function scenePrimitiveFingerprint(primitive) {
|
|
955
|
+
try {
|
|
956
|
+
return stableStringify(primitive, new Set());
|
|
957
|
+
}
|
|
958
|
+
catch {
|
|
959
|
+
return undefined;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
function stableStringify(value, seen) {
|
|
963
|
+
if (value === undefined)
|
|
964
|
+
return "undefined";
|
|
965
|
+
if (value === null)
|
|
966
|
+
return "null";
|
|
967
|
+
if (typeof value === "function" || typeof value === "symbol") {
|
|
968
|
+
throw new TypeError("Scene primitives must be serializable to be fingerprinted.");
|
|
969
|
+
}
|
|
970
|
+
if (typeof value !== "object")
|
|
971
|
+
return JSON.stringify(value) ?? "undefined";
|
|
972
|
+
const container = value;
|
|
973
|
+
if (seen.has(container))
|
|
974
|
+
throw new TypeError("Scene primitives must be acyclic to be fingerprinted.");
|
|
975
|
+
seen.add(container);
|
|
976
|
+
try {
|
|
977
|
+
if (Array.isArray(value))
|
|
978
|
+
return `[${value.map((entry) => stableStringify(entry, seen)).join(",")}]`;
|
|
979
|
+
const entries = Object.entries(value)
|
|
980
|
+
.filter(([, entryValue]) => entryValue !== undefined)
|
|
981
|
+
.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));
|
|
982
|
+
return `{${entries.map(([key, entryValue]) => `${JSON.stringify(key)}:${stableStringify(entryValue, seen)}`).join(",")}}`;
|
|
983
|
+
}
|
|
984
|
+
finally {
|
|
985
|
+
seen.delete(container);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* The application engine behind both the one-shot
|
|
990
|
+
* {@link applyCesiumScenePrimitives} and the {@link CesiumLayerHandle}-owning
|
|
991
|
+
* mount lifecycle.
|
|
992
|
+
*
|
|
993
|
+
* Two properties hold regardless of how it is driven:
|
|
994
|
+
*
|
|
995
|
+
* - **Transactional.** Any failure — including an abort — removes every handle
|
|
996
|
+
* this application created, in reverse construction order, and restores the
|
|
997
|
+
* terrain provider, vertical exaggeration, and clock the scene had on entry.
|
|
998
|
+
* Handles carried in through `reuse` are never touched, so a failed revision
|
|
999
|
+
* leaves the previously applied plan intact.
|
|
1000
|
+
* - **Ownership-complete.** Every renderer resource it constructs is either
|
|
1001
|
+
* returned in `mounted` or destroyed before the call returns. Nothing is
|
|
1002
|
+
* reachable only from a discarded local.
|
|
1003
|
+
*
|
|
1004
|
+
* @internal
|
|
1005
|
+
*/
|
|
1006
|
+
export async function applyCesiumScenePrimitivesInternal(target, primitives, options = {}) {
|
|
1007
|
+
const { signal, reuse, state } = options;
|
|
1008
|
+
signal?.throwIfAborted();
|
|
1009
|
+
const diagnostics = [...diagnoseScenePrimitives(primitives, CESIUM_SCENE_CAPABILITIES)];
|
|
437
1010
|
const cesium = await loadCesium();
|
|
1011
|
+
signal?.throwIfAborted();
|
|
1012
|
+
// Time first: entity availability, time-dynamic tileset content, and clock-
|
|
1013
|
+
// driven properties are all evaluated against the clock, so a resource that
|
|
1014
|
+
// attaches below should attach under the application's own time rather than
|
|
1015
|
+
// under whatever instant the viewer happened to be showing.
|
|
1016
|
+
const time = applyCesiumSceneTime(target, state?.timeline, cesium);
|
|
1017
|
+
diagnostics.push(...time.diagnostics);
|
|
438
1018
|
const toCartesian = (longitude, latitude, height) => cesium.Cartesian3.fromDegrees(longitude, latitude, height);
|
|
439
|
-
const
|
|
1019
|
+
const unsupportedPrimitives = new Set(primitives.filter((primitive) => diagnoseScenePrimitives([primitive], CESIUM_SCENE_CAPABILITIES).some((diagnostic) => diagnostic.status === "unsupported")));
|
|
440
1020
|
const layers = new Map();
|
|
1021
|
+
const mounted = new Map();
|
|
1022
|
+
const created = [];
|
|
1023
|
+
const reused = [];
|
|
1024
|
+
const appliedHandles = [];
|
|
1025
|
+
const deferredTerrainProviders = [];
|
|
441
1026
|
const scene = target.scene;
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
1027
|
+
const originalTerrainProvider = scene?.terrainProvider;
|
|
1028
|
+
const originalVerticalExaggeration = scene?.verticalExaggeration;
|
|
1029
|
+
let terrainWasApplied = false;
|
|
1030
|
+
const registerHandle = (key, handle) => {
|
|
1031
|
+
appliedHandles.push(handle);
|
|
1032
|
+
layers.get(handle.id)?.remove();
|
|
1033
|
+
layers.set(handle.id, handle);
|
|
1034
|
+
mounted.set(key, handle);
|
|
1035
|
+
created.push(handle.id);
|
|
1036
|
+
};
|
|
1037
|
+
try {
|
|
1038
|
+
for (const primitive of primitives) {
|
|
1039
|
+
signal?.throwIfAborted();
|
|
1040
|
+
const key = scenePrimitiveMountKey(primitive);
|
|
1041
|
+
if (reuse?.has(key)) {
|
|
1042
|
+
// Unchanged since the last application: skip materialization entirely so
|
|
1043
|
+
// the live resource — and any visibility/opacity the host set on it —
|
|
1044
|
+
// survives the revision.
|
|
1045
|
+
const carried = reuse.get(key);
|
|
1046
|
+
mounted.set(key, carried);
|
|
1047
|
+
if (carried) {
|
|
1048
|
+
layers.set(carried.id, carried);
|
|
1049
|
+
reused.push(carried.id);
|
|
1050
|
+
}
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
if (primitive.kind === "camera") {
|
|
1054
|
+
applyCameraStateToCesiumCamera(target.camera, primitive.camera, toCartesian);
|
|
1055
|
+
mounted.set(key, undefined);
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
if (!scene || unsupportedPrimitives.has(primitive)) {
|
|
1059
|
+
mounted.set(key, undefined);
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
if (primitive.kind === "elevation-source") {
|
|
1063
|
+
const previousProvider = scene.terrainProvider;
|
|
1064
|
+
terrainWasApplied = true;
|
|
1065
|
+
const handle = await applyCesiumTerrainInternal(scene, primitive, cesium, false, signal);
|
|
1066
|
+
if (handle) {
|
|
1067
|
+
if (previousProvider && previousProvider !== scene.terrainProvider) {
|
|
1068
|
+
deferredTerrainProviders.push(previousProvider);
|
|
1069
|
+
}
|
|
1070
|
+
registerHandle(key, handle);
|
|
1071
|
+
}
|
|
1072
|
+
else {
|
|
1073
|
+
mounted.set(key, undefined);
|
|
1074
|
+
}
|
|
1075
|
+
continue;
|
|
1076
|
+
}
|
|
1077
|
+
if (primitive.kind === "imagery-layer") {
|
|
1078
|
+
if (!scene.imageryLayers) {
|
|
1079
|
+
diagnostics.push({
|
|
1080
|
+
code: "scene-primitive-imagery-target-missing",
|
|
1081
|
+
severity: "error",
|
|
1082
|
+
status: "unsupported",
|
|
1083
|
+
primitiveId: primitive.id,
|
|
1084
|
+
primitiveKind: primitive.kind,
|
|
1085
|
+
renderer: "cesium",
|
|
1086
|
+
message: "Cesium imageryLayers unavailable.",
|
|
1087
|
+
fallback: "Attach a complete Cesium scene target before applying imagery.",
|
|
1088
|
+
});
|
|
1089
|
+
mounted.set(key, undefined);
|
|
1090
|
+
continue;
|
|
1091
|
+
}
|
|
1092
|
+
registerHandle(key, await addCesiumImageryLayer(scene, primitive, cesium, { ...(signal ? { signal } : {}) }));
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
if (primitive.kind === "model-layer") {
|
|
1096
|
+
// Only materialized formats reach here: anything else already diagnosed
|
|
1097
|
+
// as unsupported above and was filtered into `unsupportedPrimitives`.
|
|
1098
|
+
const materializationOptions = { ...(signal ? { signal } : {}) };
|
|
1099
|
+
if (primitive.format === "3d-tiles") {
|
|
1100
|
+
registerHandle(key, await addCesium3DTileset(scene, primitive, cesium, materializationOptions));
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
registerHandle(key, await addCesiumModel(scene, primitive, cesium, materializationOptions));
|
|
1104
|
+
}
|
|
1105
|
+
continue;
|
|
1106
|
+
}
|
|
1107
|
+
mounted.set(key, undefined);
|
|
1108
|
+
}
|
|
1109
|
+
signal?.throwIfAborted();
|
|
1110
|
+
for (const provider of [...deferredTerrainProviders].reverse())
|
|
1111
|
+
disposeOwnedCesiumTerrainProvider(provider);
|
|
1112
|
+
}
|
|
1113
|
+
catch (cause) {
|
|
1114
|
+
const rollbackErrors = [];
|
|
1115
|
+
for (const handle of appliedHandles.reverse()) {
|
|
1116
|
+
try {
|
|
1117
|
+
handle.remove();
|
|
1118
|
+
}
|
|
1119
|
+
catch (error) {
|
|
1120
|
+
rollbackErrors.push(error);
|
|
1121
|
+
}
|
|
446
1122
|
}
|
|
447
|
-
if (
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
1123
|
+
if (scene && terrainWasApplied) {
|
|
1124
|
+
try {
|
|
1125
|
+
scene.terrainProvider = originalTerrainProvider;
|
|
1126
|
+
scene.verticalExaggeration = originalVerticalExaggeration;
|
|
1127
|
+
}
|
|
1128
|
+
catch (error) {
|
|
1129
|
+
rollbackErrors.push(error);
|
|
1130
|
+
}
|
|
454
1131
|
}
|
|
455
|
-
if (
|
|
456
|
-
|
|
457
|
-
|
|
1132
|
+
if (target.clock && time.previous) {
|
|
1133
|
+
try {
|
|
1134
|
+
restoreCesiumClock(target.clock, time.previous);
|
|
458
1135
|
}
|
|
459
|
-
|
|
460
|
-
|
|
1136
|
+
catch (error) {
|
|
1137
|
+
rollbackErrors.push(error);
|
|
461
1138
|
}
|
|
462
|
-
// i3s / obj / custom: declared-capable but not materialized here.
|
|
463
1139
|
}
|
|
1140
|
+
if (rollbackErrors.length > 0) {
|
|
1141
|
+
throw new AggregateError([cause, ...rollbackErrors], "Cesium scene primitive application failed and layer rollback was incomplete.", { cause });
|
|
1142
|
+
}
|
|
1143
|
+
throw cause;
|
|
464
1144
|
}
|
|
465
1145
|
return {
|
|
466
1146
|
status: summarizeDiagnosticStatus(diagnostics),
|
|
467
1147
|
diagnostics,
|
|
468
1148
|
layers,
|
|
1149
|
+
mounted,
|
|
1150
|
+
created,
|
|
1151
|
+
reused,
|
|
1152
|
+
time,
|
|
469
1153
|
};
|
|
470
1154
|
}
|
|
471
1155
|
/**
|
|
472
1156
|
* Create a {@link SceneRuntimeAdapter} backed by CesiumJS.
|
|
473
1157
|
*
|
|
474
1158
|
* When `options.target` (a live Cesium `Viewer`/`Scene` surface — a `camera`
|
|
475
|
-
* plus an optional `scene`) is supplied, `apply` drives
|
|
476
|
-
* sync plus, when a `scene` is attached, terrain
|
|
477
|
-
* and glTF/GLB model layers
|
|
1159
|
+
* plus an optional `scene` and an optional `clock`) is supplied, `apply` drives
|
|
1160
|
+
* the live globe: camera sync plus, when a `scene` is attached, terrain and
|
|
1161
|
+
* imagery providers, 3D-Tiles tilesets, and glTF/GLB model layers, and, when a
|
|
1162
|
+
* `clock` is attached, the workspace `timeline` slice. Without a target the adapter still
|
|
478
1163
|
* diagnoses primitives against Cesium's true-3D capabilities — useful for
|
|
479
1164
|
* migration analysis before a viewer exists. CesiumJS itself is only imported
|
|
480
1165
|
* lazily when `apply` runs.
|