@honua/app-platform 0.1.2-beta.0 → 0.1.7-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/app/index.d.ts.map +1 -1
- package/app/index.js +4 -0
- 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 +88 -19
- package/contract/types.d.ts.map +1 -1
- package/contract/types.js +4 -0
- 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 +51 -21
- package/core/client.d.ts.map +1 -1
- package/core/client.js +234 -54
- package/core/error-classifications.d.ts +23 -0
- package/core/error-classifications.d.ts.map +1 -1
- package/core/error-classifications.js +23 -0
- package/core/error-code-registry.d.ts +24 -1
- package/core/error-code-registry.d.ts.map +1 -1
- package/core/error-code-registry.js +23 -0
- package/core/error-envelope.js +2 -0
- package/core/errors.d.ts +2 -2
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +1 -1
- package/core/geoparquet-sql.d.ts +69 -5
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +327 -10
- 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 +32 -0
- package/core/stac.d.ts.map +1 -1
- package/core/stac.js +158 -23
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +273 -68
- package/core/types.d.ts +138 -11
- 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/interactions/declarative-contract.d.ts +149 -0
- package/interactions/declarative-contract.d.ts.map +1 -0
- package/interactions/declarative-contract.js +293 -0
- package/interactions/declarative.d.ts +198 -0
- package/interactions/declarative.d.ts.map +1 -0
- package/interactions/declarative.js +470 -0
- package/interactions/feature-state.d.ts +7 -0
- package/interactions/feature-state.d.ts.map +1 -1
- package/interactions/feature-state.js +10 -2
- 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/maplibre-target.js +1 -1
- 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/sse.js +7 -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/runtime/style-compose.d.ts.map +1 -1
- package/runtime/style-compose.js +78 -9
- 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
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 2D/3D camera correspondence.
|
|
3
|
+
*
|
|
4
|
+
* The renderer-neutral {@link SceneCameraState} is a globe pose: geodetic
|
|
5
|
+
* longitude/latitude, an ellipsoidal camera height in metres, and a
|
|
6
|
+
* heading/pitch/roll triple in degrees using Cesium's sign convention
|
|
7
|
+
* (`pitch = -90` looks straight down, `pitch = 0` looks at the horizon).
|
|
8
|
+
*
|
|
9
|
+
* A 2D web map does not carry a camera height at all — it carries a *zoom*,
|
|
10
|
+
* which is a statement about ground resolution. This module is the documented,
|
|
11
|
+
* unit-tested bridge between the two, so no consumer has to re-derive it. The
|
|
12
|
+
* Cesium half of the same correspondence lives in `cesium-adapter.ts`
|
|
13
|
+
* (`cameraStateToCesiumView` / `cesiumCameraToSceneState`), which needs no
|
|
14
|
+
* conversion because the workspace camera *is* a globe pose.
|
|
15
|
+
*
|
|
16
|
+
* ## The zoom/height relationship
|
|
17
|
+
*
|
|
18
|
+
* Zoom fixes the ground resolution of the projected plane:
|
|
19
|
+
*
|
|
20
|
+
* ```text
|
|
21
|
+
* groundResolution(zoom, lat) = C · cos(lat) / (tileSize · 2^zoom) [m/px]
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* where `C` is the WGS84 equatorial circumference. The 2D renderer places its
|
|
25
|
+
* perspective camera so the map centre fills the viewport at that resolution:
|
|
26
|
+
*
|
|
27
|
+
* ```text
|
|
28
|
+
* centreDistance(px) = 0.5 · viewportHeight / tan(fov / 2)
|
|
29
|
+
* centreDistance(m) = groundResolution · centreDistance(px)
|
|
30
|
+
* cameraHeight(m) = centreDistance(m) · cos(pitch2D)
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* The relationship is therefore **not** latitude-independent and **not**
|
|
34
|
+
* viewport-independent: the same zoom on a taller viewport puts the camera
|
|
35
|
+
* further away in metres, because more ground is on screen at the same
|
|
36
|
+
* resolution. Both halves are captured in {@link MapLibreCameraGeometry}, which
|
|
37
|
+
* a live port reads from the map it is bound to rather than assuming.
|
|
38
|
+
*
|
|
39
|
+
* ## What cannot round-trip
|
|
40
|
+
*
|
|
41
|
+
* A globe camera can hold poses a Web Mercator plane cannot express. Those are
|
|
42
|
+
* clamped and reported as {@link SceneCameraDegradation} entries rather than
|
|
43
|
+
* silently applied: latitudes beyond the Mercator limit, zooms outside the
|
|
44
|
+
* map's own range, pitches beyond the map's maximum, and a non-zero roll on a
|
|
45
|
+
* renderer that does not support roll. A projection that needed no clamping
|
|
46
|
+
* reports `exact` fidelity and round-trips to floating-point precision.
|
|
47
|
+
*
|
|
48
|
+
* @beta Part of the beta `@honua/app-platform/scene-workspace` surface.
|
|
49
|
+
* @module
|
|
50
|
+
*/
|
|
51
|
+
import type { SceneStateSyncFidelity } from "./state-sync.js";
|
|
52
|
+
import type { SceneCameraState } from "./types.js";
|
|
53
|
+
/** WGS84 equatorial circumference in metres (`2π · 6378137`). */
|
|
54
|
+
export declare const EARTH_CIRCUMFERENCE_METERS = 40075016.68557849;
|
|
55
|
+
/**
|
|
56
|
+
* The Web Mercator latitude limit in degrees. Beyond it the projection is
|
|
57
|
+
* undefined, so a globe camera over the poles has no 2D equivalent.
|
|
58
|
+
*/
|
|
59
|
+
export declare const WEB_MERCATOR_MAX_LATITUDE = 85.05112877980659;
|
|
60
|
+
/**
|
|
61
|
+
* The viewport and lens properties a 2D zoom is defined against.
|
|
62
|
+
*
|
|
63
|
+
* A live port reads these from the map it is bound to; the defaults describe a
|
|
64
|
+
* 600 CSS-pixel-tall viewport with the standard 512-pixel tile scheme and the
|
|
65
|
+
* renderer's default vertical field of view.
|
|
66
|
+
*/
|
|
67
|
+
export interface MapLibreCameraGeometry {
|
|
68
|
+
/** Viewport height in CSS pixels. */
|
|
69
|
+
readonly viewportHeightPixels: number;
|
|
70
|
+
/** Vertical field of view in radians. */
|
|
71
|
+
readonly fovRadians: number;
|
|
72
|
+
/** Tile edge length in pixels the zoom scale is defined against. */
|
|
73
|
+
readonly tileSizePixels: number;
|
|
74
|
+
}
|
|
75
|
+
/** Documented defaults for {@link MapLibreCameraGeometry}. */
|
|
76
|
+
export declare const DEFAULT_MAPLIBRE_CAMERA_GEOMETRY: MapLibreCameraGeometry;
|
|
77
|
+
/** What a 2D map will actually accept; anything outside it is clamped. */
|
|
78
|
+
export interface MapLibreCameraLimits {
|
|
79
|
+
readonly minZoom: number;
|
|
80
|
+
readonly maxZoom: number;
|
|
81
|
+
readonly maxPitch: number;
|
|
82
|
+
/** Whether the renderer can express a non-zero roll. */
|
|
83
|
+
readonly rollSupported: boolean;
|
|
84
|
+
}
|
|
85
|
+
/** Documented defaults for {@link MapLibreCameraLimits}. */
|
|
86
|
+
export declare const DEFAULT_MAPLIBRE_CAMERA_LIMITS: MapLibreCameraLimits;
|
|
87
|
+
/** A 2D map camera: centre, zoom, and screen orientation, all in degrees. */
|
|
88
|
+
export interface MapLibreCameraView {
|
|
89
|
+
readonly center: readonly [number, number];
|
|
90
|
+
readonly zoom: number;
|
|
91
|
+
/** Compass direction that is "up", clockwise from north — the same convention as a globe heading. */
|
|
92
|
+
readonly bearing: number;
|
|
93
|
+
/** Tilt in degrees where `0` looks straight down. */
|
|
94
|
+
readonly pitch: number;
|
|
95
|
+
readonly roll: number;
|
|
96
|
+
}
|
|
97
|
+
export type SceneCameraDegradationCode = "camera-latitude-clamped" | "camera-zoom-clamped" | "camera-pitch-clamped" | "camera-roll-dropped";
|
|
98
|
+
/** One named way a globe pose failed to survive projection onto a 2D map. */
|
|
99
|
+
export interface SceneCameraDegradation {
|
|
100
|
+
readonly code: SceneCameraDegradationCode;
|
|
101
|
+
readonly message: string;
|
|
102
|
+
readonly requested: number;
|
|
103
|
+
readonly applied: number;
|
|
104
|
+
}
|
|
105
|
+
/** A projected 2D view plus the honest account of what projecting it cost. */
|
|
106
|
+
export interface MapLibreCameraProjection {
|
|
107
|
+
readonly view: MapLibreCameraView;
|
|
108
|
+
/** `exact` when nothing was clamped or dropped, `equivalent` otherwise. */
|
|
109
|
+
readonly fidelity: SceneStateSyncFidelity;
|
|
110
|
+
readonly degradations: readonly SceneCameraDegradation[];
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Ground resolution in metres per CSS pixel at a zoom and latitude.
|
|
114
|
+
*
|
|
115
|
+
* This is the definition of zoom, and the only part of the correspondence that
|
|
116
|
+
* is independent of the viewport and the lens.
|
|
117
|
+
*/
|
|
118
|
+
export declare function mapLibreGroundResolutionMeters(zoom: number, latitude: number, geometry?: MapLibreCameraGeometry): number;
|
|
119
|
+
/**
|
|
120
|
+
* Camera height in metres above the map centre for a 2D zoom.
|
|
121
|
+
*
|
|
122
|
+
* `pitchDegrees` is the 2D tilt (`0` = straight down), not the globe pitch.
|
|
123
|
+
*/
|
|
124
|
+
export declare function mapLibreZoomToCameraHeight(zoom: number, latitude: number, pitchDegrees?: number, geometry?: MapLibreCameraGeometry): number;
|
|
125
|
+
/**
|
|
126
|
+
* The inverse of {@link mapLibreZoomToCameraHeight}: the zoom whose camera sits
|
|
127
|
+
* `height` metres above the map centre. Unclamped — callers decide what their
|
|
128
|
+
* map will accept.
|
|
129
|
+
*/
|
|
130
|
+
export declare function mapLibreCameraHeightToZoom(height: number, latitude: number, pitchDegrees?: number, geometry?: MapLibreCameraGeometry): number;
|
|
131
|
+
/**
|
|
132
|
+
* Read a 2D map view as a renderer-neutral globe pose.
|
|
133
|
+
*
|
|
134
|
+
* Always lossless in this direction: every 2D view is a valid globe pose. The
|
|
135
|
+
* pitch convention flips (`pitch2D = 0` looks down, which is `pitch = -90` on
|
|
136
|
+
* the globe) and the bearing is the heading unchanged.
|
|
137
|
+
*/
|
|
138
|
+
export declare function mapLibreViewToSceneCamera(view: MapLibreCameraView, geometry?: MapLibreCameraGeometry): SceneCameraState;
|
|
139
|
+
/**
|
|
140
|
+
* Project a globe pose onto a 2D map view, clamping what the plane cannot hold
|
|
141
|
+
* and naming every clamp.
|
|
142
|
+
*
|
|
143
|
+
* The caller is expected to apply `view` and surface `degradations`; the shared
|
|
144
|
+
* state is deliberately left alone, because writing the clamped pose back would
|
|
145
|
+
* drag the 3D view down to the 2D renderer's limits.
|
|
146
|
+
*/
|
|
147
|
+
export declare function sceneCameraToMapLibreView(camera: SceneCameraState, options?: {
|
|
148
|
+
readonly geometry?: MapLibreCameraGeometry;
|
|
149
|
+
readonly limits?: MapLibreCameraLimits;
|
|
150
|
+
}): MapLibreCameraProjection;
|
|
151
|
+
//# sourceMappingURL=camera-correspondence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"camera-correspondence.d.ts","sourceRoot":"","sources":["../../../src/scene-workspace/camera-correspondence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,iEAAiE;AACjE,eAAO,MAAM,0BAA0B,oBAAwB,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,yBAAyB,oBAAwB,CAAC;AAE/D;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,qCAAqC;IACrC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,yCAAyC;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,8DAA8D;AAC9D,eAAO,MAAM,gCAAgC,EAAE,sBAI7C,CAAC;AAEH,0EAA0E;AAC1E,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAED,4DAA4D;AAC5D,eAAO,MAAM,8BAA8B,EAAE,oBAK3C,CAAC;AAEH,6EAA6E;AAC7E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qGAAqG;IACrG,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,qDAAqD;IACrD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,0BAA0B,GAClC,yBAAyB,GACzB,qBAAqB,GACrB,sBAAsB,GACtB,qBAAqB,CAAC;AAE1B,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,8EAA8E;AAC9E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAC1D;AAMD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,sBAAyD,GAClE,MAAM,CAIR;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,YAAY,SAAI,EAChB,QAAQ,GAAE,sBAAyD,GAClE,MAAM,CAIR;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,SAAI,EAChB,QAAQ,GAAE,sBAAyD,GAClE,MAAM,CAOR;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,kBAAkB,EACxB,QAAQ,GAAE,sBAAyD,GAClE,gBAAgB,CAYlB;AAED;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;IACP,QAAQ,CAAC,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAC3C,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CACnC,GACL,wBAAwB,CAyE1B"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 2D/3D camera correspondence.
|
|
3
|
+
*
|
|
4
|
+
* The renderer-neutral {@link SceneCameraState} is a globe pose: geodetic
|
|
5
|
+
* longitude/latitude, an ellipsoidal camera height in metres, and a
|
|
6
|
+
* heading/pitch/roll triple in degrees using Cesium's sign convention
|
|
7
|
+
* (`pitch = -90` looks straight down, `pitch = 0` looks at the horizon).
|
|
8
|
+
*
|
|
9
|
+
* A 2D web map does not carry a camera height at all — it carries a *zoom*,
|
|
10
|
+
* which is a statement about ground resolution. This module is the documented,
|
|
11
|
+
* unit-tested bridge between the two, so no consumer has to re-derive it. The
|
|
12
|
+
* Cesium half of the same correspondence lives in `cesium-adapter.ts`
|
|
13
|
+
* (`cameraStateToCesiumView` / `cesiumCameraToSceneState`), which needs no
|
|
14
|
+
* conversion because the workspace camera *is* a globe pose.
|
|
15
|
+
*
|
|
16
|
+
* ## The zoom/height relationship
|
|
17
|
+
*
|
|
18
|
+
* Zoom fixes the ground resolution of the projected plane:
|
|
19
|
+
*
|
|
20
|
+
* ```text
|
|
21
|
+
* groundResolution(zoom, lat) = C · cos(lat) / (tileSize · 2^zoom) [m/px]
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* where `C` is the WGS84 equatorial circumference. The 2D renderer places its
|
|
25
|
+
* perspective camera so the map centre fills the viewport at that resolution:
|
|
26
|
+
*
|
|
27
|
+
* ```text
|
|
28
|
+
* centreDistance(px) = 0.5 · viewportHeight / tan(fov / 2)
|
|
29
|
+
* centreDistance(m) = groundResolution · centreDistance(px)
|
|
30
|
+
* cameraHeight(m) = centreDistance(m) · cos(pitch2D)
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* The relationship is therefore **not** latitude-independent and **not**
|
|
34
|
+
* viewport-independent: the same zoom on a taller viewport puts the camera
|
|
35
|
+
* further away in metres, because more ground is on screen at the same
|
|
36
|
+
* resolution. Both halves are captured in {@link MapLibreCameraGeometry}, which
|
|
37
|
+
* a live port reads from the map it is bound to rather than assuming.
|
|
38
|
+
*
|
|
39
|
+
* ## What cannot round-trip
|
|
40
|
+
*
|
|
41
|
+
* A globe camera can hold poses a Web Mercator plane cannot express. Those are
|
|
42
|
+
* clamped and reported as {@link SceneCameraDegradation} entries rather than
|
|
43
|
+
* silently applied: latitudes beyond the Mercator limit, zooms outside the
|
|
44
|
+
* map's own range, pitches beyond the map's maximum, and a non-zero roll on a
|
|
45
|
+
* renderer that does not support roll. A projection that needed no clamping
|
|
46
|
+
* reports `exact` fidelity and round-trips to floating-point precision.
|
|
47
|
+
*
|
|
48
|
+
* @beta Part of the beta `@honua/app-platform/scene-workspace` surface.
|
|
49
|
+
* @module
|
|
50
|
+
*/
|
|
51
|
+
/** WGS84 equatorial circumference in metres (`2π · 6378137`). */
|
|
52
|
+
export const EARTH_CIRCUMFERENCE_METERS = 40_075_016.685_578_49;
|
|
53
|
+
/**
|
|
54
|
+
* The Web Mercator latitude limit in degrees. Beyond it the projection is
|
|
55
|
+
* undefined, so a globe camera over the poles has no 2D equivalent.
|
|
56
|
+
*/
|
|
57
|
+
export const WEB_MERCATOR_MAX_LATITUDE = 85.051_128_779_806_59;
|
|
58
|
+
/** Documented defaults for {@link MapLibreCameraGeometry}. */
|
|
59
|
+
export const DEFAULT_MAPLIBRE_CAMERA_GEOMETRY = Object.freeze({
|
|
60
|
+
viewportHeightPixels: 600,
|
|
61
|
+
fovRadians: 0.643_501_108_793_284_4,
|
|
62
|
+
tileSizePixels: 512,
|
|
63
|
+
});
|
|
64
|
+
/** Documented defaults for {@link MapLibreCameraLimits}. */
|
|
65
|
+
export const DEFAULT_MAPLIBRE_CAMERA_LIMITS = Object.freeze({
|
|
66
|
+
minZoom: 0,
|
|
67
|
+
maxZoom: 22,
|
|
68
|
+
maxPitch: 60,
|
|
69
|
+
rollSupported: false,
|
|
70
|
+
});
|
|
71
|
+
const DEG2RAD = Math.PI / 180;
|
|
72
|
+
/** Smallest camera height treated as physical, so the inverse never divides by zero. */
|
|
73
|
+
const MIN_CAMERA_HEIGHT_METERS = 1e-3;
|
|
74
|
+
/**
|
|
75
|
+
* Ground resolution in metres per CSS pixel at a zoom and latitude.
|
|
76
|
+
*
|
|
77
|
+
* This is the definition of zoom, and the only part of the correspondence that
|
|
78
|
+
* is independent of the viewport and the lens.
|
|
79
|
+
*/
|
|
80
|
+
export function mapLibreGroundResolutionMeters(zoom, latitude, geometry = DEFAULT_MAPLIBRE_CAMERA_GEOMETRY) {
|
|
81
|
+
const normalized = normalizeGeometry(geometry);
|
|
82
|
+
const cosine = Math.cos(clampLatitude(latitude) * DEG2RAD);
|
|
83
|
+
return (EARTH_CIRCUMFERENCE_METERS * cosine) / (normalized.tileSizePixels * 2 ** zoom);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Camera height in metres above the map centre for a 2D zoom.
|
|
87
|
+
*
|
|
88
|
+
* `pitchDegrees` is the 2D tilt (`0` = straight down), not the globe pitch.
|
|
89
|
+
*/
|
|
90
|
+
export function mapLibreZoomToCameraHeight(zoom, latitude, pitchDegrees = 0, geometry = DEFAULT_MAPLIBRE_CAMERA_GEOMETRY) {
|
|
91
|
+
const normalized = normalizeGeometry(geometry);
|
|
92
|
+
const distance = mapLibreGroundResolutionMeters(zoom, latitude, normalized) * centerDistancePixels(normalized);
|
|
93
|
+
return Math.max(MIN_CAMERA_HEIGHT_METERS, distance * Math.cos(clampPitch(pitchDegrees) * DEG2RAD));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The inverse of {@link mapLibreZoomToCameraHeight}: the zoom whose camera sits
|
|
97
|
+
* `height` metres above the map centre. Unclamped — callers decide what their
|
|
98
|
+
* map will accept.
|
|
99
|
+
*/
|
|
100
|
+
export function mapLibreCameraHeightToZoom(height, latitude, pitchDegrees = 0, geometry = DEFAULT_MAPLIBRE_CAMERA_GEOMETRY) {
|
|
101
|
+
const normalized = normalizeGeometry(geometry);
|
|
102
|
+
const safeHeight = Math.max(MIN_CAMERA_HEIGHT_METERS, finite(height, MIN_CAMERA_HEIGHT_METERS));
|
|
103
|
+
const distance = safeHeight / Math.cos(clampPitch(pitchDegrees) * DEG2RAD);
|
|
104
|
+
const resolution = distance / centerDistancePixels(normalized);
|
|
105
|
+
const cosine = Math.cos(clampLatitude(latitude) * DEG2RAD);
|
|
106
|
+
return Math.log2((EARTH_CIRCUMFERENCE_METERS * cosine) / (normalized.tileSizePixels * resolution));
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Read a 2D map view as a renderer-neutral globe pose.
|
|
110
|
+
*
|
|
111
|
+
* Always lossless in this direction: every 2D view is a valid globe pose. The
|
|
112
|
+
* pitch convention flips (`pitch2D = 0` looks down, which is `pitch = -90` on
|
|
113
|
+
* the globe) and the bearing is the heading unchanged.
|
|
114
|
+
*/
|
|
115
|
+
export function mapLibreViewToSceneCamera(view, geometry = DEFAULT_MAPLIBRE_CAMERA_GEOMETRY) {
|
|
116
|
+
const longitude = wrapLongitude(finite(view.center[0], 0));
|
|
117
|
+
const latitude = clampLatitude(finite(view.center[1], 0));
|
|
118
|
+
const pitch = clampPitch(finite(view.pitch, 0));
|
|
119
|
+
return Object.freeze({
|
|
120
|
+
longitude,
|
|
121
|
+
latitude,
|
|
122
|
+
height: mapLibreZoomToCameraHeight(finite(view.zoom, 0), latitude, pitch, geometry),
|
|
123
|
+
heading: wrapDegrees(finite(view.bearing, 0)),
|
|
124
|
+
pitch: pitch - 90,
|
|
125
|
+
roll: wrapSignedDegrees(finite(view.roll, 0)),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Project a globe pose onto a 2D map view, clamping what the plane cannot hold
|
|
130
|
+
* and naming every clamp.
|
|
131
|
+
*
|
|
132
|
+
* The caller is expected to apply `view` and surface `degradations`; the shared
|
|
133
|
+
* state is deliberately left alone, because writing the clamped pose back would
|
|
134
|
+
* drag the 3D view down to the 2D renderer's limits.
|
|
135
|
+
*/
|
|
136
|
+
export function sceneCameraToMapLibreView(camera, options = {}) {
|
|
137
|
+
const geometry = normalizeGeometry(options.geometry ?? DEFAULT_MAPLIBRE_CAMERA_GEOMETRY);
|
|
138
|
+
const limits = normalizeLimits(options.limits ?? DEFAULT_MAPLIBRE_CAMERA_LIMITS);
|
|
139
|
+
const degradations = [];
|
|
140
|
+
const requestedLatitude = finite(camera.latitude, 0);
|
|
141
|
+
const latitude = clampLatitude(requestedLatitude);
|
|
142
|
+
if (Math.abs(requestedLatitude - latitude) > 1e-9) {
|
|
143
|
+
degradations.push(degradation("camera-latitude-clamped", "Latitude is beyond the Web Mercator limit and was clamped; the 2D plane cannot reach the poles.", requestedLatitude, latitude));
|
|
144
|
+
}
|
|
145
|
+
const requestedPitch = finite(camera.pitch ?? -90, -90) + 90;
|
|
146
|
+
const pitch = Math.min(Math.max(requestedPitch, 0), limits.maxPitch);
|
|
147
|
+
if (Math.abs(requestedPitch - pitch) > 1e-9) {
|
|
148
|
+
degradations.push(degradation("camera-pitch-clamped", "Globe pitch exceeds the 2D map's maximum tilt and was clamped.", requestedPitch, pitch));
|
|
149
|
+
}
|
|
150
|
+
const requestedZoom = mapLibreCameraHeightToZoom(Math.max(finite(camera.height, MIN_CAMERA_HEIGHT_METERS), MIN_CAMERA_HEIGHT_METERS), latitude, pitch, geometry);
|
|
151
|
+
const zoom = Math.min(Math.max(requestedZoom, limits.minZoom), limits.maxZoom);
|
|
152
|
+
if (Math.abs(requestedZoom - zoom) > 1e-9) {
|
|
153
|
+
degradations.push(degradation("camera-zoom-clamped", "Camera height maps outside the 2D map's zoom range and was clamped.", requestedZoom, zoom));
|
|
154
|
+
}
|
|
155
|
+
const requestedRoll = wrapSignedDegrees(finite(camera.roll ?? 0, 0));
|
|
156
|
+
const roll = limits.rollSupported ? requestedRoll : 0;
|
|
157
|
+
if (!limits.rollSupported && Math.abs(requestedRoll) > 1e-9) {
|
|
158
|
+
degradations.push(degradation("camera-roll-dropped", "The 2D renderer cannot express camera roll; the globe's roll was dropped.", requestedRoll, 0));
|
|
159
|
+
}
|
|
160
|
+
return Object.freeze({
|
|
161
|
+
view: Object.freeze({
|
|
162
|
+
center: Object.freeze([wrapLongitude(finite(camera.longitude, 0)), latitude]),
|
|
163
|
+
zoom,
|
|
164
|
+
bearing: wrapDegrees(finite(camera.heading ?? 0, 0)),
|
|
165
|
+
pitch,
|
|
166
|
+
roll,
|
|
167
|
+
}),
|
|
168
|
+
fidelity: (degradations.length === 0 ? "exact" : "equivalent"),
|
|
169
|
+
degradations: Object.freeze(degradations),
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
function degradation(code, message, requested, applied) {
|
|
173
|
+
return Object.freeze({ code, message, requested, applied });
|
|
174
|
+
}
|
|
175
|
+
function centerDistancePixels(geometry) {
|
|
176
|
+
return (0.5 * geometry.viewportHeightPixels) / Math.tan(geometry.fovRadians / 2);
|
|
177
|
+
}
|
|
178
|
+
function normalizeGeometry(geometry) {
|
|
179
|
+
const viewportHeightPixels = positive(geometry?.viewportHeightPixels, DEFAULT_MAPLIBRE_CAMERA_GEOMETRY.viewportHeightPixels);
|
|
180
|
+
const tileSizePixels = positive(geometry?.tileSizePixels, DEFAULT_MAPLIBRE_CAMERA_GEOMETRY.tileSizePixels);
|
|
181
|
+
const fovRaw = positive(geometry?.fovRadians, DEFAULT_MAPLIBRE_CAMERA_GEOMETRY.fovRadians);
|
|
182
|
+
const fovRadians = fovRaw >= Math.PI ? DEFAULT_MAPLIBRE_CAMERA_GEOMETRY.fovRadians : fovRaw;
|
|
183
|
+
return { viewportHeightPixels, fovRadians, tileSizePixels };
|
|
184
|
+
}
|
|
185
|
+
function normalizeLimits(limits) {
|
|
186
|
+
const minZoom = finite(limits?.minZoom, DEFAULT_MAPLIBRE_CAMERA_LIMITS.minZoom);
|
|
187
|
+
const maxZoomRaw = finite(limits?.maxZoom, DEFAULT_MAPLIBRE_CAMERA_LIMITS.maxZoom);
|
|
188
|
+
return {
|
|
189
|
+
minZoom,
|
|
190
|
+
maxZoom: Math.max(minZoom, maxZoomRaw),
|
|
191
|
+
maxPitch: Math.min(Math.max(finite(limits?.maxPitch, DEFAULT_MAPLIBRE_CAMERA_LIMITS.maxPitch), 0), 89),
|
|
192
|
+
rollSupported: limits?.rollSupported === true,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function clampLatitude(latitude) {
|
|
196
|
+
return Math.min(Math.max(latitude, -WEB_MERCATOR_MAX_LATITUDE), WEB_MERCATOR_MAX_LATITUDE);
|
|
197
|
+
}
|
|
198
|
+
function clampPitch(pitch) {
|
|
199
|
+
return Math.min(Math.max(pitch, 0), 89);
|
|
200
|
+
}
|
|
201
|
+
function wrapLongitude(longitude) {
|
|
202
|
+
const wrapped = ((((longitude + 180) % 360) + 360) % 360) - 180;
|
|
203
|
+
return Object.is(wrapped, -0) ? 0 : wrapped;
|
|
204
|
+
}
|
|
205
|
+
/** Wrap into `[0, 360)`, matching the heading range the Cesium half normalizes to. */
|
|
206
|
+
function wrapDegrees(degrees) {
|
|
207
|
+
const wrapped = degrees % 360;
|
|
208
|
+
return wrapped < 0 ? wrapped + 360 : wrapped;
|
|
209
|
+
}
|
|
210
|
+
/** Wrap into `(-180, 180]`, the natural range for a signed roll. */
|
|
211
|
+
function wrapSignedDegrees(degrees) {
|
|
212
|
+
const wrapped = wrapDegrees(degrees);
|
|
213
|
+
return wrapped > 180 ? wrapped - 360 : wrapped;
|
|
214
|
+
}
|
|
215
|
+
function finite(value, fallback) {
|
|
216
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
217
|
+
}
|
|
218
|
+
function positive(value, fallback) {
|
|
219
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
220
|
+
}
|