@npm9912/v-map 0.1.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/LICENSE +21 -0
- package/README.md +185 -0
- package/dist/cjs/_commonjsHelpers-B83fTs8d.js +36 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
- package/dist/cjs/cesium-provider-BiFFyAl9.js +2598 -0
- package/dist/cjs/deck-provider-Ctq3Q8a1.js +47824 -0
- package/dist/cjs/geotiff-CEwvF9cG.js +47 -0
- package/dist/cjs/geotiff-source-RaNzzWkC.js +1522 -0
- package/dist/cjs/index-B1oGO1g-.js +10658 -0
- package/dist/cjs/index-B8LHqjyg.js +1765 -0
- package/dist/cjs/index-BIL4VsgP.js +310 -0
- package/dist/cjs/index-Blku2QY8.js +167 -0
- package/dist/cjs/index-CJvvX4yx.js +21 -0
- package/dist/cjs/index-CbVT-Con.js +699 -0
- package/dist/cjs/index-ISOEpMC3.js +20478 -0
- package/dist/cjs/index-JSwBbvGA.js +1621 -0
- package/dist/cjs/index.browser-DQhD8Jwl.js +6873 -0
- package/dist/cjs/index.cjs.js +2 -0
- package/dist/cjs/layer-extension-B_olS0rc.js +65 -0
- package/dist/cjs/leaflet-provider-DOqfs7g5.js +1815 -0
- package/dist/cjs/loader.cjs.js +13 -0
- package/dist/cjs/main-dist-7TykwFci.js +2655 -0
- package/dist/cjs/messages-D7h4m8Tx.js +186 -0
- package/dist/cjs/openlayers-provider-Dfeg6L4n.js +1604 -0
- package/dist/cjs/polygon-layer-B9PrN7vr.js +1300 -0
- package/dist/cjs/scenegraph-layer-DwNoxQdi.js +2530 -0
- package/dist/cjs/styleconfig-CVRqArk-.js +23 -0
- package/dist/cjs/v-map-builder.cjs.entry.js +3786 -0
- package/dist/cjs/v-map-layer-geojson_12.cjs.entry.js +40894 -0
- package/dist/cjs/v-map-layer-helper-iAzxAg9I.js +285 -0
- package/dist/cjs/v-map-layer-terrain-geotiff.cjs.entry.js +258 -0
- package/dist/cjs/v-map-layercontrol.cjs.entry.js +247 -0
- package/dist/cjs/v-map.cjs.js +25 -0
- package/dist/cjs/v-map.v-map-layer-osm.v-map-layergroup-BsXp3BoL.js +582 -0
- package/dist/cjs/v-map_3.cjs.entry.js +12 -0
- package/dist/collection/collection-manifest.json +30 -0
- package/dist/collection/components/v-map/v-map.css +3 -0
- package/dist/collection/components/v-map/v-map.js +467 -0
- package/dist/collection/components/v-map/v-map.test.js +33 -0
- package/dist/collection/components/v-map-builder/v-map-builder.css +1 -0
- package/dist/collection/components/v-map-builder/v-map-builder.js +913 -0
- package/dist/collection/components/v-map-builder/v-map-builder.test.js +56 -0
- package/dist/collection/components/v-map-layer-geojson/v-map-layer-geojson.js +862 -0
- package/dist/collection/components/v-map-layer-geojson/v-map-layer-geojson.test.js +42 -0
- package/dist/collection/components/v-map-layer-geotiff/v-map-layer-geotiff.css +4 -0
- package/dist/collection/components/v-map-layer-geotiff/v-map-layer-geotiff.js +500 -0
- package/dist/collection/components/v-map-layer-geotiff/v-map-layer-geotiff.test.js +38 -0
- package/dist/collection/components/v-map-layer-google/v-map-layer-google.css +1 -0
- package/dist/collection/components/v-map-layer-google/v-map-layer-google.js +442 -0
- package/dist/collection/components/v-map-layer-osm/error-api.test.js +108 -0
- package/dist/collection/components/v-map-layer-osm/v-map-layer-osm.css +4 -0
- package/dist/collection/components/v-map-layer-osm/v-map-layer-osm.js +311 -0
- package/dist/collection/components/v-map-layer-osm/v-map-layer-osm.test.js +36 -0
- package/dist/collection/components/v-map-layer-scatterplot/v-map-layer-scatterplot.css +1 -0
- package/dist/collection/components/v-map-layer-scatterplot/v-map-layer-scatterplot.js +305 -0
- package/dist/collection/components/v-map-layer-terrain/v-map-layer-terrain.css +3 -0
- package/dist/collection/components/v-map-layer-terrain/v-map-layer-terrain.js +548 -0
- package/dist/collection/components/v-map-layer-terrain/v-map-layer-terrain.test.js +36 -0
- package/dist/collection/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.css +3 -0
- package/dist/collection/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.js +735 -0
- package/dist/collection/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.test.js +42 -0
- package/dist/collection/components/v-map-layer-tile3d/v-map-layer-tile3d.css +3 -0
- package/dist/collection/components/v-map-layer-tile3d/v-map-layer-tile3d.js +449 -0
- package/dist/collection/components/v-map-layer-tile3d/v-map-layer-tile3d.test.js +50 -0
- package/dist/collection/components/v-map-layer-wcs/v-map-layer-wcs.css +1 -0
- package/dist/collection/components/v-map-layer-wcs/v-map-layer-wcs.js +448 -0
- package/dist/collection/components/v-map-layer-wcs/v-map-layer-wcs.test.js +39 -0
- package/dist/collection/components/v-map-layer-wfs/v-map-layer-wfs.css +1 -0
- package/dist/collection/components/v-map-layer-wfs/v-map-layer-wfs.js +489 -0
- package/dist/collection/components/v-map-layer-wfs/v-map-layer-wfs.test.js +43 -0
- package/dist/collection/components/v-map-layer-wkt/v-map-layer-wkt.css +1 -0
- package/dist/collection/components/v-map-layer-wkt/v-map-layer-wkt.js +811 -0
- package/dist/collection/components/v-map-layer-wkt/v-map-layer-wkt.test.js +34 -0
- package/dist/collection/components/v-map-layer-wms/v-map-layer-wms.css +1 -0
- package/dist/collection/components/v-map-layer-wms/v-map-layer-wms.js +453 -0
- package/dist/collection/components/v-map-layer-wms/v-map-layer-wms.test.js +36 -0
- package/dist/collection/components/v-map-layer-xyz/v-map-layer-xyz.css +1 -0
- package/dist/collection/components/v-map-layer-xyz/v-map-layer-xyz.js +331 -0
- package/dist/collection/components/v-map-layer-xyz/v-map-layer-xyz.test.js +28 -0
- package/dist/collection/components/v-map-layercontrol/v-map-layercontrol.css +74 -0
- package/dist/collection/components/v-map-layercontrol/v-map-layercontrol.js +277 -0
- package/dist/collection/components/v-map-layercontrol/v-map-layercontrol.test.js +134 -0
- package/dist/collection/components/v-map-layergroup/v-map-layergroup.css +4 -0
- package/dist/collection/components/v-map-layergroup/v-map-layergroup.js +212 -0
- package/dist/collection/components/v-map-layergroup/v-map-layergroup.test.js +39 -0
- package/dist/collection/components/v-map-style/v-map-style.css +38 -0
- package/dist/collection/components/v-map-style/v-map-style.js +492 -0
- package/dist/collection/components/v-map-style/v-map-style.unit.js +62 -0
- package/dist/collection/index.js +1 -0
- package/dist/collection/layer/v-map-layer-helper.js +281 -0
- package/dist/collection/layer/v-map-layer-helper.unit.js +234 -0
- package/dist/collection/lib/cesium-loader.js +58 -0
- package/dist/collection/lib/ensure-importmap.js +12 -0
- package/dist/collection/lib/ensure-importmap.unit.js +57 -0
- package/dist/collection/lib/versions.gen.js +6 -0
- package/dist/collection/lib/vstyle.js +8 -0
- package/dist/collection/map-provider/cesium/CesiumGeoTIFFTerrainProvider.js +285 -0
- package/dist/collection/map-provider/cesium/CesiumLayerGroups.js +159 -0
- package/dist/collection/map-provider/cesium/GeoTIFFImageryProvider.js +192 -0
- package/dist/collection/map-provider/cesium/GeoTIFFImageryProvider.test.js +57 -0
- package/dist/collection/map-provider/cesium/cesium-provider.js +1408 -0
- package/dist/collection/map-provider/cesium/i-layer.js +1 -0
- package/dist/collection/map-provider/cesium/layer-manager.js +467 -0
- package/dist/collection/map-provider/deck/DeckGLGeoTIFFLayer.js +483 -0
- package/dist/collection/map-provider/deck/DeckGLGeoTIFFTerrainLayer.js +410 -0
- package/dist/collection/map-provider/deck/LayerGroupWithModel.js +169 -0
- package/dist/collection/map-provider/deck/LayerGroups.js +192 -0
- package/dist/collection/map-provider/deck/LayerModel.js +1 -0
- package/dist/collection/map-provider/deck/RenderableGroup.js +1 -0
- package/dist/collection/map-provider/deck/deck-provider.js +1563 -0
- package/dist/collection/map-provider/geotiff/geotiff-source.js +172 -0
- package/dist/collection/map-provider/geotiff/utils/AABB2D.js +24 -0
- package/dist/collection/map-provider/geotiff/utils/BVHNode2D.js +166 -0
- package/dist/collection/map-provider/geotiff/utils/GeoTIFFTileProcessor.js +484 -0
- package/dist/collection/map-provider/geotiff/utils/Triangle.js +1 -0
- package/dist/collection/map-provider/geotiff/utils/Triangulation.js +321 -0
- package/dist/collection/map-provider/geotiff/utils/colormap-utils.js +190 -0
- package/dist/collection/map-provider/geotiff/utils/normalization-utils.js +122 -0
- package/dist/collection/map-provider/geotiff/utils/sampling-utils.js +108 -0
- package/dist/collection/map-provider/leaflet/GeoTIFFGridLayer.js +147 -0
- package/dist/collection/map-provider/leaflet/WCSGridLayer.js +124 -0
- package/dist/collection/map-provider/leaflet/google-map-tiles-layer.js +352 -0
- package/dist/collection/map-provider/leaflet/leaflet-helpers.js +94 -0
- package/dist/collection/map-provider/leaflet/leaflet-provider.js +1095 -0
- package/dist/collection/map-provider/ol/CustomGeoTiff.js +145 -0
- package/dist/collection/map-provider/ol/openlayers-helper.js +26 -0
- package/dist/collection/map-provider/ol/openlayers-provider.js +1427 -0
- package/dist/collection/map-provider/provider-factory.js +44 -0
- package/dist/collection/map-provider/provider-factory.unit.js +66 -0
- package/dist/collection/testing/browser-test-utils.js +49 -0
- package/dist/collection/testing/e2e-testing.js +122 -0
- package/dist/collection/testing/e2e-utils.js +70 -0
- package/dist/collection/testing/geotiff-test-server.js +100 -0
- package/dist/collection/testing/mocks/geostyler-lyrx-parser.js +12 -0
- package/dist/collection/testing/mocks/geostyler-mapbox-parser.js +12 -0
- package/dist/collection/testing/mocks/geostyler-qgis-parser.js +12 -0
- package/dist/collection/testing/mocks/geostyler-sld-parser.js +13 -0
- package/dist/collection/testing/mocks/geostyler-style.js +5 -0
- package/dist/collection/testing/setupTests.browser.js +1 -0
- package/dist/collection/testing/setupTests.stencil.js +20 -0
- package/dist/collection/testing/setupTests.vitest.js +59 -0
- package/dist/collection/testing/stencil-testing-wrapper.js +43 -0
- package/dist/collection/testing/styleMock.js +1 -0
- package/dist/collection/types/color.js +1 -0
- package/dist/collection/types/cssmode.js +1 -0
- package/dist/collection/types/flavour.js +1 -0
- package/dist/collection/types/layerconfig.js +1 -0
- package/dist/collection/types/lonlat.js +1 -0
- package/dist/collection/types/mapinitoptions.js +1 -0
- package/dist/collection/types/mapprovider.js +1 -0
- package/dist/collection/types/provideroptions.js +1 -0
- package/dist/collection/types/styleconfig.js +19 -0
- package/dist/collection/types/styling.js +13 -0
- package/dist/collection/types/styling.unit.js +37 -0
- package/dist/collection/types/vmaplayer.js +1 -0
- package/dist/collection/utils/async-mutex.js +28 -0
- package/dist/collection/utils/diff.js +142 -0
- package/dist/collection/utils/diff.unit.js +59 -0
- package/dist/collection/utils/dom-env.js +43 -0
- package/dist/collection/utils/dom-env.unit.js +92 -0
- package/dist/collection/utils/events.js +8 -0
- package/dist/collection/utils/logger.js +183 -0
- package/dist/collection/utils/logger.unit.js +98 -0
- package/dist/collection/utils/messages.js +12 -0
- package/dist/collection/utils/spatial-utils.js +27 -0
- package/dist/collection/utils/spatial-utils.unit.js +24 -0
- package/dist/components/_commonjsHelpers.js +1 -0
- package/dist/components/cesium-provider.js +1 -0
- package/dist/components/deck-provider.js +1 -0
- package/dist/components/events.js +1 -0
- package/dist/components/geotiff-source.js +1 -0
- package/dist/components/geotiff.js +4 -0
- package/dist/components/index.browser.js +15 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +1 -0
- package/dist/components/index2.js +1 -0
- package/dist/components/index3.js +1 -0
- package/dist/components/index4.js +1 -0
- package/dist/components/index5.js +1 -0
- package/dist/components/index6.js +1 -0
- package/dist/components/index7.js +1 -0
- package/dist/components/index8.js +7 -0
- package/dist/components/layer-extension.js +1 -0
- package/dist/components/leaflet-provider.js +1 -0
- package/dist/components/main-dist.js +1 -0
- package/dist/components/messages.js +1 -0
- package/dist/components/openlayers-provider.js +1 -0
- package/dist/components/polygon-layer.js +1 -0
- package/dist/components/scenegraph-layer.js +1 -0
- package/dist/components/styleconfig.js +1 -0
- package/dist/components/styling.js +1 -0
- package/dist/components/v-map-builder.d.ts +11 -0
- package/dist/components/v-map-builder.js +2 -0
- package/dist/components/v-map-layer-geojson.d.ts +11 -0
- package/dist/components/v-map-layer-geojson.js +1 -0
- package/dist/components/v-map-layer-geojson2.js +1 -0
- package/dist/components/v-map-layer-geotiff.d.ts +11 -0
- package/dist/components/v-map-layer-geotiff.js +1 -0
- package/dist/components/v-map-layer-geotiff2.js +1 -0
- package/dist/components/v-map-layer-google.d.ts +11 -0
- package/dist/components/v-map-layer-google.js +1 -0
- package/dist/components/v-map-layer-google2.js +1 -0
- package/dist/components/v-map-layer-helper.js +1 -0
- package/dist/components/v-map-layer-osm.d.ts +11 -0
- package/dist/components/v-map-layer-osm.js +1 -0
- package/dist/components/v-map-layer-osm2.js +1 -0
- package/dist/components/v-map-layer-scatterplot.d.ts +11 -0
- package/dist/components/v-map-layer-scatterplot.js +1 -0
- package/dist/components/v-map-layer-scatterplot2.js +1 -0
- package/dist/components/v-map-layer-terrain-geotiff.d.ts +11 -0
- package/dist/components/v-map-layer-terrain-geotiff.js +1 -0
- package/dist/components/v-map-layer-terrain.d.ts +11 -0
- package/dist/components/v-map-layer-terrain.js +1 -0
- package/dist/components/v-map-layer-terrain2.js +1 -0
- package/dist/components/v-map-layer-tile3d.d.ts +11 -0
- package/dist/components/v-map-layer-tile3d.js +1 -0
- package/dist/components/v-map-layer-tile3d2.js +1 -0
- package/dist/components/v-map-layer-wcs.d.ts +11 -0
- package/dist/components/v-map-layer-wcs.js +1 -0
- package/dist/components/v-map-layer-wcs2.js +1 -0
- package/dist/components/v-map-layer-wfs.d.ts +11 -0
- package/dist/components/v-map-layer-wfs.js +1 -0
- package/dist/components/v-map-layer-wfs2.js +1 -0
- package/dist/components/v-map-layer-wkt.d.ts +11 -0
- package/dist/components/v-map-layer-wkt.js +1 -0
- package/dist/components/v-map-layer-wkt2.js +1 -0
- package/dist/components/v-map-layer-wms.d.ts +11 -0
- package/dist/components/v-map-layer-wms.js +1 -0
- package/dist/components/v-map-layer-wms2.js +1 -0
- package/dist/components/v-map-layer-xyz.d.ts +11 -0
- package/dist/components/v-map-layer-xyz.js +1 -0
- package/dist/components/v-map-layer-xyz2.js +1 -0
- package/dist/components/v-map-layercontrol.d.ts +11 -0
- package/dist/components/v-map-layercontrol.js +1 -0
- package/dist/components/v-map-layergroup.d.ts +11 -0
- package/dist/components/v-map-layergroup.js +1 -0
- package/dist/components/v-map-layergroup2.js +1 -0
- package/dist/components/v-map-style.d.ts +11 -0
- package/dist/components/v-map-style.js +1 -0
- package/dist/components/v-map-style2.js +10 -0
- package/dist/components/v-map.d.ts +11 -0
- package/dist/components/v-map.js +1 -0
- package/dist/components/v-map2.js +1 -0
- package/dist/esm/_commonjsHelpers-E-ZsRS8r.js +32 -0
- package/dist/esm/app-globals-DQuL1Twl.js +3 -0
- package/dist/esm/cesium-provider-BJfAup3w.js +2596 -0
- package/dist/esm/deck-provider-C7U9VDEq.js +47709 -0
- package/dist/esm/geotiff-BEWxTIfH.js +45 -0
- package/dist/esm/geotiff-source-esnDnC-u.js +1516 -0
- package/dist/esm/index-B1zwA4IC.js +685 -0
- package/dist/esm/index-BBpiaTpT.js +165 -0
- package/dist/esm/index-BIEmlzCf.js +1697 -0
- package/dist/esm/index-BUHa4Jj0.js +307 -0
- package/dist/esm/index-DbSdn93t.js +20461 -0
- package/dist/esm/index-RpJarvr_.js +10656 -0
- package/dist/esm/index-jN06TXUp.js +14 -0
- package/dist/esm/index-jzneDarq.js +1613 -0
- package/dist/esm/index.browser-DhQAXuA7.js +6860 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/layer-extension-CZXK5goK.js +63 -0
- package/dist/esm/leaflet-provider-Q41TB6ku.js +1794 -0
- package/dist/esm/loader.js +11 -0
- package/dist/esm/main-dist-CwnA7_Xn.js +2652 -0
- package/dist/esm/messages-CMKJzsgL.js +180 -0
- package/dist/esm/openlayers-provider-CMsDsQTQ.js +1602 -0
- package/dist/esm/polygon-layer-ByhxGhWC.js +1295 -0
- package/dist/esm/scenegraph-layer-09K_B6DT.js +2526 -0
- package/dist/esm/styleconfig-B-bAcABs.js +21 -0
- package/dist/esm/v-map-builder.entry.js +3784 -0
- package/dist/esm/v-map-layer-geojson_12.entry.js +40881 -0
- package/dist/esm/v-map-layer-helper-Dys44Cgo.js +283 -0
- package/dist/esm/v-map-layer-terrain-geotiff.entry.js +256 -0
- package/dist/esm/v-map-layercontrol.entry.js +245 -0
- package/dist/esm/v-map.js +21 -0
- package/dist/esm/v-map.v-map-layer-osm.v-map-layergroup-B4pFHuSf.js +572 -0
- package/dist/esm/v-map_3.entry.js +4 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/types/cesium-augment.d.ts +5 -0
- package/dist/types/components/v-map/v-map.d.ts +70 -0
- package/dist/types/components/v-map/v-map.test.d.ts +1 -0
- package/dist/types/components/v-map-builder/v-map-builder.d.ts +48 -0
- package/dist/types/components/v-map-builder/v-map-builder.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-geojson/v-map-layer-geojson.d.ts +129 -0
- package/dist/types/components/v-map-layer-geojson/v-map-layer-geojson.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-geotiff/v-map-layer-geotiff.d.ts +74 -0
- package/dist/types/components/v-map-layer-geotiff/v-map-layer-geotiff.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-google/v-map-layer-google.d.ts +78 -0
- package/dist/types/components/v-map-layer-osm/error-api.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-osm/v-map-layer-osm.d.ts +50 -0
- package/dist/types/components/v-map-layer-osm/v-map-layer-osm.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-scatterplot/v-map-layer-scatterplot.d.ts +54 -0
- package/dist/types/components/v-map-layer-terrain/v-map-layer-terrain.d.ts +74 -0
- package/dist/types/components/v-map-layer-terrain/v-map-layer-terrain.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.d.ts +117 -0
- package/dist/types/components/v-map-layer-terrain-geotiff/v-map-layer-terrain-geotiff.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-tile3d/v-map-layer-tile3d.d.ts +69 -0
- package/dist/types/components/v-map-layer-tile3d/v-map-layer-tile3d.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-wcs/v-map-layer-wcs.d.ts +47 -0
- package/dist/types/components/v-map-layer-wcs/v-map-layer-wcs.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-wfs/v-map-layer-wfs.d.ts +59 -0
- package/dist/types/components/v-map-layer-wfs/v-map-layer-wfs.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-wkt/v-map-layer-wkt.d.ts +132 -0
- package/dist/types/components/v-map-layer-wkt/v-map-layer-wkt.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-wms/v-map-layer-wms.d.ts +76 -0
- package/dist/types/components/v-map-layer-wms/v-map-layer-wms.test.d.ts +1 -0
- package/dist/types/components/v-map-layer-xyz/v-map-layer-xyz.d.ts +59 -0
- package/dist/types/components/v-map-layer-xyz/v-map-layer-xyz.test.d.ts +1 -0
- package/dist/types/components/v-map-layercontrol/v-map-layercontrol.d.ts +44 -0
- package/dist/types/components/v-map-layercontrol/v-map-layercontrol.test.d.ts +1 -0
- package/dist/types/components/v-map-layergroup/v-map-layergroup.d.ts +31 -0
- package/dist/types/components/v-map-layergroup/v-map-layergroup.test.d.ts +1 -0
- package/dist/types/components/v-map-style/v-map-style.d.ts +75 -0
- package/dist/types/components/v-map-style/v-map-style.unit.d.ts +1 -0
- package/dist/types/components.d.ts +2391 -0
- package/dist/types/globals.d.ts +16 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/layer/v-map-layer-helper.d.ts +45 -0
- package/dist/types/layer/v-map-layer-helper.unit.d.ts +1 -0
- package/dist/types/leaflet-augment.d.ts +15 -0
- package/dist/types/lib/cesium-loader.d.ts +3 -0
- package/dist/types/lib/ensure-importmap.d.ts +3 -0
- package/dist/types/lib/ensure-importmap.unit.d.ts +1 -0
- package/dist/types/lib/versions.gen.d.ts +5 -0
- package/dist/types/lib/vstyle.d.ts +44 -0
- package/dist/types/map-provider/cesium/CesiumGeoTIFFTerrainProvider.d.ts +92 -0
- package/dist/types/map-provider/cesium/CesiumLayerGroups.d.ts +64 -0
- package/dist/types/map-provider/cesium/GeoTIFFImageryProvider.d.ts +75 -0
- package/dist/types/map-provider/cesium/GeoTIFFImageryProvider.test.d.ts +1 -0
- package/dist/types/map-provider/cesium/cesium-provider.d.ts +87 -0
- package/dist/types/map-provider/cesium/i-layer.d.ts +11 -0
- package/dist/types/map-provider/cesium/layer-manager.d.ts +31 -0
- package/dist/types/map-provider/deck/DeckGLGeoTIFFLayer.d.ts +91 -0
- package/dist/types/map-provider/deck/DeckGLGeoTIFFTerrainLayer.d.ts +82 -0
- package/dist/types/map-provider/deck/LayerGroupWithModel.d.ts +55 -0
- package/dist/types/map-provider/deck/LayerGroups.d.ts +63 -0
- package/dist/types/map-provider/deck/LayerModel.d.ts +8 -0
- package/dist/types/map-provider/deck/RenderableGroup.d.ts +20 -0
- package/dist/types/map-provider/deck/deck-provider.d.ts +92 -0
- package/dist/types/map-provider/geotiff/geotiff-source.d.ts +30 -0
- package/dist/types/map-provider/geotiff/utils/AABB2D.d.ts +28 -0
- package/dist/types/map-provider/geotiff/utils/BVHNode2D.d.ts +36 -0
- package/dist/types/map-provider/geotiff/utils/GeoTIFFTileProcessor.d.ts +116 -0
- package/dist/types/map-provider/geotiff/utils/Triangle.d.ts +5 -0
- package/dist/types/map-provider/geotiff/utils/Triangulation.d.ts +94 -0
- package/dist/types/map-provider/geotiff/utils/colormap-utils.d.ts +47 -0
- package/dist/types/map-provider/geotiff/utils/normalization-utils.d.ts +39 -0
- package/dist/types/map-provider/geotiff/utils/sampling-utils.d.ts +13 -0
- package/dist/types/map-provider/leaflet/GeoTIFFGridLayer.d.ts +34 -0
- package/dist/types/map-provider/leaflet/WCSGridLayer.d.ts +38 -0
- package/dist/types/map-provider/leaflet/google-map-tiles-layer.d.ts +73 -0
- package/dist/types/map-provider/leaflet/leaflet-helpers.d.ts +6 -0
- package/dist/types/map-provider/leaflet/leaflet-provider.d.ts +73 -0
- package/dist/types/map-provider/ol/CustomGeoTiff.d.ts +14 -0
- package/dist/types/map-provider/ol/openlayers-helper.d.ts +2 -0
- package/dist/types/map-provider/ol/openlayers-provider.d.ts +80 -0
- package/dist/types/map-provider/provider-factory.d.ts +12 -0
- package/dist/types/map-provider/provider-factory.unit.d.ts +1 -0
- package/dist/types/namespaces.d.ts +3 -0
- package/dist/types/ol-augment.d.ts +3 -0
- package/dist/types/ol-override.d.ts +7 -0
- package/dist/types/ol.d.ts +10 -0
- package/dist/types/stencil-public-runtime.d.ts +1860 -0
- package/dist/types/testing/browser-test-utils.d.ts +6 -0
- package/dist/types/testing/e2e-testing.d.ts +5 -0
- package/dist/types/testing/e2e-utils.d.ts +4 -0
- package/dist/types/testing/geotiff-test-server.d.ts +5 -0
- package/dist/types/testing/mocks/geostyler-lyrx-parser.d.ts +11 -0
- package/dist/types/testing/mocks/geostyler-mapbox-parser.d.ts +11 -0
- package/dist/types/testing/mocks/geostyler-qgis-parser.d.ts +11 -0
- package/dist/types/testing/mocks/geostyler-sld-parser.d.ts +11 -0
- package/dist/types/testing/mocks/geostyler-style.d.ts +5 -0
- package/dist/types/testing/setupTests.browser.d.ts +1 -0
- package/dist/types/testing/setupTests.stencil.d.ts +1 -0
- package/dist/types/testing/setupTests.vitest.d.ts +1 -0
- package/dist/types/testing/stencil-testing-wrapper.d.ts +3 -0
- package/dist/types/types/color.d.ts +1 -0
- package/dist/types/types/cssmode.d.ts +1 -0
- package/dist/types/types/flavour.d.ts +1 -0
- package/dist/types/types/layerconfig.d.ts +207 -0
- package/dist/types/types/lonlat.d.ts +1 -0
- package/dist/types/types/mapinitoptions.d.ts +4 -0
- package/dist/types/types/mapprovider.d.ts +46 -0
- package/dist/types/types/provideroptions.d.ts +8 -0
- package/dist/types/types/styleconfig.d.ts +27 -0
- package/dist/types/types/styling.d.ts +24 -0
- package/dist/types/types/styling.unit.d.ts +1 -0
- package/dist/types/types/vmaplayer.d.ts +10 -0
- package/dist/types/utils/async-mutex.d.ts +7 -0
- package/dist/types/utils/diff.d.ts +64 -0
- package/dist/types/utils/diff.unit.d.ts +1 -0
- package/dist/types/utils/dom-env.d.ts +5 -0
- package/dist/types/utils/dom-env.unit.d.ts +1 -0
- package/dist/types/utils/events.d.ts +29 -0
- package/dist/types/utils/logger.d.ts +47 -0
- package/dist/types/utils/logger.unit.d.ts +1 -0
- package/dist/types/utils/messages.d.ts +12 -0
- package/dist/types/utils/spatial-utils.d.ts +6 -0
- package/dist/types/utils/spatial-utils.unit.d.ts +1 -0
- package/dist/types/versions.d.ts +7 -0
- package/dist/v-map/index.esm.js +0 -0
- package/dist/v-map/p--vVleK-M.js +1 -0
- package/dist/v-map/p-09d10db0.entry.js +1 -0
- package/dist/v-map/p-5eba6058.entry.js +10 -0
- package/dist/v-map/p-6b102336.entry.js +1 -0
- package/dist/v-map/p-B-bAcABs.js +1 -0
- package/dist/v-map/p-BBpiaTpT.js +1 -0
- package/dist/v-map/p-BdijL4Av.js +1 -0
- package/dist/v-map/p-Be3r33VF.js +4 -0
- package/dist/v-map/p-BeFu0ap4.js +1 -0
- package/dist/v-map/p-BxFJezdK.js +1 -0
- package/dist/v-map/p-CMKJzsgL.js +1 -0
- package/dist/v-map/p-CXfA_q8m.js +1 -0
- package/dist/v-map/p-CZqY0yW4.js +1 -0
- package/dist/v-map/p-CafTHT9i.js +1 -0
- package/dist/v-map/p-DCTHyf58.js +1 -0
- package/dist/v-map/p-DQuL1Twl.js +1 -0
- package/dist/v-map/p-DR9McdNX.js +1 -0
- package/dist/v-map/p-Dckgonw8.js +1 -0
- package/dist/v-map/p-DhQAXuA7.js +15 -0
- package/dist/v-map/p-DmICdG34.js +7 -0
- package/dist/v-map/p-DrOQ9V4h.js +1 -0
- package/dist/v-map/p-DvHXtWUg.js +1 -0
- package/dist/v-map/p-E-ZsRS8r.js +1 -0
- package/dist/v-map/p-MyTSFnEk.js +1 -0
- package/dist/v-map/p-RpJarvr_.js +1 -0
- package/dist/v-map/p-WaMDUuAz.js +1 -0
- package/dist/v-map/p-aa410e64.entry.js +2 -0
- package/dist/v-map/p-c21c93fe.entry.js +1 -0
- package/dist/v-map/p-jzneDarq.js +2 -0
- package/dist/v-map/p-uiIP-taz.js +1 -0
- package/dist/v-map/v-map.esm.js +1 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +193 -0
|
@@ -0,0 +1,2596 @@
|
|
|
1
|
+
import { w as warn, l as log, e as error } from './messages-CMKJzsgL.js';
|
|
2
|
+
import { C as CESIUM_VERSION } from './v-map.v-map-layer-osm.v-map-layergroup-B4pFHuSf.js';
|
|
3
|
+
import { l as loadGeoTIFFSource, a as getGeoTIFFSource, b as getTileProcessorConfig, G as GeoTIFFTileProcessor, g as getColorStops } from './geotiff-source-esnDnC-u.js';
|
|
4
|
+
import './index-jzneDarq.js';
|
|
5
|
+
import './v-map-layer-helper-Dys44Cgo.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Eine Gruppe verwaltet Sichtbarkeit & Basemap-Filter ihrer Cesium-Layer.
|
|
9
|
+
* - group.visible = false => Alle Layer der Gruppe unsichtbar.
|
|
10
|
+
* - group.basemap = "X" => Nur Layer mit elementId==="X" in der Gruppe sichtbar.
|
|
11
|
+
* - Der ursprüngliche Sichtbarkeitszustand jedes Layers wird gemerkt und bei
|
|
12
|
+
* Re-Aktivierung wiederhergestellt.
|
|
13
|
+
*/
|
|
14
|
+
class CesiumLayerGroup {
|
|
15
|
+
id;
|
|
16
|
+
_visible = true;
|
|
17
|
+
_basemap = null;
|
|
18
|
+
_layers = new Map();
|
|
19
|
+
_originalVisible = new Map();
|
|
20
|
+
_dirty = true;
|
|
21
|
+
constructor(id, visible = true) {
|
|
22
|
+
this.id = id;
|
|
23
|
+
this._visible = visible;
|
|
24
|
+
}
|
|
25
|
+
get visible() {
|
|
26
|
+
return this._visible;
|
|
27
|
+
}
|
|
28
|
+
set visible(v) {
|
|
29
|
+
if (this._visible === v)
|
|
30
|
+
return;
|
|
31
|
+
this._visible = v;
|
|
32
|
+
this._dirty = true;
|
|
33
|
+
}
|
|
34
|
+
get basemap() {
|
|
35
|
+
return this._basemap;
|
|
36
|
+
}
|
|
37
|
+
set basemap(b) {
|
|
38
|
+
if (this._basemap === b)
|
|
39
|
+
return;
|
|
40
|
+
this._basemap = b;
|
|
41
|
+
this._dirty = true;
|
|
42
|
+
}
|
|
43
|
+
isDirty() {
|
|
44
|
+
return this._dirty;
|
|
45
|
+
}
|
|
46
|
+
addLayer(ref) {
|
|
47
|
+
if (this._layers.has(ref.id))
|
|
48
|
+
return;
|
|
49
|
+
this._layers.set(ref.id, ref);
|
|
50
|
+
this._originalVisible.set(ref.id, ref.layer.getVisible());
|
|
51
|
+
this._dirty = true;
|
|
52
|
+
}
|
|
53
|
+
/** optional zum Nachziehen von elementId (z. B. wenn erst später bekannt) */
|
|
54
|
+
setLayerElementId(layerId, elementId) {
|
|
55
|
+
const r = this._layers.get(layerId);
|
|
56
|
+
if (!r)
|
|
57
|
+
return;
|
|
58
|
+
if (r.elementId === elementId)
|
|
59
|
+
return;
|
|
60
|
+
r.elementId = elementId ?? null;
|
|
61
|
+
this._dirty = true;
|
|
62
|
+
}
|
|
63
|
+
removeLayer(layerId) {
|
|
64
|
+
const had = this._layers.delete(layerId);
|
|
65
|
+
this._originalVisible.delete(layerId);
|
|
66
|
+
if (had)
|
|
67
|
+
this._dirty = true;
|
|
68
|
+
return had;
|
|
69
|
+
}
|
|
70
|
+
clear() {
|
|
71
|
+
this._layers.clear();
|
|
72
|
+
this._originalVisible.clear();
|
|
73
|
+
this._dirty = true;
|
|
74
|
+
}
|
|
75
|
+
/** zentrale Logik: Basemap/Visibility anwenden */
|
|
76
|
+
apply() {
|
|
77
|
+
if (!this._dirty)
|
|
78
|
+
return;
|
|
79
|
+
for (const [id, ref] of this._layers) {
|
|
80
|
+
const original = this._originalVisible.get(id) ?? true;
|
|
81
|
+
// effektive Sichtbarkeit nach Gruppenregeln
|
|
82
|
+
let effective = this._visible && original;
|
|
83
|
+
if (effective && this._basemap) {
|
|
84
|
+
// innerhalb der Gruppe nur Layer mit passender elementId anzeigen
|
|
85
|
+
effective = ref.elementId === this._basemap;
|
|
86
|
+
}
|
|
87
|
+
// Nur dann setzen, wenn sich etwas ändert
|
|
88
|
+
if (ref.layer.getVisible() !== effective) {
|
|
89
|
+
ref.layer.setVisible(effective);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
this._dirty = false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Root-Store für mehrere Cesium-Gruppen.
|
|
97
|
+
* - Ordnung/Z-Index übernimmst du weiterhin im LayerManager pro Layer.
|
|
98
|
+
* - Diese Klasse kümmert sich um Gruppensichtbarkeit & Basemap-Filter.
|
|
99
|
+
*/
|
|
100
|
+
class CesiumLayerGroups {
|
|
101
|
+
_groups = [];
|
|
102
|
+
_dirty = true;
|
|
103
|
+
get groups() {
|
|
104
|
+
return [...this._groups];
|
|
105
|
+
}
|
|
106
|
+
getGroup(id) {
|
|
107
|
+
return this._groups.find(g => g.id === id);
|
|
108
|
+
}
|
|
109
|
+
hasGroup(id) {
|
|
110
|
+
return this._groups.some(g => g.id === id);
|
|
111
|
+
}
|
|
112
|
+
ensureGroup(id, visible = true) {
|
|
113
|
+
let g = this.getGroup(id);
|
|
114
|
+
if (g)
|
|
115
|
+
return g;
|
|
116
|
+
g = new CesiumLayerGroup(id, visible);
|
|
117
|
+
this._groups.push(g);
|
|
118
|
+
this._dirty = true;
|
|
119
|
+
return g;
|
|
120
|
+
}
|
|
121
|
+
addLayerToGroup(groupId, visible, ref) {
|
|
122
|
+
const g = this.ensureGroup(groupId, visible);
|
|
123
|
+
g.addLayer(ref);
|
|
124
|
+
this._dirty = true;
|
|
125
|
+
}
|
|
126
|
+
removeLayer(layerId, removeFromAll = true) {
|
|
127
|
+
let removed = false;
|
|
128
|
+
for (const g of this._groups) {
|
|
129
|
+
if (g.removeLayer(layerId)) {
|
|
130
|
+
removed = true;
|
|
131
|
+
if (!removeFromAll)
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (removed)
|
|
136
|
+
this._dirty = true;
|
|
137
|
+
return removed;
|
|
138
|
+
}
|
|
139
|
+
setGroupVisible(groupId, visible) {
|
|
140
|
+
const g = this.getGroup(groupId);
|
|
141
|
+
if (!g)
|
|
142
|
+
throw new Error(`CesiumLayerGroup "${groupId}" nicht gefunden`);
|
|
143
|
+
g.visible = visible;
|
|
144
|
+
this._dirty = true;
|
|
145
|
+
}
|
|
146
|
+
setBasemap(groupId, basemap) {
|
|
147
|
+
const g = this.getGroup(groupId);
|
|
148
|
+
if (!g)
|
|
149
|
+
throw new Error(`CesiumLayerGroup "${groupId}" nicht gefunden`);
|
|
150
|
+
g.basemap = basemap;
|
|
151
|
+
this._dirty = true;
|
|
152
|
+
}
|
|
153
|
+
/** Wendet alle Gruppenregeln an (sichtbar/basemap). */
|
|
154
|
+
apply() {
|
|
155
|
+
if (!this._dirty && !this._groups.some(g => g.isDirty()))
|
|
156
|
+
return;
|
|
157
|
+
for (const g of this._groups)
|
|
158
|
+
g.apply();
|
|
159
|
+
this._dirty = false;
|
|
160
|
+
}
|
|
161
|
+
clear() {
|
|
162
|
+
this._groups = [];
|
|
163
|
+
this._dirty = true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
class LayerManager {
|
|
168
|
+
Cesium;
|
|
169
|
+
layers = new Map();
|
|
170
|
+
viewer;
|
|
171
|
+
//private imageryZMutex = new AsyncMutex();
|
|
172
|
+
constructor(Cesium, viewer) {
|
|
173
|
+
this.viewer = viewer;
|
|
174
|
+
this.Cesium = Cesium;
|
|
175
|
+
}
|
|
176
|
+
replaceLayer(id, oldlayer, layer) {
|
|
177
|
+
if (!this.Cesium) {
|
|
178
|
+
throw new Error('Cesium must be initialized first. Call init() method.');
|
|
179
|
+
}
|
|
180
|
+
const zIndex = oldlayer.getZIndex();
|
|
181
|
+
const visible = oldlayer.getVisible();
|
|
182
|
+
const opacity = oldlayer.getOpacity();
|
|
183
|
+
this.removeLayer(id);
|
|
184
|
+
const wrappedLayer = this.addLayer(id, layer);
|
|
185
|
+
wrappedLayer.setZIndex(zIndex);
|
|
186
|
+
wrappedLayer.setVisible(visible);
|
|
187
|
+
wrappedLayer.setOpacity(opacity);
|
|
188
|
+
return wrappedLayer;
|
|
189
|
+
}
|
|
190
|
+
addLayer(id, layer) {
|
|
191
|
+
if (!this.Cesium) {
|
|
192
|
+
throw new Error('Cesium must be initialized first. Call init() method.');
|
|
193
|
+
}
|
|
194
|
+
//add layer
|
|
195
|
+
if (layer instanceof this.Cesium.GeoJsonDataSource) {
|
|
196
|
+
this.viewer.dataSources.add(layer);
|
|
197
|
+
}
|
|
198
|
+
else if (layer instanceof this.Cesium.DataSource) {
|
|
199
|
+
this.viewer.dataSources.add(layer);
|
|
200
|
+
}
|
|
201
|
+
else if (layer instanceof this.Cesium.Cesium3DTileset) {
|
|
202
|
+
this.viewer.scene.primitives.add(layer);
|
|
203
|
+
if (!layer.style) {
|
|
204
|
+
layer.style = new this.Cesium.Cesium3DTileStyle();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else if (layer instanceof this.Cesium.ImageryLayer) {
|
|
208
|
+
this.viewer.imageryLayers.add(layer);
|
|
209
|
+
}
|
|
210
|
+
layer.id = id;
|
|
211
|
+
const wrapped = this.wrapLayer(layer);
|
|
212
|
+
this.layers.set(id, wrapped);
|
|
213
|
+
return wrapped;
|
|
214
|
+
}
|
|
215
|
+
addCustomLayer(id, layer) {
|
|
216
|
+
this.layers.set(id, layer);
|
|
217
|
+
return layer;
|
|
218
|
+
}
|
|
219
|
+
getLayer(layerId) {
|
|
220
|
+
const layer = this.layers.get(layerId);
|
|
221
|
+
if (!layer)
|
|
222
|
+
throw new Error(`Layer mit ID "${layerId}" nicht gefunden.`);
|
|
223
|
+
return layer;
|
|
224
|
+
}
|
|
225
|
+
getLayerById(layerId) {
|
|
226
|
+
return this.getLayer(layerId);
|
|
227
|
+
}
|
|
228
|
+
removeLayer(layerId) {
|
|
229
|
+
const layer = this.getLayer(layerId);
|
|
230
|
+
layer.remove();
|
|
231
|
+
this.layers.delete(layerId);
|
|
232
|
+
}
|
|
233
|
+
setVisible(layerId, visible) {
|
|
234
|
+
const layer = this.getLayer(layerId);
|
|
235
|
+
layer.setVisible(visible);
|
|
236
|
+
}
|
|
237
|
+
setOpacity(layerId, opacity) {
|
|
238
|
+
const layer = this.getLayer(layerId);
|
|
239
|
+
layer.setOpacity(opacity);
|
|
240
|
+
}
|
|
241
|
+
async setZIndex(layerId, zindex) {
|
|
242
|
+
const layer = this.getLayer(layerId);
|
|
243
|
+
await layer.setZIndex(zindex);
|
|
244
|
+
}
|
|
245
|
+
wrapLayer(layer) {
|
|
246
|
+
if (layer instanceof this.Cesium.ImageryLayer) {
|
|
247
|
+
return this.wrapImageryLayer(layer);
|
|
248
|
+
}
|
|
249
|
+
else if (layer instanceof this.Cesium.Cesium3DTileset) {
|
|
250
|
+
return this.wrapTilesetLayer(layer);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
return this.wrapDataSourceLayer(layer);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
async sortImageryLayers(collection, layer, targetZ) {
|
|
257
|
+
const tempCollection = this.sort(collection, layer, targetZ);
|
|
258
|
+
// Collection leeren und neu befüllen
|
|
259
|
+
collection.removeAll(false);
|
|
260
|
+
tempCollection.forEach(ds => collection.add(ds));
|
|
261
|
+
}
|
|
262
|
+
async sort3DTileSets(collection, tileset, targetZ) {
|
|
263
|
+
const tempCollection = this.sort(collection, tileset, targetZ);
|
|
264
|
+
// Collection leeren und neu befüllen
|
|
265
|
+
collection.removeAll();
|
|
266
|
+
tempCollection.forEach(ds => collection.add(ds));
|
|
267
|
+
}
|
|
268
|
+
async sortDataSources(collection, dataSource, zIndex) {
|
|
269
|
+
const tempCollection = this.sort(collection, dataSource, zIndex);
|
|
270
|
+
// Collection leeren und neu befüllen
|
|
271
|
+
collection.removeAll(false);
|
|
272
|
+
tempCollection.forEach(async (ds) => await collection.add(ds));
|
|
273
|
+
}
|
|
274
|
+
sort(collection, dataSource, zIndex) {
|
|
275
|
+
// 1. Layer entfernen
|
|
276
|
+
collection.remove(dataSource, false);
|
|
277
|
+
// 2. Layer an der richtigen Position wieder hinzufügen
|
|
278
|
+
// Cesium hat keine direkte "setZIndex"-Methode für DataSources,
|
|
279
|
+
// also müssen wir die Reihenfolge manuell steuern.
|
|
280
|
+
// Da DataSourceCollection keine Z-Index-Unterstützung hat,
|
|
281
|
+
// müssen wir alle Layer neu sortieren.
|
|
282
|
+
// const dataSources: DataSource[] = [];
|
|
283
|
+
const tempDataSources = [];
|
|
284
|
+
// Alle Layer sammeln
|
|
285
|
+
for (let i = 0; i < collection.length; i++) {
|
|
286
|
+
tempDataSources.push(collection.get(i));
|
|
287
|
+
}
|
|
288
|
+
// Sortieren nach zIndex (falls vorhanden) oder Reihenfolge
|
|
289
|
+
tempDataSources.sort((a, b) => {
|
|
290
|
+
const aZIndex = a.zIndex || 0;
|
|
291
|
+
const bZIndex = b.zIndex || 0;
|
|
292
|
+
return aZIndex - bZIndex;
|
|
293
|
+
});
|
|
294
|
+
// Den Layer mit dem neuen zIndex einfügen
|
|
295
|
+
dataSource.zIndex = zIndex;
|
|
296
|
+
tempDataSources.push(dataSource);
|
|
297
|
+
// Neu sortieren
|
|
298
|
+
tempDataSources.sort((a, b) => {
|
|
299
|
+
const aZIndex = a.zIndex || 0;
|
|
300
|
+
const bZIndex = b.zIndex || 0;
|
|
301
|
+
return aZIndex - bZIndex;
|
|
302
|
+
});
|
|
303
|
+
return tempDataSources;
|
|
304
|
+
}
|
|
305
|
+
// /**
|
|
306
|
+
// * Verschiebt ein bereits vorhandenes ImageryLayer innerhalb seiner Collection
|
|
307
|
+
// * zu einem gewünschten zIndex und hält die Collection nach zIndex sortiert.
|
|
308
|
+
// *
|
|
309
|
+
// * @param collection Die Sammlung, in der sich das Layer befindet.
|
|
310
|
+
// * @param layer Das zu verschiebende Layer (ist bereits Teil der Collection).
|
|
311
|
+
// * @param targetZ Der gewünschte neue zIndex.
|
|
312
|
+
// */
|
|
313
|
+
// private moveImageryLayerToZIndex(
|
|
314
|
+
// collection: ImageryLayerCollection,
|
|
315
|
+
// layer: ImageryLayer,
|
|
316
|
+
// targetZ: number,
|
|
317
|
+
// ): void {
|
|
318
|
+
// // fire-and-forget; Thread-Sicherheit via Mutex
|
|
319
|
+
// void this.imageryZMutex.runExclusive(async () => {
|
|
320
|
+
// // -------------------------------------------------
|
|
321
|
+
// // 1️⃣ Neues zIndex setzen (überschreibt das alte)
|
|
322
|
+
// // -------------------------------------------------
|
|
323
|
+
// (layer as any).zIndex = targetZ;
|
|
324
|
+
// // -------------------------------------------------
|
|
325
|
+
// // 2️⃣ Aktuelle Position bestimmen
|
|
326
|
+
// // -------------------------------------------------
|
|
327
|
+
// const curIdx = collection.indexOf(layer);
|
|
328
|
+
// if (curIdx === -1) {
|
|
329
|
+
// throw new Error('Der übergebene Layer ist nicht Teil der Collection.');
|
|
330
|
+
// }
|
|
331
|
+
// // -------------------------------------------------
|
|
332
|
+
// // 3️⃣ Nach oben schieben, solange Vorgänger einen
|
|
333
|
+
// // größeren zIndex hat (stabile Sortierung)
|
|
334
|
+
// // -------------------------------------------------
|
|
335
|
+
// let idx = curIdx;
|
|
336
|
+
// while (
|
|
337
|
+
// idx > 0 && // nicht am Anfang
|
|
338
|
+
// collection[idx - 1].zIndex > targetZ // Vorgänger hat höheren zIndex
|
|
339
|
+
// ) {
|
|
340
|
+
// // `raise` vertauscht das aktuelle Element mit seinem Vorgänger
|
|
341
|
+
// collection.raise(collection[idx]);
|
|
342
|
+
// idx--;
|
|
343
|
+
// }
|
|
344
|
+
// // -------------------------------------------------
|
|
345
|
+
// // 4️⃣ Nach unten schieben, falls das neue zIndex
|
|
346
|
+
// // größer ist als das der nachfolgenden Elemente
|
|
347
|
+
// // -------------------------------------------------
|
|
348
|
+
// while (
|
|
349
|
+
// idx < collection.length - 1 && // nicht am Ende
|
|
350
|
+
// collection[idx + 1].zIndex < targetZ // Nachfolger hat kleineren zIndex
|
|
351
|
+
// ) {
|
|
352
|
+
// // `lower` vertauscht das aktuelle Element mit seinem Nachfolger
|
|
353
|
+
// collection.lower(collection[idx]);
|
|
354
|
+
// idx++;
|
|
355
|
+
// }
|
|
356
|
+
// });
|
|
357
|
+
// // -------------------------------------------------
|
|
358
|
+
// // 5️⃣ Optional: Guard‑Clause für extreme Werte
|
|
359
|
+
// // -------------------------------------------------
|
|
360
|
+
// // (Falls du Min/Max‑Grenzen definieren willst)
|
|
361
|
+
// // if (targetZ < MIN_Z) (layer as any).zIndex = MIN_Z;
|
|
362
|
+
// // if (targetZ > MAX_Z) (layer as any).zIndex = MAX_Z;
|
|
363
|
+
// }
|
|
364
|
+
// private moveTilesetToIndex(tileset: Cesium3DTileset, index: number): void {
|
|
365
|
+
// const primitives = this.viewer.scene.primitives;
|
|
366
|
+
// primitives.remove(tileset);
|
|
367
|
+
// if (index >= primitives.length) {
|
|
368
|
+
// primitives.add(tileset);
|
|
369
|
+
// } else {
|
|
370
|
+
// const tilesets = [];
|
|
371
|
+
// for (let i = 0; i < primitives.length; i++) {
|
|
372
|
+
// const current = primitives.get(i);
|
|
373
|
+
// if (i === index) tilesets.push(tileset);
|
|
374
|
+
// if (current !== tileset) tilesets.push(current);
|
|
375
|
+
// }
|
|
376
|
+
// primitives.removeAll();
|
|
377
|
+
// tilesets.forEach(t => primitives.add(t));
|
|
378
|
+
// }
|
|
379
|
+
// }
|
|
380
|
+
// private moveDataSourceToIndex(
|
|
381
|
+
// collection: DataSourceCollection,
|
|
382
|
+
// dataSource: DataSource,
|
|
383
|
+
// zIndex: number,
|
|
384
|
+
// ): void {
|
|
385
|
+
// // 1. Layer entfernen
|
|
386
|
+
// collection.remove(dataSource);
|
|
387
|
+
// // 2. Layer an der richtigen Position wieder hinzufügen
|
|
388
|
+
// // Cesium hat keine direkte "setZIndex"-Methode für DataSources,
|
|
389
|
+
// // also müssen wir die Reihenfolge manuell steuern.
|
|
390
|
+
// // Da DataSourceCollection keine Z-Index-Unterstützung hat,
|
|
391
|
+
// // müssen wir alle Layer neu sortieren.
|
|
392
|
+
// // const dataSources: DataSource[] = [];
|
|
393
|
+
// const tempDataSources: DataSource[] = [];
|
|
394
|
+
// // Alle Layer sammeln
|
|
395
|
+
// for (let i = 0; i < collection.length; i++) {
|
|
396
|
+
// tempDataSources.push(collection.get(i));
|
|
397
|
+
// }
|
|
398
|
+
// // Sortieren nach zIndex (falls vorhanden) oder Reihenfolge
|
|
399
|
+
// tempDataSources.sort((a, b) => {
|
|
400
|
+
// const aZIndex = (a as any).zIndex || 0;
|
|
401
|
+
// const bZIndex = (b as any).zIndex || 0;
|
|
402
|
+
// return aZIndex - bZIndex;
|
|
403
|
+
// });
|
|
404
|
+
// // Den Layer mit dem neuen zIndex einfügen
|
|
405
|
+
// (dataSource as any).zIndex = zIndex;
|
|
406
|
+
// tempDataSources.push(dataSource);
|
|
407
|
+
// // Neu sortieren
|
|
408
|
+
// tempDataSources.sort((a, b) => {
|
|
409
|
+
// const aZIndex = (a as any).zIndex || 0;
|
|
410
|
+
// const bZIndex = (b as any).zIndex || 0;
|
|
411
|
+
// return aZIndex - bZIndex;
|
|
412
|
+
// });
|
|
413
|
+
// // Collection leeren und neu befüllen
|
|
414
|
+
// collection.removeAll();
|
|
415
|
+
// tempDataSources.forEach(ds => collection.add(ds));
|
|
416
|
+
// }
|
|
417
|
+
wrapImageryLayer(layer) {
|
|
418
|
+
const collection = this.viewer.imageryLayers;
|
|
419
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- matches ILayer interface contract
|
|
420
|
+
let iLOptions = {};
|
|
421
|
+
return {
|
|
422
|
+
getOptions: () => {
|
|
423
|
+
return iLOptions;
|
|
424
|
+
},
|
|
425
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- matches ILayer interface contract
|
|
426
|
+
setOptions(options) {
|
|
427
|
+
iLOptions = options;
|
|
428
|
+
},
|
|
429
|
+
getVisible: () => {
|
|
430
|
+
return layer.show;
|
|
431
|
+
},
|
|
432
|
+
setVisible: (value) => {
|
|
433
|
+
layer.show = value;
|
|
434
|
+
},
|
|
435
|
+
getOpacity: () => layer.alpha,
|
|
436
|
+
setOpacity: (value) => {
|
|
437
|
+
layer.alpha = value;
|
|
438
|
+
},
|
|
439
|
+
getZIndex: () => {
|
|
440
|
+
for (let i = 0; i < collection.length; i++) {
|
|
441
|
+
if (collection.get(i) === layer)
|
|
442
|
+
return i;
|
|
443
|
+
}
|
|
444
|
+
return -1;
|
|
445
|
+
},
|
|
446
|
+
setZIndex: async (zIndex) => {
|
|
447
|
+
if (zIndex !== undefined) {
|
|
448
|
+
await this.sortImageryLayers(collection, layer, zIndex);
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
remove: () => collection.remove(layer),
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
wrapTilesetLayer(layer) {
|
|
455
|
+
const collection = this.viewer.scene.primitives;
|
|
456
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- matches ILayer interface contract
|
|
457
|
+
let c3dTSOptions = {};
|
|
458
|
+
return {
|
|
459
|
+
getOptions: () => {
|
|
460
|
+
return c3dTSOptions;
|
|
461
|
+
},
|
|
462
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- matches ILayer interface contract
|
|
463
|
+
setOptions(options) {
|
|
464
|
+
c3dTSOptions = options;
|
|
465
|
+
},
|
|
466
|
+
getVisible: () => {
|
|
467
|
+
return layer.show;
|
|
468
|
+
},
|
|
469
|
+
setVisible: (value) => {
|
|
470
|
+
layer.show = value;
|
|
471
|
+
},
|
|
472
|
+
getOpacity: () => {
|
|
473
|
+
const style = layer.style;
|
|
474
|
+
if (style.color && typeof style.color === 'string') {
|
|
475
|
+
const colorStr = style.color;
|
|
476
|
+
const match = colorStr.match(/color\(.*?,([\d.]+)\)/);
|
|
477
|
+
return match ? parseFloat(match[1]) : 1.0;
|
|
478
|
+
}
|
|
479
|
+
return 1.0;
|
|
480
|
+
},
|
|
481
|
+
setOpacity: (value) => {
|
|
482
|
+
const currentColor = layer.style.color;
|
|
483
|
+
let colorExpr;
|
|
484
|
+
if (typeof currentColor === 'string') {
|
|
485
|
+
const colorStr = currentColor;
|
|
486
|
+
const colorPart = colorStr.replace(/color\((.*?),[\d.]+\)/, `color($1, ${value})`);
|
|
487
|
+
colorExpr = colorPart.includes('color')
|
|
488
|
+
? colorPart
|
|
489
|
+
: `color('white', ${value})`;
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
colorExpr = `color('white', ${value})`;
|
|
493
|
+
}
|
|
494
|
+
layer.style = new this.Cesium.Cesium3DTileStyle({
|
|
495
|
+
color: colorExpr,
|
|
496
|
+
colorBlendMode: this.Cesium.ColorBlendMode.MIX,
|
|
497
|
+
});
|
|
498
|
+
},
|
|
499
|
+
getZIndex: () => {
|
|
500
|
+
const primitives = this.viewer.scene.primitives;
|
|
501
|
+
for (let i = 0; i < primitives.length; i++) {
|
|
502
|
+
if (primitives.get(i) === layer)
|
|
503
|
+
return i;
|
|
504
|
+
}
|
|
505
|
+
return -1;
|
|
506
|
+
},
|
|
507
|
+
setZIndex: async (zIndex) => {
|
|
508
|
+
if (zIndex !== undefined) {
|
|
509
|
+
this.sort3DTileSets(collection, layer, zIndex);
|
|
510
|
+
//this.moveTilesetToIndex(layer, zIndex);
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
setColor: (color, opacity = 1.0) => {
|
|
514
|
+
const cssColor = color instanceof this.Cesium.Color
|
|
515
|
+
? color.toCssHexString()
|
|
516
|
+
: color.replace(/[#\s]/g, '');
|
|
517
|
+
layer.style = new this.Cesium.Cesium3DTileStyle({
|
|
518
|
+
color: `color('${cssColor}', ${opacity})`,
|
|
519
|
+
colorBlendMode: this.Cesium.ColorBlendMode.MIX,
|
|
520
|
+
});
|
|
521
|
+
},
|
|
522
|
+
setStyle: (style) => {
|
|
523
|
+
layer.style =
|
|
524
|
+
style instanceof this.Cesium.Cesium3DTileStyle
|
|
525
|
+
? style
|
|
526
|
+
: new this.Cesium.Cesium3DTileStyle(style);
|
|
527
|
+
},
|
|
528
|
+
remove: () => this.viewer.scene.primitives.remove(layer),
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
wrapDataSourceLayer(layer) {
|
|
532
|
+
const collection = this.viewer.dataSources;
|
|
533
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- matches ILayer interface contract
|
|
534
|
+
let dsOptions = {};
|
|
535
|
+
return {
|
|
536
|
+
getOptions: () => {
|
|
537
|
+
return dsOptions;
|
|
538
|
+
},
|
|
539
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- matches ILayer interface contract
|
|
540
|
+
setOptions(options) {
|
|
541
|
+
dsOptions = options;
|
|
542
|
+
},
|
|
543
|
+
getVisible: () => {
|
|
544
|
+
return layer.show;
|
|
545
|
+
},
|
|
546
|
+
setVisible: (value) => {
|
|
547
|
+
layer.show = value;
|
|
548
|
+
},
|
|
549
|
+
getOpacity: () => 1.0, //todo
|
|
550
|
+
setOpacity: (value) => {
|
|
551
|
+
if (layer.__vmapLockOpacity)
|
|
552
|
+
return;
|
|
553
|
+
layer.entities.values.forEach((entity) => {
|
|
554
|
+
// Helper-Funktion zum Setzen der Opacity
|
|
555
|
+
const setColorOpacity = (colorProperty, defaultColor) => {
|
|
556
|
+
const { Color: CesiumColor, JulianDate } = this.Cesium;
|
|
557
|
+
const applyAlpha = (color) => CesiumColor.fromAlpha(color ?? defaultColor, value, new CesiumColor());
|
|
558
|
+
if (!colorProperty) {
|
|
559
|
+
return new this.Cesium.ConstantProperty(applyAlpha(defaultColor));
|
|
560
|
+
}
|
|
561
|
+
const maybeProperty = colorProperty;
|
|
562
|
+
if (maybeProperty && typeof maybeProperty.getValue === 'function') {
|
|
563
|
+
const currentColor = maybeProperty.getValue(this.viewer?.clock?.currentTime ?? new JulianDate(), new CesiumColor());
|
|
564
|
+
const nextColor = applyAlpha(currentColor);
|
|
565
|
+
if (typeof maybeProperty.setValue === 'function') {
|
|
566
|
+
maybeProperty.setValue(nextColor);
|
|
567
|
+
return maybeProperty;
|
|
568
|
+
}
|
|
569
|
+
return new this.Cesium.ConstantProperty(nextColor);
|
|
570
|
+
}
|
|
571
|
+
if (colorProperty instanceof this.Cesium.Color) {
|
|
572
|
+
return new this.Cesium.ConstantProperty(applyAlpha(colorProperty));
|
|
573
|
+
}
|
|
574
|
+
return new this.Cesium.ConstantProperty(applyAlpha(defaultColor));
|
|
575
|
+
};
|
|
576
|
+
// Polygone
|
|
577
|
+
if (entity.polygon) {
|
|
578
|
+
const material = entity.polygon.material;
|
|
579
|
+
if (material instanceof Cesium.ColorMaterialProperty) {
|
|
580
|
+
const color = material.color;
|
|
581
|
+
material.color = setColorOpacity(color, Cesium.Color.WHITE);
|
|
582
|
+
}
|
|
583
|
+
else if (material instanceof Cesium.ImageMaterialProperty) {
|
|
584
|
+
material.color = setColorOpacity(material.color, Cesium.Color.WHITE);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
// Polylinien
|
|
588
|
+
if (entity.polyline) {
|
|
589
|
+
const material = entity.polyline.material;
|
|
590
|
+
if (material instanceof Cesium.ColorMaterialProperty) {
|
|
591
|
+
material.color = setColorOpacity(material.color, Cesium.Color.WHITE);
|
|
592
|
+
}
|
|
593
|
+
else if (material instanceof Cesium.PolylineOutlineMaterialProperty) {
|
|
594
|
+
material.color = setColorOpacity(material.color, Cesium.Color.WHITE);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
// Punkte
|
|
598
|
+
if (entity.point) {
|
|
599
|
+
entity.point.color = setColorOpacity(entity.point.color, Cesium.Color.WHITE);
|
|
600
|
+
}
|
|
601
|
+
// Billboards
|
|
602
|
+
if (entity.billboard) {
|
|
603
|
+
entity.billboard.color = setColorOpacity(entity.billboard.color, Cesium.Color.WHITE);
|
|
604
|
+
}
|
|
605
|
+
// Labels
|
|
606
|
+
if (entity.label) {
|
|
607
|
+
entity.label.fillColor = setColorOpacity(entity.label.fillColor, Cesium.Color.BLACK);
|
|
608
|
+
if (entity.label.outlineColor) {
|
|
609
|
+
entity.label.outlineColor = setColorOpacity(entity.label.outlineColor, Cesium.Color.BLACK);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
// 3D-Modelle (falls vorhanden)
|
|
613
|
+
if (entity.model) {
|
|
614
|
+
entity.model.color = setColorOpacity(entity.model.color, Cesium.Color.WHITE);
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
},
|
|
618
|
+
getZIndex: () => {
|
|
619
|
+
for (let i = 0; i < collection.length; i++) {
|
|
620
|
+
if (collection.get(i) === layer)
|
|
621
|
+
return i;
|
|
622
|
+
}
|
|
623
|
+
return -1;
|
|
624
|
+
},
|
|
625
|
+
setZIndex: async (zIndex) => {
|
|
626
|
+
if (zIndex !== undefined) {
|
|
627
|
+
await this.sortDataSources(collection, layer, zIndex);
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
remove: () => collection.remove(layer),
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// utils/async-mutex.ts
|
|
636
|
+
class AsyncMutex {
|
|
637
|
+
locked = false;
|
|
638
|
+
queue = [];
|
|
639
|
+
async runExclusive(fn) {
|
|
640
|
+
await this.acquire();
|
|
641
|
+
try {
|
|
642
|
+
return await fn();
|
|
643
|
+
}
|
|
644
|
+
finally {
|
|
645
|
+
this.release();
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
acquire() {
|
|
649
|
+
if (!this.locked) {
|
|
650
|
+
this.locked = true;
|
|
651
|
+
return Promise.resolve();
|
|
652
|
+
}
|
|
653
|
+
return new Promise(resolve => this.queue.push(resolve));
|
|
654
|
+
}
|
|
655
|
+
release() {
|
|
656
|
+
const next = this.queue.shift();
|
|
657
|
+
if (next)
|
|
658
|
+
next();
|
|
659
|
+
else
|
|
660
|
+
this.locked = false;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function assert(cond, msg) {
|
|
665
|
+
if (!cond)
|
|
666
|
+
throw new Error(msg);
|
|
667
|
+
}
|
|
668
|
+
const sameMM = (exp, act) => exp.match(/^\d+\.\d+/)?.[0] === act.match(/^\d+\.\d+/)?.[0];
|
|
669
|
+
const loadCesiumMutex = new AsyncMutex();
|
|
670
|
+
async function loadCesium(version = CESIUM_VERSION) {
|
|
671
|
+
const v = version.replace(/^[^\d]*/, '');
|
|
672
|
+
const base = `https://cdn.jsdelivr.net/npm/cesium@${v}/Build/Cesium`;
|
|
673
|
+
const url = `${base}/Cesium.js`;
|
|
674
|
+
await loadCesiumMutex.runExclusive(async () => {
|
|
675
|
+
if (!globalThis.Cesium) {
|
|
676
|
+
await new Promise((resolve, reject) => {
|
|
677
|
+
const id = 'cesium-cdn-script';
|
|
678
|
+
if (document.getElementById(id))
|
|
679
|
+
return resolve();
|
|
680
|
+
const s = document.createElement('script');
|
|
681
|
+
s.id = id;
|
|
682
|
+
s.async = true;
|
|
683
|
+
s.src = url;
|
|
684
|
+
s.addEventListener('load', () => resolve(), { once: true });
|
|
685
|
+
s.addEventListener('error', () => reject(new Error(`Laden fehlgeschlagen: ${url}`)), { once: true });
|
|
686
|
+
document.head.appendChild(s);
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
const Cesium = globalThis.Cesium;
|
|
691
|
+
assert(Cesium, 'globalThis.Cesium nicht verfügbar.');
|
|
692
|
+
const actual = Cesium.VERSION; // z.B. "1.133"
|
|
693
|
+
assert(sameMM(String(version), actual), // Major.Minor muss passen
|
|
694
|
+
`Cesium-Version abweichend: erwartet ~${version}, geladen ${actual}`);
|
|
695
|
+
globalThis.CESIUM_BASE_URL = base;
|
|
696
|
+
return Cesium;
|
|
697
|
+
}
|
|
698
|
+
async function injectWidgetsCss(shadowRoot) {
|
|
699
|
+
const v = CESIUM_VERSION.replace(/^[^\d]*/, '');
|
|
700
|
+
const base = `https://cdn.jsdelivr.net/npm/cesium@${v}/Build/Cesium`;
|
|
701
|
+
const cssUrl = `${base}/Widgets/widgets.css`;
|
|
702
|
+
const cssText = await (await fetch(cssUrl)).text();
|
|
703
|
+
const absolutized = cssText.replace(/url\((?!['"]?data:)(['"]?)([^'")]+)\1\)/g, (_m, _q, rel) => `url(${base}/Widgets/${rel.replace(/^\.?\//, '')})`);
|
|
704
|
+
if (!shadowRoot)
|
|
705
|
+
return;
|
|
706
|
+
if ('adoptedStyleSheets' in Document.prototype) {
|
|
707
|
+
const sheet = new CSSStyleSheet();
|
|
708
|
+
await sheet.replace(absolutized);
|
|
709
|
+
shadowRoot.adoptedStyleSheets = [
|
|
710
|
+
...(shadowRoot.adoptedStyleSheets ?? []),
|
|
711
|
+
sheet,
|
|
712
|
+
];
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
const style = document.createElement('style');
|
|
716
|
+
style.textContent = absolutized;
|
|
717
|
+
shadowRoot.appendChild(style);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Custom ImageryProvider that renders GeoTIFF tiles on demand using
|
|
723
|
+
* the shared GeoTIFFTileProcessor (triangulation-based reprojection).
|
|
724
|
+
*/
|
|
725
|
+
class GeoTIFFImageryProvider {
|
|
726
|
+
tileWidth;
|
|
727
|
+
tileHeight;
|
|
728
|
+
tilingScheme;
|
|
729
|
+
rectangle;
|
|
730
|
+
errorEvent;
|
|
731
|
+
credit = undefined;
|
|
732
|
+
tileDiscardPolicy = undefined;
|
|
733
|
+
proxy = undefined;
|
|
734
|
+
hasAlphaChannel = true;
|
|
735
|
+
minimumLevel;
|
|
736
|
+
maximumLevel;
|
|
737
|
+
Cesium;
|
|
738
|
+
tileProcessor;
|
|
739
|
+
resolution;
|
|
740
|
+
resampleMethod;
|
|
741
|
+
colorStops;
|
|
742
|
+
readyPromiseInternal;
|
|
743
|
+
ready = false;
|
|
744
|
+
constructor(options) {
|
|
745
|
+
const { Cesium, rectangleDegrees, tileProcessor, tileSize, resolution, resampleMethod, colorStops, minimumLevel, maximumLevel, } = options;
|
|
746
|
+
this.Cesium = Cesium;
|
|
747
|
+
this.tileProcessor = tileProcessor;
|
|
748
|
+
this.tileWidth = tileSize;
|
|
749
|
+
this.tileHeight = tileSize;
|
|
750
|
+
this.resolution = resolution;
|
|
751
|
+
this.resampleMethod = resampleMethod;
|
|
752
|
+
this.colorStops = colorStops;
|
|
753
|
+
this.minimumLevel = minimumLevel ?? 0;
|
|
754
|
+
this.maximumLevel = maximumLevel;
|
|
755
|
+
this.rectangle = Cesium.Rectangle.fromDegrees(rectangleDegrees[0], rectangleDegrees[1], rectangleDegrees[2], rectangleDegrees[3]);
|
|
756
|
+
// Always use WebMercatorTilingScheme because the GeoTIFFTileProcessor
|
|
757
|
+
// interprets (x,y,z) as Web Mercator tile coordinates.
|
|
758
|
+
this.tilingScheme = new Cesium.WebMercatorTilingScheme();
|
|
759
|
+
this.errorEvent = new Cesium.Event();
|
|
760
|
+
this.ready = true;
|
|
761
|
+
this.readyPromiseInternal = Promise.resolve(true);
|
|
762
|
+
}
|
|
763
|
+
get tilingSchemeName() {
|
|
764
|
+
// Expose helper for debugging if needed.
|
|
765
|
+
return this.tilingScheme instanceof this.Cesium.WebMercatorTilingScheme
|
|
766
|
+
? 'WebMercator'
|
|
767
|
+
: undefined;
|
|
768
|
+
}
|
|
769
|
+
get readyPromise() {
|
|
770
|
+
return this.readyPromiseInternal;
|
|
771
|
+
}
|
|
772
|
+
get tileCredits() {
|
|
773
|
+
return undefined;
|
|
774
|
+
}
|
|
775
|
+
getTileCredits(_x, _y, _level) {
|
|
776
|
+
return undefined;
|
|
777
|
+
}
|
|
778
|
+
get url() {
|
|
779
|
+
return undefined;
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Flips a canvas vertically (Y-axis inversion) for Cesium.
|
|
783
|
+
* Creates a new canvas with the flipped content.
|
|
784
|
+
*
|
|
785
|
+
* @param sourceCanvas - The canvas to flip
|
|
786
|
+
* @param width - Width of the canvas
|
|
787
|
+
* @param height - Height of the canvas
|
|
788
|
+
* @returns A new canvas with vertically flipped content, or the source canvas if flipping fails
|
|
789
|
+
*/
|
|
790
|
+
flipCanvasVertically(sourceCanvas, width, height) {
|
|
791
|
+
const flippedCanvas = document.createElement('canvas');
|
|
792
|
+
flippedCanvas.width = width;
|
|
793
|
+
flippedCanvas.height = height;
|
|
794
|
+
const flippedCtx = flippedCanvas.getContext('2d');
|
|
795
|
+
if (!flippedCtx) {
|
|
796
|
+
warn('v-map - cesium - failed to get 2d context for flip');
|
|
797
|
+
return sourceCanvas; // Fallback to source canvas
|
|
798
|
+
}
|
|
799
|
+
flippedCtx.translate(0, height);
|
|
800
|
+
flippedCtx.scale(1, -1);
|
|
801
|
+
flippedCtx.drawImage(sourceCanvas, 0, 0);
|
|
802
|
+
return flippedCanvas;
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Creates a flipped ImageBitmap from RGBA data.
|
|
806
|
+
* Uses ImageBitmap for better performance when available.
|
|
807
|
+
*
|
|
808
|
+
* @param rgbaData - The RGBA pixel data
|
|
809
|
+
* @param sampleSize - Size of the tile (width and height)
|
|
810
|
+
* @returns A flipped ImageBitmap, or undefined if creation fails
|
|
811
|
+
*/
|
|
812
|
+
async createFlippedImageBitmap(rgbaData, sampleSize) {
|
|
813
|
+
if (typeof createImageBitmap !== 'function') {
|
|
814
|
+
return undefined;
|
|
815
|
+
}
|
|
816
|
+
try {
|
|
817
|
+
// Create temporary canvas for Y-axis flip
|
|
818
|
+
const tempCanvas = document.createElement('canvas');
|
|
819
|
+
tempCanvas.width = sampleSize;
|
|
820
|
+
tempCanvas.height = sampleSize;
|
|
821
|
+
const tempCtx = tempCanvas.getContext('2d');
|
|
822
|
+
if (!tempCtx) {
|
|
823
|
+
throw new Error('Failed to get 2d context');
|
|
824
|
+
}
|
|
825
|
+
const imageData = tempCtx.createImageData(sampleSize, sampleSize);
|
|
826
|
+
imageData.data.set(rgbaData);
|
|
827
|
+
tempCtx.putImageData(imageData, 0, 0);
|
|
828
|
+
// Flip vertically for Cesium
|
|
829
|
+
const flippedCanvas = this.flipCanvasVertically(tempCanvas, sampleSize, sampleSize);
|
|
830
|
+
return await createImageBitmap(flippedCanvas);
|
|
831
|
+
}
|
|
832
|
+
catch (err) {
|
|
833
|
+
warn('v-map - cesium - createImageBitmap failed, falling back', err);
|
|
834
|
+
return undefined;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Creates a flipped image (ImageBitmap or Canvas) from RGBA data.
|
|
839
|
+
* Prefers ImageBitmap for better performance, falls back to Canvas.
|
|
840
|
+
*
|
|
841
|
+
* @param rgbaData - The RGBA pixel data
|
|
842
|
+
* @returns A flipped ImageBitmap or Canvas, or undefined if creation fails
|
|
843
|
+
*/
|
|
844
|
+
async createFlippedImageFromRGBA(rgbaData) {
|
|
845
|
+
// Calculate actual sample size (may differ from tileWidth due to resolution)
|
|
846
|
+
const sampleSize = Math.ceil(this.tileWidth * this.resolution);
|
|
847
|
+
// Prefer ImageBitmap when available for better performance
|
|
848
|
+
const imageBitmap = await this.createFlippedImageBitmap(rgbaData, sampleSize);
|
|
849
|
+
if (imageBitmap) {
|
|
850
|
+
return imageBitmap;
|
|
851
|
+
}
|
|
852
|
+
// Fallback to Canvas
|
|
853
|
+
const canvas = document.createElement('canvas');
|
|
854
|
+
canvas.width = sampleSize;
|
|
855
|
+
canvas.height = sampleSize;
|
|
856
|
+
const ctx = canvas.getContext('2d');
|
|
857
|
+
if (!ctx) {
|
|
858
|
+
warn('v-map - cesium - unable to acquire canvas 2d context');
|
|
859
|
+
return undefined;
|
|
860
|
+
}
|
|
861
|
+
const imageData = ctx.createImageData(sampleSize, sampleSize);
|
|
862
|
+
imageData.data.set(rgbaData);
|
|
863
|
+
ctx.putImageData(imageData, 0, 0);
|
|
864
|
+
// Flip the canvas vertically for Cesium (Y-axis inversion)
|
|
865
|
+
return this.flipCanvasVertically(canvas, sampleSize, sampleSize);
|
|
866
|
+
}
|
|
867
|
+
async requestImage(x, y, level) {
|
|
868
|
+
if (!this.ready)
|
|
869
|
+
return undefined;
|
|
870
|
+
if (level < this.minimumLevel ||
|
|
871
|
+
(this.maximumLevel !== undefined && level > this.maximumLevel)) {
|
|
872
|
+
return undefined;
|
|
873
|
+
}
|
|
874
|
+
const params = {
|
|
875
|
+
x,
|
|
876
|
+
y,
|
|
877
|
+
z: level,
|
|
878
|
+
tileSize: this.tileWidth,
|
|
879
|
+
resolution: this.resolution,
|
|
880
|
+
resampleMethod: this.resampleMethod,
|
|
881
|
+
colorStops: this.colorStops,
|
|
882
|
+
};
|
|
883
|
+
let rgbaData = null;
|
|
884
|
+
try {
|
|
885
|
+
rgbaData = await this.tileProcessor.getTileData(params);
|
|
886
|
+
if (!rgbaData) {
|
|
887
|
+
log(`v-map - cesium - geotiff - requestImage(${x},${y},${level}): no data returned`);
|
|
888
|
+
return undefined;
|
|
889
|
+
}
|
|
890
|
+
log(`v-map - cesium - geotiff - requestImage(${x},${y},${level}): rgba ${rgbaData.length} bytes, sampleSize=${Math.ceil(this.tileWidth * this.resolution)}`);
|
|
891
|
+
}
|
|
892
|
+
catch (err) {
|
|
893
|
+
this.errorEvent.raiseEvent(err);
|
|
894
|
+
warn('v-map - cesium - getTileData - GeoTIFF tile request failed', err);
|
|
895
|
+
return undefined;
|
|
896
|
+
}
|
|
897
|
+
try {
|
|
898
|
+
const result = await this.createFlippedImageFromRGBA(rgbaData);
|
|
899
|
+
log(`v-map - cesium - geotiff - requestImage(${x},${y},${level}): result=${result?.constructor?.name ?? 'undefined'}, size=${result instanceof HTMLCanvasElement ? `${result.width}x${result.height}` : result instanceof ImageBitmap ? `${result.width}x${result.height}` : 'n/a'}`);
|
|
900
|
+
return result;
|
|
901
|
+
}
|
|
902
|
+
catch (err) {
|
|
903
|
+
this.errorEvent.raiseEvent(err);
|
|
904
|
+
warn('v-map - cesium - createFlippedImageFromRGBA - GeoTIFF tile request failed', err);
|
|
905
|
+
return undefined;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
pickFeatures() {
|
|
909
|
+
return undefined;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
const LOG_PREFIX = 'v-map - cesium - terrain-geotiff - ';
|
|
914
|
+
/**
|
|
915
|
+
* Custom Cesium Terrain Provider for GeoTIFF elevation data
|
|
916
|
+
*
|
|
917
|
+
* This provider loads a GeoTIFF file containing elevation data and provides
|
|
918
|
+
* it to Cesium's terrain system as a heightmap.
|
|
919
|
+
*/
|
|
920
|
+
class CesiumGeoTIFFTerrainProvider {
|
|
921
|
+
Cesium;
|
|
922
|
+
image;
|
|
923
|
+
fromProjection = 'EPSG:4326';
|
|
924
|
+
sourceBounds = [0, 0, 0, 0];
|
|
925
|
+
wgs84Bounds = [0, 0, 0, 0];
|
|
926
|
+
width = 0;
|
|
927
|
+
height = 0;
|
|
928
|
+
noDataValue = 0;
|
|
929
|
+
ready = false;
|
|
930
|
+
_readyPromise;
|
|
931
|
+
heightmapWidth = 65;
|
|
932
|
+
heightmapHeight = 65;
|
|
933
|
+
proj4;
|
|
934
|
+
tilingScheme;
|
|
935
|
+
constructor(options) {
|
|
936
|
+
this.Cesium = options.Cesium;
|
|
937
|
+
// Initialize with GeographicTilingScheme (WGS84)
|
|
938
|
+
this.tilingScheme = new this.Cesium.GeographicTilingScheme();
|
|
939
|
+
// Start loading the GeoTIFF
|
|
940
|
+
this._readyPromise = this.initialize(options);
|
|
941
|
+
}
|
|
942
|
+
async initialize(options) {
|
|
943
|
+
try {
|
|
944
|
+
log(`${LOG_PREFIX}loadGeoTIFF: url=${options.url}`);
|
|
945
|
+
const [geotiffModule, { default: proj4 }, geokeysModule] = await Promise.all([
|
|
946
|
+
import('./geotiff-BEWxTIfH.js').then(function (n) { return n.g; }),
|
|
947
|
+
import('./index-RpJarvr_.js'),
|
|
948
|
+
import('./main-dist-CwnA7_Xn.js').then(function (n) { return n.m; }),
|
|
949
|
+
]);
|
|
950
|
+
const source = await loadGeoTIFFSource(options.url, {
|
|
951
|
+
projection: options.projection,
|
|
952
|
+
forceProjection: options.forceProjection ?? false,
|
|
953
|
+
nodata: options.nodata,
|
|
954
|
+
}, {
|
|
955
|
+
geotiff: geotiffModule,
|
|
956
|
+
proj4,
|
|
957
|
+
geokeysToProj4: geokeysModule,
|
|
958
|
+
});
|
|
959
|
+
this.image = source.baseImage;
|
|
960
|
+
this.fromProjection = source.fromProjection;
|
|
961
|
+
this.sourceBounds = source.sourceBounds;
|
|
962
|
+
this.wgs84Bounds = source.wgs84Bounds;
|
|
963
|
+
this.width = source.width;
|
|
964
|
+
this.height = source.height;
|
|
965
|
+
this.noDataValue = source.noDataValue ?? 0;
|
|
966
|
+
this.proj4 = source.proj4; // Store proj4 instance with registered projections
|
|
967
|
+
log(`${LOG_PREFIX}loaded: projection=${this.fromProjection}, bounds=[${this.sourceBounds.map(v => v.toFixed(0)).join(',')}], wgs84=[${this.wgs84Bounds.map(v => v.toFixed(4)).join(',')}], size=${this.width}x${this.height}`);
|
|
968
|
+
this.ready = true;
|
|
969
|
+
return true;
|
|
970
|
+
}
|
|
971
|
+
catch (err) {
|
|
972
|
+
error(`${LOG_PREFIX}failed to load GeoTIFF:`, err);
|
|
973
|
+
this.ready = false;
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Get the coverage rectangle in WGS84 coordinates
|
|
979
|
+
*/
|
|
980
|
+
get rectangle() {
|
|
981
|
+
if (!this.ready || !this.wgs84Bounds) {
|
|
982
|
+
return this.Cesium.Rectangle.MAX_VALUE;
|
|
983
|
+
}
|
|
984
|
+
const [west, south, east, north] = this.wgs84Bounds;
|
|
985
|
+
return this.Cesium.Rectangle.fromDegrees(west, south, east, north);
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Request tile geometry for a specific tile
|
|
989
|
+
*/
|
|
990
|
+
async requestTileGeometry(x, y, level) {
|
|
991
|
+
if (!this.ready || !this.image) {
|
|
992
|
+
return undefined;
|
|
993
|
+
}
|
|
994
|
+
try {
|
|
995
|
+
// Get tile bounds in WGS84
|
|
996
|
+
const rectangle = this.tilingScheme.tileXYToRectangle(x, y, level);
|
|
997
|
+
let west = this.Cesium.Math.toDegrees(rectangle.west);
|
|
998
|
+
let south = this.Cesium.Math.toDegrees(rectangle.south);
|
|
999
|
+
let east = this.Cesium.Math.toDegrees(rectangle.east);
|
|
1000
|
+
let north = this.Cesium.Math.toDegrees(rectangle.north);
|
|
1001
|
+
// Get GeoTIFF bounds in WGS84
|
|
1002
|
+
const [geoWest, geoSouth, geoEast, geoNorth] = this.wgs84Bounds;
|
|
1003
|
+
// Check if tile intersects with GeoTIFF bounds
|
|
1004
|
+
if (east < geoWest ||
|
|
1005
|
+
west > geoEast ||
|
|
1006
|
+
north < geoSouth ||
|
|
1007
|
+
south > geoNorth) {
|
|
1008
|
+
// Tile is completely outside GeoTIFF bounds, return flat heightmap
|
|
1009
|
+
return this.createFlatHeightmap();
|
|
1010
|
+
}
|
|
1011
|
+
// Clamp tile bounds to GeoTIFF coverage area
|
|
1012
|
+
// This prevents transformation errors when the GeoTIFF projection
|
|
1013
|
+
// doesn't support the full WGS84 range (e.g., Mercator and poles)
|
|
1014
|
+
west = Math.max(geoWest, Math.min(geoEast, west));
|
|
1015
|
+
east = Math.max(geoWest, Math.min(geoEast, east));
|
|
1016
|
+
south = Math.max(geoSouth, Math.min(geoNorth, south));
|
|
1017
|
+
north = Math.max(geoSouth, Math.min(geoNorth, north));
|
|
1018
|
+
// Transform tile bounds to source projection
|
|
1019
|
+
// Use the stored proj4 instance that has the projection definitions
|
|
1020
|
+
const transformToSource = (coord) => {
|
|
1021
|
+
try {
|
|
1022
|
+
return this.proj4('EPSG:4326', this.fromProjection, coord);
|
|
1023
|
+
}
|
|
1024
|
+
catch (err) {
|
|
1025
|
+
warn(`${LOG_PREFIX}transform failed:`, err);
|
|
1026
|
+
return coord;
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
const swSource = transformToSource([west, south]);
|
|
1030
|
+
const neSource = transformToSource([east, north]);
|
|
1031
|
+
// Calculate pixel coordinates in GeoTIFF
|
|
1032
|
+
const [srcWest, srcSouth, srcEast, srcNorth] = this.sourceBounds;
|
|
1033
|
+
const srcWidth = this.width;
|
|
1034
|
+
const srcHeight = this.height;
|
|
1035
|
+
const pixelWidth = srcEast - srcWest;
|
|
1036
|
+
const pixelHeight = srcNorth - srcSouth;
|
|
1037
|
+
const x0 = Math.floor(((swSource[0] - srcWest) / pixelWidth) * srcWidth);
|
|
1038
|
+
const y0 = Math.floor(((srcNorth - neSource[1]) / pixelHeight) * srcHeight);
|
|
1039
|
+
const x1 = Math.ceil(((neSource[0] - srcWest) / pixelWidth) * srcWidth);
|
|
1040
|
+
const y1 = Math.ceil(((srcNorth - swSource[1]) / pixelHeight) * srcHeight);
|
|
1041
|
+
// Clamp to image bounds
|
|
1042
|
+
const windowX = Math.max(0, Math.min(x0, srcWidth));
|
|
1043
|
+
const windowY = Math.max(0, Math.min(y0, srcHeight));
|
|
1044
|
+
const windowWidth = Math.max(1, Math.min(x1 - x0, srcWidth - windowX));
|
|
1045
|
+
const windowHeight = Math.max(1, Math.min(y1 - y0, srcHeight - windowY));
|
|
1046
|
+
// Read elevation data from GeoTIFF
|
|
1047
|
+
const rasterData = await this.image.readRasters({
|
|
1048
|
+
window: [
|
|
1049
|
+
windowX,
|
|
1050
|
+
windowY,
|
|
1051
|
+
windowX + windowWidth,
|
|
1052
|
+
windowY + windowHeight,
|
|
1053
|
+
],
|
|
1054
|
+
width: this.heightmapWidth,
|
|
1055
|
+
height: this.heightmapHeight,
|
|
1056
|
+
resampleMethod: 'bilinear',
|
|
1057
|
+
});
|
|
1058
|
+
// Convert to heightmap array (first band contains elevation)
|
|
1059
|
+
const elevationData = rasterData[0];
|
|
1060
|
+
const buffer = new Float32Array(this.heightmapWidth * this.heightmapHeight);
|
|
1061
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
1062
|
+
let value = elevationData[i];
|
|
1063
|
+
// Replace nodata values with 0
|
|
1064
|
+
if (value === this.noDataValue || !isFinite(value)) {
|
|
1065
|
+
value = 0;
|
|
1066
|
+
}
|
|
1067
|
+
buffer[i] = value;
|
|
1068
|
+
}
|
|
1069
|
+
// Create Cesium HeightmapTerrainData
|
|
1070
|
+
return new this.Cesium.HeightmapTerrainData({
|
|
1071
|
+
buffer,
|
|
1072
|
+
width: this.heightmapWidth,
|
|
1073
|
+
height: this.heightmapHeight,
|
|
1074
|
+
childTileMask: 0,
|
|
1075
|
+
structure: {
|
|
1076
|
+
heightScale: 1.0,
|
|
1077
|
+
heightOffset: 0.0,
|
|
1078
|
+
elementsPerHeight: 1,
|
|
1079
|
+
stride: 1,
|
|
1080
|
+
elementMultiplier: 1.0,
|
|
1081
|
+
},
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
catch (err) {
|
|
1085
|
+
warn(`${LOG_PREFIX}failed to load tile geometry:`, err);
|
|
1086
|
+
return this.createFlatHeightmap();
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Create a flat heightmap for tiles outside the GeoTIFF bounds
|
|
1091
|
+
*/
|
|
1092
|
+
createFlatHeightmap() {
|
|
1093
|
+
const buffer = new Float32Array(this.heightmapWidth * this.heightmapHeight);
|
|
1094
|
+
buffer.fill(0);
|
|
1095
|
+
return new this.Cesium.HeightmapTerrainData({
|
|
1096
|
+
buffer,
|
|
1097
|
+
width: this.heightmapWidth,
|
|
1098
|
+
height: this.heightmapHeight,
|
|
1099
|
+
childTileMask: 0,
|
|
1100
|
+
});
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Get the availability of tiles
|
|
1104
|
+
*/
|
|
1105
|
+
get availability() {
|
|
1106
|
+
// For now, we say all tiles are available
|
|
1107
|
+
// In a more sophisticated implementation, we'd track which tiles
|
|
1108
|
+
// intersect with the GeoTIFF bounds
|
|
1109
|
+
return undefined;
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Get the tiling scheme
|
|
1113
|
+
*/
|
|
1114
|
+
getTilingScheme() {
|
|
1115
|
+
return this.tilingScheme;
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* Get the maximum geometric error allowed at a specific level
|
|
1119
|
+
* Required by Cesium's TerrainProvider interface
|
|
1120
|
+
*
|
|
1121
|
+
* The geometric error is the difference (in meters) between the actual terrain
|
|
1122
|
+
* and the terrain approximation at this level. Higher levels have lower error.
|
|
1123
|
+
*/
|
|
1124
|
+
getLevelMaximumGeometricError(level) {
|
|
1125
|
+
// Standard geometric error calculation for terrain providers
|
|
1126
|
+
// Based on Cesium's approach: error decreases exponentially with level
|
|
1127
|
+
// Formula: maximumRadius / (tileWidth * (2^level))
|
|
1128
|
+
const ellipsoid = this.tilingScheme.ellipsoid;
|
|
1129
|
+
const maximumRadius = ellipsoid.maximumRadius;
|
|
1130
|
+
const tileWidth = 65; // Standard heightmap width
|
|
1131
|
+
return maximumRadius / (tileWidth * Math.pow(2, level));
|
|
1132
|
+
}
|
|
1133
|
+
loadTileDataAvailability(_x, _y, _level) {
|
|
1134
|
+
return undefined;
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Check if tile data is available for a specific tile
|
|
1138
|
+
* Required by Cesium's TerrainProvider interface
|
|
1139
|
+
*/
|
|
1140
|
+
getTileDataAvailable(x, y, level) {
|
|
1141
|
+
if (!this.ready) {
|
|
1142
|
+
return false;
|
|
1143
|
+
}
|
|
1144
|
+
// Check if tile intersects with GeoTIFF bounds
|
|
1145
|
+
const rectangle = this.tilingScheme.tileXYToRectangle(x, y, level);
|
|
1146
|
+
const west = this.Cesium.Math.toDegrees(rectangle.west);
|
|
1147
|
+
const south = this.Cesium.Math.toDegrees(rectangle.south);
|
|
1148
|
+
const east = this.Cesium.Math.toDegrees(rectangle.east);
|
|
1149
|
+
const north = this.Cesium.Math.toDegrees(rectangle.north);
|
|
1150
|
+
const [geoWest, geoSouth, geoEast, geoNorth] = this.wgs84Bounds;
|
|
1151
|
+
// Return true if tile intersects with GeoTIFF bounds
|
|
1152
|
+
return !(east < geoWest ||
|
|
1153
|
+
west > geoEast ||
|
|
1154
|
+
north < geoSouth ||
|
|
1155
|
+
south > geoNorth);
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1158
|
+
* Check if the provider is ready
|
|
1159
|
+
*/
|
|
1160
|
+
get readyPromise() {
|
|
1161
|
+
return this._readyPromise;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Get the credit to display
|
|
1165
|
+
*/
|
|
1166
|
+
get credit() {
|
|
1167
|
+
return new this.Cesium.Credit('GeoTIFF Terrain');
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* Check if the provider has water mask
|
|
1171
|
+
*/
|
|
1172
|
+
get hasWaterMask() {
|
|
1173
|
+
return false;
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* Check if the provider has vertex normals
|
|
1177
|
+
*/
|
|
1178
|
+
get hasVertexNormals() {
|
|
1179
|
+
return false;
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* Get the error event
|
|
1183
|
+
*/
|
|
1184
|
+
get errorEvent() {
|
|
1185
|
+
return new this.Cesium.Event();
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Factory function to create a CesiumGeoTIFFTerrainProvider
|
|
1190
|
+
*/
|
|
1191
|
+
async function createCesiumGeoTIFFTerrainProvider(options) {
|
|
1192
|
+
const provider = new CesiumGeoTIFFTerrainProvider(options);
|
|
1193
|
+
await provider.readyPromise;
|
|
1194
|
+
return provider;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// CesiumProvider.ts – relevante Ergänzungen
|
|
1198
|
+
const TERRAIN_GEOTIFF_LOG_PREFIX = 'v-map - cesium - terrain-geotiff - ';
|
|
1199
|
+
/**
|
|
1200
|
+
* Entfernt das von Cesium injectWidgetsCss() eingefügte CSS.
|
|
1201
|
+
* Funktioniert sowohl, wenn das Element eine ID hat,
|
|
1202
|
+
* als auch wenn es keine ID besitzt (neue Cesium‑Versionen).
|
|
1203
|
+
*/
|
|
1204
|
+
function removeCesiumWidgetsCss(shadowRoot) {
|
|
1205
|
+
if (!shadowRoot)
|
|
1206
|
+
return;
|
|
1207
|
+
// NodeList → echtes Array konvertieren
|
|
1208
|
+
const styles = Array.from(shadowRoot.querySelectorAll('style'));
|
|
1209
|
+
for (const style of styles) {
|
|
1210
|
+
if (style.textContent?.includes('.cesium-credit-lightbox-overlay')) {
|
|
1211
|
+
style.remove(); // modernes DOM‑API
|
|
1212
|
+
// oder für sehr alte Browser:
|
|
1213
|
+
// style.parentNode?.removeChild(style);
|
|
1214
|
+
log('v-map - provider - cesium - Cesium‑Widget‑CSS entfernt');
|
|
1215
|
+
break; // wir haben das gesuchte Style‑Tag gefunden
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
class CesiumTerrainLayer {
|
|
1220
|
+
Cesium;
|
|
1221
|
+
viewer;
|
|
1222
|
+
provider;
|
|
1223
|
+
options;
|
|
1224
|
+
opacity = 1;
|
|
1225
|
+
previousProvider;
|
|
1226
|
+
constructor(Cesium, viewer, provider, options) {
|
|
1227
|
+
this.Cesium = Cesium;
|
|
1228
|
+
this.viewer = viewer;
|
|
1229
|
+
this.provider = provider;
|
|
1230
|
+
this.options = options ?? {};
|
|
1231
|
+
this.previousProvider = viewer.terrainProvider;
|
|
1232
|
+
this.viewer.terrainProvider = this.provider;
|
|
1233
|
+
}
|
|
1234
|
+
getOptions() {
|
|
1235
|
+
return this.options;
|
|
1236
|
+
}
|
|
1237
|
+
setOptions(options) {
|
|
1238
|
+
this.options = options;
|
|
1239
|
+
}
|
|
1240
|
+
getVisible() {
|
|
1241
|
+
return this.viewer.scene.globe.show;
|
|
1242
|
+
}
|
|
1243
|
+
setVisible(value) {
|
|
1244
|
+
this.viewer.scene.globe.show = value;
|
|
1245
|
+
}
|
|
1246
|
+
getOpacity() {
|
|
1247
|
+
return this.opacity;
|
|
1248
|
+
}
|
|
1249
|
+
setOpacity(value) {
|
|
1250
|
+
this.opacity = value;
|
|
1251
|
+
const globe = this.viewer.scene.globe;
|
|
1252
|
+
if (!globe.translucency) {
|
|
1253
|
+
try {
|
|
1254
|
+
globe.translucency = new this.Cesium.GlobeTranslucency();
|
|
1255
|
+
globe.translucency.enabled = true;
|
|
1256
|
+
}
|
|
1257
|
+
catch (e) {
|
|
1258
|
+
warn('Cesium terrain opacity not supported', e);
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
globe.translucency.enabled = value < 1;
|
|
1263
|
+
globe.translucency.frontFaceAlpha = value;
|
|
1264
|
+
}
|
|
1265
|
+
getZIndex() {
|
|
1266
|
+
return 0;
|
|
1267
|
+
}
|
|
1268
|
+
async setZIndex(_zIndex) {
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
remove() {
|
|
1272
|
+
try {
|
|
1273
|
+
this.viewer.terrainProvider = this.previousProvider
|
|
1274
|
+
? this.previousProvider
|
|
1275
|
+
: new this.Cesium.EllipsoidTerrainProvider();
|
|
1276
|
+
this.viewer.scene.globe.show = true;
|
|
1277
|
+
}
|
|
1278
|
+
catch (error) {
|
|
1279
|
+
warn('Cesium terrain reset failed', error);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
class CesiumProvider {
|
|
1284
|
+
viewer;
|
|
1285
|
+
Cesium;
|
|
1286
|
+
layerManager;
|
|
1287
|
+
shadowRoot;
|
|
1288
|
+
layerGroups = new CesiumLayerGroups();
|
|
1289
|
+
layerManagerMutex = new AsyncMutex();
|
|
1290
|
+
layerErrorCallbacks = new Map();
|
|
1291
|
+
layerErrorCleanups = new Map();
|
|
1292
|
+
async init(options) {
|
|
1293
|
+
this.shadowRoot = options.shadowRoot;
|
|
1294
|
+
const sr = options.target.getRootNode() instanceof ShadowRoot
|
|
1295
|
+
? options.target.getRootNode()
|
|
1296
|
+
: undefined;
|
|
1297
|
+
await injectWidgetsCss(sr);
|
|
1298
|
+
this.Cesium = await loadCesium();
|
|
1299
|
+
/*
|
|
1300
|
+
this.viewer = new this.Cesium.Viewer(container, {
|
|
1301
|
+
terrainProvider: await this.Cesium.createWorldTerrainAsync(),
|
|
1302
|
+
...options,
|
|
1303
|
+
});
|
|
1304
|
+
*/
|
|
1305
|
+
Cesium.Ion.defaultAccessToken = null;
|
|
1306
|
+
this.viewer = new this.Cesium.Viewer(options.target, {
|
|
1307
|
+
baseLayer: false,
|
|
1308
|
+
baseLayerPicker: false, // Remove the base layer picker if you don’t need to switch layers
|
|
1309
|
+
terrainProvider: new Cesium.EllipsoidTerrainProvider(), // Use a simple ellipsoid terrain
|
|
1310
|
+
});
|
|
1311
|
+
//this.viewer.scene.terrainProvider..removeAll();
|
|
1312
|
+
this.viewer.scene.primitives.removeAll();
|
|
1313
|
+
this.viewer.scene.backgroundColor = this.Cesium.Color.WHITE;
|
|
1314
|
+
this.viewer.scene.globe.baseColor = this.Cesium.Color.WHITE;
|
|
1315
|
+
this.viewer.scene.globe.depthTestAgainstTerrain = false;
|
|
1316
|
+
// this.viewer.terrainProvider = null;
|
|
1317
|
+
/*
|
|
1318
|
+
if (options.center) {
|
|
1319
|
+
await this.viewer.camera.flyTo({
|
|
1320
|
+
destination: this.Cesium.Cartesian3.fromDegrees(
|
|
1321
|
+
options.center.longitude,
|
|
1322
|
+
options.center.latitude,
|
|
1323
|
+
1000,
|
|
1324
|
+
),
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
*/
|
|
1328
|
+
this.layerManager = new LayerManager(this.Cesium, this.viewer);
|
|
1329
|
+
}
|
|
1330
|
+
async destroy() {
|
|
1331
|
+
removeCesiumWidgetsCss(this.shadowRoot);
|
|
1332
|
+
this.viewer?.destroy();
|
|
1333
|
+
this.viewer = undefined;
|
|
1334
|
+
}
|
|
1335
|
+
async createLayer(layerConfig, layerId) {
|
|
1336
|
+
let wrapper = null;
|
|
1337
|
+
switch (layerConfig.type) {
|
|
1338
|
+
case 'geojson': {
|
|
1339
|
+
const options = {
|
|
1340
|
+
// clampToGround: true,
|
|
1341
|
+
//fill: Cesium.Color.RED,
|
|
1342
|
+
};
|
|
1343
|
+
const geojsonConfig = layerConfig;
|
|
1344
|
+
const ds = await this.createGeoJSONLayer(geojsonConfig, options);
|
|
1345
|
+
wrapper = this.layerManager.addLayer(layerId, ds);
|
|
1346
|
+
wrapper.setOptions(options);
|
|
1347
|
+
break;
|
|
1348
|
+
}
|
|
1349
|
+
case 'osm': {
|
|
1350
|
+
const iLayer = await this.createOSMLayer(layerConfig);
|
|
1351
|
+
wrapper = this.layerManager.addLayer(layerId, iLayer);
|
|
1352
|
+
break;
|
|
1353
|
+
}
|
|
1354
|
+
case 'google': {
|
|
1355
|
+
const iLayer = await this.createGoogleLayer(layerConfig);
|
|
1356
|
+
wrapper = this.layerManager.addLayer(layerId, iLayer);
|
|
1357
|
+
break;
|
|
1358
|
+
}
|
|
1359
|
+
case 'terrain': {
|
|
1360
|
+
const terrainLayer = await this.createTerrainLayer(layerConfig);
|
|
1361
|
+
wrapper = this.layerManager.addCustomLayer(layerId, terrainLayer);
|
|
1362
|
+
break;
|
|
1363
|
+
}
|
|
1364
|
+
case 'xyz': {
|
|
1365
|
+
const iLayer = await this.createXYZLayer(layerConfig);
|
|
1366
|
+
wrapper = this.layerManager.addLayer(layerId, iLayer);
|
|
1367
|
+
break;
|
|
1368
|
+
}
|
|
1369
|
+
case 'wms': {
|
|
1370
|
+
const iLayer = await this.addWMSLayer(layerConfig);
|
|
1371
|
+
wrapper = this.layerManager.addLayer(layerId, iLayer);
|
|
1372
|
+
break;
|
|
1373
|
+
}
|
|
1374
|
+
case 'wcs': {
|
|
1375
|
+
const iLayer = await this.createWCSLayer(layerConfig);
|
|
1376
|
+
wrapper = this.layerManager.addLayer(layerId, iLayer);
|
|
1377
|
+
break;
|
|
1378
|
+
}
|
|
1379
|
+
case 'arcgis': {
|
|
1380
|
+
await this.addArcGISLayer(layerConfig);
|
|
1381
|
+
//todo wrapper = this.layerManager.addLayer(layerId, iLayer);
|
|
1382
|
+
break;
|
|
1383
|
+
}
|
|
1384
|
+
case 'wfs': {
|
|
1385
|
+
const options = { clampToGround: true };
|
|
1386
|
+
const wfsConfig = layerConfig;
|
|
1387
|
+
const ds = await this.createWFSLayer(wfsConfig, options);
|
|
1388
|
+
wrapper = this.layerManager.addLayer(layerId, ds);
|
|
1389
|
+
wrapper.setOptions(options);
|
|
1390
|
+
break;
|
|
1391
|
+
}
|
|
1392
|
+
case 'wkt': {
|
|
1393
|
+
const options = { clampToGround: true };
|
|
1394
|
+
const wktConfig = layerConfig;
|
|
1395
|
+
const ds = await this.createWKTLayer(wktConfig, options);
|
|
1396
|
+
wrapper = this.layerManager.addLayer(layerId, ds);
|
|
1397
|
+
wrapper.setOptions(options);
|
|
1398
|
+
break;
|
|
1399
|
+
}
|
|
1400
|
+
case 'geotiff': {
|
|
1401
|
+
const iLayer = await this.createGeoTIFFLayer(layerConfig);
|
|
1402
|
+
wrapper = this.layerManager.addLayer(layerId, iLayer);
|
|
1403
|
+
break;
|
|
1404
|
+
}
|
|
1405
|
+
case 'tile3d': {
|
|
1406
|
+
const tileset = await this.createTile3DLayer(layerConfig);
|
|
1407
|
+
wrapper = this.layerManager.addLayer(layerId, tileset);
|
|
1408
|
+
const tile3dConfig = layerConfig;
|
|
1409
|
+
wrapper.setOptions(tile3dConfig.tilesetOptions ?? {});
|
|
1410
|
+
if (tile3dConfig.cesiumStyle && 'setStyle' in wrapper) {
|
|
1411
|
+
wrapper.setStyle(tile3dConfig.cesiumStyle);
|
|
1412
|
+
}
|
|
1413
|
+
break;
|
|
1414
|
+
}
|
|
1415
|
+
case 'terrain-geotiff': {
|
|
1416
|
+
const terrainLayer = await this.createGeoTIFFTerrainLayer(layerConfig);
|
|
1417
|
+
wrapper = this.layerManager.addCustomLayer(layerId, terrainLayer);
|
|
1418
|
+
break;
|
|
1419
|
+
}
|
|
1420
|
+
default:
|
|
1421
|
+
throw new Error(`Unsupported layer type: ${layerConfig.type}`);
|
|
1422
|
+
}
|
|
1423
|
+
if (!wrapper)
|
|
1424
|
+
return null;
|
|
1425
|
+
// zIndex/Opacity/Visible zuerst auf dem Layer anwenden (bleiben „Originalzustand“ der Gruppe)
|
|
1426
|
+
const commonProps = layerConfig;
|
|
1427
|
+
if (commonProps.zIndex !== undefined)
|
|
1428
|
+
await wrapper.setZIndex(commonProps.zIndex);
|
|
1429
|
+
if (commonProps.opacity !== undefined)
|
|
1430
|
+
wrapper.setOpacity(commonProps.opacity);
|
|
1431
|
+
if (commonProps.visible !== undefined)
|
|
1432
|
+
wrapper.setVisible(commonProps.visible);
|
|
1433
|
+
return wrapper;
|
|
1434
|
+
}
|
|
1435
|
+
// ---------- Layer anlegen (mit Group & Basemap-Key) ----------
|
|
1436
|
+
async addLayerToGroup(layerConfig) {
|
|
1437
|
+
return await this.layerManagerMutex.runExclusive(async () => {
|
|
1438
|
+
const layerId = crypto.randomUUID();
|
|
1439
|
+
const wrapper = await this.createLayer(layerConfig, layerId);
|
|
1440
|
+
// >>> In Gruppenverwaltung registrieren (inkl. Basemap-Key)
|
|
1441
|
+
const elementId = layerConfig.layerElementId ??
|
|
1442
|
+
layerConfig.elementId ??
|
|
1443
|
+
null;
|
|
1444
|
+
this.layerGroups.addLayerToGroup(layerConfig.groupId, typeof layerConfig.groupVisible !== undefined
|
|
1445
|
+
? layerConfig.groupVisible
|
|
1446
|
+
: true, {
|
|
1447
|
+
id: layerId,
|
|
1448
|
+
elementId,
|
|
1449
|
+
layer: wrapper,
|
|
1450
|
+
});
|
|
1451
|
+
// Regeln anwenden (sichtbar/basemap)
|
|
1452
|
+
this.layerGroups.apply();
|
|
1453
|
+
return layerId;
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
// ---------- Basemap-API analog deck ----------
|
|
1457
|
+
async setBaseLayer(groupId, layerElementId) {
|
|
1458
|
+
await this.layerManagerMutex.runExclusive(async () => {
|
|
1459
|
+
this.layerGroups.setBasemap(groupId, layerElementId ?? null);
|
|
1460
|
+
this.layerGroups.apply();
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
// Optional: Helper wie in deck.addBaseLayer(...)
|
|
1464
|
+
async addBaseLayer(layerConfig, basemapid, layerElementId) {
|
|
1465
|
+
if (!layerElementId || !basemapid)
|
|
1466
|
+
return null;
|
|
1467
|
+
return await this.layerManagerMutex.runExclusive(async () => {
|
|
1468
|
+
const layerId = crypto.randomUUID();
|
|
1469
|
+
const wrapper = await this.createLayer(layerConfig, layerId);
|
|
1470
|
+
this.layerGroups.addLayerToGroup(layerConfig.groupId, typeof layerConfig.groupVisible !== undefined
|
|
1471
|
+
? layerConfig.groupVisible
|
|
1472
|
+
: true, {
|
|
1473
|
+
id: layerId,
|
|
1474
|
+
elementId: layerElementId,
|
|
1475
|
+
layer: wrapper,
|
|
1476
|
+
});
|
|
1477
|
+
this.layerGroups.setBasemap(layerConfig.groupId ?? 'basemap', basemapid);
|
|
1478
|
+
this.layerGroups.apply();
|
|
1479
|
+
return layerId;
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
async ensureGroup(groupId, visible, _opts) {
|
|
1483
|
+
this.layerGroups.ensureGroup(groupId, visible);
|
|
1484
|
+
}
|
|
1485
|
+
// ---------- Sichtbarkeit/Z-Index/Opacity bleiben wie gehabt ----------
|
|
1486
|
+
async setGroupVisible(groupId, visible) {
|
|
1487
|
+
this.layerGroups.setGroupVisible(groupId, visible);
|
|
1488
|
+
this.layerGroups.apply();
|
|
1489
|
+
}
|
|
1490
|
+
// ── Runtime error listeners ──────────────────────────────────────
|
|
1491
|
+
onLayerError(layerId, callback) {
|
|
1492
|
+
this.layerErrorCallbacks.set(layerId, callback);
|
|
1493
|
+
this.attachCesiumErrorListeners(layerId);
|
|
1494
|
+
}
|
|
1495
|
+
offLayerError(layerId) {
|
|
1496
|
+
this.layerErrorCleanups.get(layerId)?.();
|
|
1497
|
+
this.layerErrorCleanups.delete(layerId);
|
|
1498
|
+
this.layerErrorCallbacks.delete(layerId);
|
|
1499
|
+
}
|
|
1500
|
+
attachCesiumErrorListeners(layerId) {
|
|
1501
|
+
this.layerErrorCleanups.get(layerId)?.();
|
|
1502
|
+
const cb = this.layerErrorCallbacks.get(layerId);
|
|
1503
|
+
if (!cb)
|
|
1504
|
+
return;
|
|
1505
|
+
const iLayer = this.layerManager.getLayer(layerId);
|
|
1506
|
+
if (!iLayer)
|
|
1507
|
+
return;
|
|
1508
|
+
const cleanups = [];
|
|
1509
|
+
const handler = () => { cb({ type: 'network', message: 'Tile load error' }); };
|
|
1510
|
+
// ImageryLayer: access provider.errorEvent
|
|
1511
|
+
const nativeLayer = iLayer._imageryLayer;
|
|
1512
|
+
if (nativeLayer?.imageryProvider?.errorEvent) {
|
|
1513
|
+
const unsub = nativeLayer.imageryProvider.errorEvent.addEventListener(handler);
|
|
1514
|
+
cleanups.push(unsub);
|
|
1515
|
+
}
|
|
1516
|
+
// Cesium3DTileset: tileFailed event
|
|
1517
|
+
const tileset = iLayer._tileset;
|
|
1518
|
+
if (tileset?.tileFailed) {
|
|
1519
|
+
const unsub = tileset.tileFailed.addEventListener(handler);
|
|
1520
|
+
cleanups.push(unsub);
|
|
1521
|
+
}
|
|
1522
|
+
if (cleanups.length > 0) {
|
|
1523
|
+
this.layerErrorCleanups.set(layerId, () => cleanups.forEach(fn => fn()));
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
async removeLayer(layerId) {
|
|
1527
|
+
if (!layerId)
|
|
1528
|
+
return;
|
|
1529
|
+
this.offLayerError(layerId);
|
|
1530
|
+
await this.layerManagerMutex.runExclusive(async () => {
|
|
1531
|
+
this.layerManager.removeLayer(layerId);
|
|
1532
|
+
this.layerGroups.removeLayer(layerId, true);
|
|
1533
|
+
this.layerGroups.apply();
|
|
1534
|
+
});
|
|
1535
|
+
}
|
|
1536
|
+
// updateLayer, setOpacity, setZIndex, setVisible bleiben – du änderst damit den
|
|
1537
|
+
// „Originalzustand“ der Layer. Danach LayerGroups.apply() aufrufen, damit
|
|
1538
|
+
// Gruppen-/Basemap-Regeln sofort wieder durchgesetzt werden:
|
|
1539
|
+
async setOpacity(layerId, opacity) {
|
|
1540
|
+
this.layerManager.setOpacity(layerId, opacity);
|
|
1541
|
+
this.layerGroups.apply();
|
|
1542
|
+
}
|
|
1543
|
+
async setVisible(layerId, visible) {
|
|
1544
|
+
this.layerManager.setVisible(layerId, visible);
|
|
1545
|
+
this.layerGroups.apply();
|
|
1546
|
+
}
|
|
1547
|
+
async setZIndex(layerId, zIndex) {
|
|
1548
|
+
// Note: layerManager.setZIndex calls layer.setZIndex which is async (returns Promise<void>)
|
|
1549
|
+
// even though the manager method itself is not marked as async. The await is kept here
|
|
1550
|
+
// for future compatibility when the manager method becomes properly async.
|
|
1551
|
+
await this.layerManager.setZIndex(layerId, zIndex);
|
|
1552
|
+
// Z-Order ist unabhängig von Basemap/Group-Visible, aber apply() schadet nicht
|
|
1553
|
+
this.layerGroups.apply();
|
|
1554
|
+
}
|
|
1555
|
+
// ========== Enhanced Styling Helper Methods ==========
|
|
1556
|
+
/**
|
|
1557
|
+
* Apply Geostyler styling to a GeoJsonDataSource
|
|
1558
|
+
*/
|
|
1559
|
+
applyGeostylerStyling(dataSource, geostylerStyle) {
|
|
1560
|
+
dataSource.__vmapLockOpacity = true;
|
|
1561
|
+
// Helper to extract static value from GeoStyler property
|
|
1562
|
+
const getValue = (prop, defaultValue) => {
|
|
1563
|
+
if (prop === undefined || prop === null)
|
|
1564
|
+
return defaultValue;
|
|
1565
|
+
// If it's a GeoStyler function object, we can't evaluate it here - return default
|
|
1566
|
+
if (typeof prop === 'object' && prop !== null && 'name' in prop)
|
|
1567
|
+
return defaultValue;
|
|
1568
|
+
return prop;
|
|
1569
|
+
};
|
|
1570
|
+
const toNumber = (value, fallback) => {
|
|
1571
|
+
if (value == null)
|
|
1572
|
+
return fallback;
|
|
1573
|
+
if (typeof value === 'number')
|
|
1574
|
+
return value;
|
|
1575
|
+
const n = Number(value);
|
|
1576
|
+
return Number.isFinite(n) ? n : fallback;
|
|
1577
|
+
};
|
|
1578
|
+
const entities = dataSource.entities.values;
|
|
1579
|
+
if (geostylerStyle.rules) {
|
|
1580
|
+
for (const rule of geostylerStyle.rules) {
|
|
1581
|
+
if (rule.symbolizers) {
|
|
1582
|
+
for (const symbolizer of rule.symbolizers) {
|
|
1583
|
+
for (let i = 0; i < entities.length; i++) {
|
|
1584
|
+
const entity = entities[i];
|
|
1585
|
+
switch (symbolizer.kind) {
|
|
1586
|
+
case 'Fill':
|
|
1587
|
+
if (entity.polygon) {
|
|
1588
|
+
const fillColor = getValue(symbolizer.color, 'rgba(0,100,255,0.3)');
|
|
1589
|
+
const fillOpacity = toNumber(getValue(symbolizer.opacity, 0.3), 0.3);
|
|
1590
|
+
const outlineColor = getValue(symbolizer.outlineColor, 'rgba(0,100,255,1)');
|
|
1591
|
+
const outlineWidth = getValue(symbolizer.outlineWidth, 1);
|
|
1592
|
+
let polygonColor = this.parseCesiumColor(fillColor, this.Cesium.Color.BLUE.withAlpha(0.3));
|
|
1593
|
+
if (fillOpacity !== undefined && fillOpacity !== null) {
|
|
1594
|
+
polygonColor = this.applyCesiumOpacity(polygonColor, fillOpacity);
|
|
1595
|
+
}
|
|
1596
|
+
//outline color
|
|
1597
|
+
const outlineCesiumColor = this.parseCesiumColor(outlineColor, this.Cesium.Color.BLUE);
|
|
1598
|
+
log('v-map - provider - cesium - applyGeostylerStyling: Fill', {
|
|
1599
|
+
fillColor,
|
|
1600
|
+
fillOpacity,
|
|
1601
|
+
computedFill: polygonColor?.toString?.(),
|
|
1602
|
+
outlineColor,
|
|
1603
|
+
outlineWidth,
|
|
1604
|
+
});
|
|
1605
|
+
//fill
|
|
1606
|
+
entity.polygon.fill = new this.Cesium.ConstantProperty(true);
|
|
1607
|
+
//fill color
|
|
1608
|
+
entity.polygon.material =
|
|
1609
|
+
new this.Cesium.ColorMaterialProperty(polygonColor);
|
|
1610
|
+
//outline
|
|
1611
|
+
entity.polygon.outline = new this.Cesium.ConstantProperty(true);
|
|
1612
|
+
entity.polygon.outlineColor =
|
|
1613
|
+
new this.Cesium.ConstantProperty(outlineCesiumColor);
|
|
1614
|
+
entity.polygon.outlineWidth =
|
|
1615
|
+
new this.Cesium.ConstantProperty(outlineWidth);
|
|
1616
|
+
//entity.polygon.height = new this.Cesium.ConstantProperty(0);
|
|
1617
|
+
//
|
|
1618
|
+
entity.polygon.extrudedHeight = undefined;
|
|
1619
|
+
entity.polygon.heightReference =
|
|
1620
|
+
new this.Cesium.ConstantProperty(this.Cesium.HeightReference.CLAMP_TO_GROUND);
|
|
1621
|
+
entity.polygon.perPositionHeight =
|
|
1622
|
+
new this.Cesium.ConstantProperty(false);
|
|
1623
|
+
entity.polygon.classificationType =
|
|
1624
|
+
new this.Cesium.ConstantProperty(this.Cesium.ClassificationType.BOTH);
|
|
1625
|
+
}
|
|
1626
|
+
break;
|
|
1627
|
+
case 'Line':
|
|
1628
|
+
if (entity.polyline) {
|
|
1629
|
+
const lineColor = getValue(symbolizer.color, 'rgba(0,100,255,1)');
|
|
1630
|
+
const lineWidth = toNumber(getValue(symbolizer.width, 2), 2);
|
|
1631
|
+
const lineOpacity = toNumber(getValue(symbolizer.opacity, 1), 1);
|
|
1632
|
+
let materialColor = this.parseCesiumColor(lineColor, this.Cesium.Color.BLUE);
|
|
1633
|
+
if (lineOpacity !== undefined && lineOpacity !== null) {
|
|
1634
|
+
materialColor = this.applyCesiumOpacity(materialColor, lineOpacity);
|
|
1635
|
+
}
|
|
1636
|
+
log('v-map - provider - cesium - applyGeostylerStyling: Line', {
|
|
1637
|
+
lineColor,
|
|
1638
|
+
lineOpacity,
|
|
1639
|
+
computedColor: materialColor?.toString?.(),
|
|
1640
|
+
lineWidth,
|
|
1641
|
+
});
|
|
1642
|
+
entity.polyline.material =
|
|
1643
|
+
new this.Cesium.ColorMaterialProperty(materialColor);
|
|
1644
|
+
entity.polyline.width = new this.Cesium.ConstantProperty(lineWidth);
|
|
1645
|
+
}
|
|
1646
|
+
break;
|
|
1647
|
+
case 'Mark':
|
|
1648
|
+
if (entity.point) {
|
|
1649
|
+
const pointColor = getValue(symbolizer.color, 'rgba(0,100,255,1)');
|
|
1650
|
+
const pointRadius = toNumber(getValue(symbolizer.radius, 6), 6);
|
|
1651
|
+
const pointOpacity = toNumber(getValue(symbolizer.opacity, 1), 1);
|
|
1652
|
+
let materialColor = this.parseCesiumColor(pointColor, this.Cesium.Color.BLUE);
|
|
1653
|
+
if (pointOpacity !== undefined && pointOpacity !== null) {
|
|
1654
|
+
materialColor = this.applyCesiumOpacity(materialColor, pointOpacity);
|
|
1655
|
+
}
|
|
1656
|
+
log('v-map - provider - cesium - applyGeostylerStyling: Mark', {
|
|
1657
|
+
pointColor,
|
|
1658
|
+
pointOpacity,
|
|
1659
|
+
computedColor: materialColor?.toString?.(),
|
|
1660
|
+
pointRadius,
|
|
1661
|
+
});
|
|
1662
|
+
entity.point.color = new this.Cesium.ConstantProperty(materialColor);
|
|
1663
|
+
entity.point.pixelSize = new this.Cesium.ConstantProperty(pointRadius);
|
|
1664
|
+
}
|
|
1665
|
+
break;
|
|
1666
|
+
case 'Icon':
|
|
1667
|
+
if (entity.point) {
|
|
1668
|
+
const iconSrc = getValue(symbolizer.image);
|
|
1669
|
+
const iconSize = toNumber(getValue(symbolizer.size, 32), 32);
|
|
1670
|
+
const iconOpacity = toNumber(getValue(symbolizer.opacity, 1), 1);
|
|
1671
|
+
if (iconSrc && typeof iconSrc === 'string') {
|
|
1672
|
+
entity.billboard = new this.Cesium.BillboardGraphics({
|
|
1673
|
+
image: new this.Cesium.ConstantProperty(iconSrc),
|
|
1674
|
+
width: new this.Cesium.ConstantProperty(iconSize),
|
|
1675
|
+
height: new this.Cesium.ConstantProperty(iconSize),
|
|
1676
|
+
verticalOrigin: new this.Cesium.ConstantProperty(this.Cesium.VerticalOrigin.BOTTOM),
|
|
1677
|
+
color: iconOpacity !== undefined && iconOpacity !== null
|
|
1678
|
+
? new this.Cesium.ConstantProperty(this.Cesium.Color.WHITE.withAlpha(iconOpacity))
|
|
1679
|
+
: undefined,
|
|
1680
|
+
});
|
|
1681
|
+
entity.point.show = new this.Cesium.ConstantProperty(false);
|
|
1682
|
+
log('v-map - provider - cesium - applyGeostylerStyling: Icon', {
|
|
1683
|
+
iconSrc,
|
|
1684
|
+
iconSize,
|
|
1685
|
+
iconOpacity,
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
break;
|
|
1690
|
+
case 'Text':
|
|
1691
|
+
const labelExpr = symbolizer.label;
|
|
1692
|
+
const labelProp = typeof labelExpr === 'string' ? labelExpr : undefined;
|
|
1693
|
+
if (labelProp &&
|
|
1694
|
+
entity.properties &&
|
|
1695
|
+
entity.properties[labelProp]) {
|
|
1696
|
+
const textColor = getValue(symbolizer.color, '#000000');
|
|
1697
|
+
const textSize = toNumber(getValue(symbolizer.size, 12), 12);
|
|
1698
|
+
const textOpacity = toNumber(getValue(symbolizer.opacity, 1), 1);
|
|
1699
|
+
let labelColor = this.parseCesiumColor(textColor, this.Cesium.Color.WHITE);
|
|
1700
|
+
if (textOpacity !== undefined && textOpacity !== null) {
|
|
1701
|
+
labelColor = this.applyCesiumOpacity(labelColor, textOpacity);
|
|
1702
|
+
}
|
|
1703
|
+
log('v-map - provider - cesium - applyGeostylerStyling: Text', {
|
|
1704
|
+
labelProp,
|
|
1705
|
+
textColor,
|
|
1706
|
+
textOpacity,
|
|
1707
|
+
computedColor: labelColor?.toString?.(),
|
|
1708
|
+
textSize,
|
|
1709
|
+
});
|
|
1710
|
+
const textValue = entity.properties[labelProp]?.getValue?.(this.viewer.clock.currentTime) ??
|
|
1711
|
+
entity.properties[labelProp]?._value ??
|
|
1712
|
+
'';
|
|
1713
|
+
entity.label = new this.Cesium.LabelGraphics({
|
|
1714
|
+
text: new this.Cesium.ConstantProperty(String(textValue)),
|
|
1715
|
+
font: new this.Cesium.ConstantProperty(`${textSize}px Arial`),
|
|
1716
|
+
fillColor: new this.Cesium.ConstantProperty(labelColor),
|
|
1717
|
+
verticalOrigin: new this.Cesium.ConstantProperty(this.Cesium.VerticalOrigin.BOTTOM),
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
break;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
/**
|
|
1729
|
+
* Convert CSS color to Cesium Color
|
|
1730
|
+
*/
|
|
1731
|
+
parseCesiumColor(color, defaultColor) {
|
|
1732
|
+
if (!color)
|
|
1733
|
+
return defaultColor;
|
|
1734
|
+
// Handle hex colors
|
|
1735
|
+
if (color.startsWith('#')) {
|
|
1736
|
+
return this.Cesium.Color.fromCssColorString(color);
|
|
1737
|
+
}
|
|
1738
|
+
// Handle rgba/rgb colors
|
|
1739
|
+
if (color.includes('rgb')) {
|
|
1740
|
+
return this.Cesium.Color.fromCssColorString(color);
|
|
1741
|
+
}
|
|
1742
|
+
// Try to parse as CSS color string
|
|
1743
|
+
try {
|
|
1744
|
+
return this.Cesium.Color.fromCssColorString(color);
|
|
1745
|
+
}
|
|
1746
|
+
catch {
|
|
1747
|
+
return defaultColor;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
/**
|
|
1751
|
+
* Apply opacity to Cesium color
|
|
1752
|
+
*/
|
|
1753
|
+
applyCesiumOpacity(color, opacity) {
|
|
1754
|
+
if (!color)
|
|
1755
|
+
return color;
|
|
1756
|
+
return color.withAlpha(opacity);
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Create Cesium styling options from StyleConfig
|
|
1760
|
+
*/
|
|
1761
|
+
createCesiumStyle(style = {}) {
|
|
1762
|
+
// Default colors
|
|
1763
|
+
const defaultFillColor = this.Cesium.Color.BLUE.withAlpha(0.3);
|
|
1764
|
+
const defaultStrokeColor = this.Cesium.Color.BLUE;
|
|
1765
|
+
const defaultPointColor = this.Cesium.Color.BLUE;
|
|
1766
|
+
// Parse colors
|
|
1767
|
+
const fillColor = this.parseCesiumColor(style.fillColor, defaultFillColor);
|
|
1768
|
+
const strokeColor = this.parseCesiumColor(style.strokeColor, defaultStrokeColor);
|
|
1769
|
+
const pointColor = this.parseCesiumColor(style.pointColor, defaultPointColor);
|
|
1770
|
+
// Apply opacity
|
|
1771
|
+
const finalFillColor = style.fillOpacity !== undefined
|
|
1772
|
+
? this.applyCesiumOpacity(fillColor, style.fillOpacity)
|
|
1773
|
+
: fillColor;
|
|
1774
|
+
const finalStrokeColor = style.strokeOpacity !== undefined
|
|
1775
|
+
? this.applyCesiumOpacity(strokeColor, style.strokeOpacity)
|
|
1776
|
+
: strokeColor;
|
|
1777
|
+
const finalPointColor = style.pointOpacity !== undefined
|
|
1778
|
+
? this.applyCesiumOpacity(pointColor, style.pointOpacity)
|
|
1779
|
+
: pointColor;
|
|
1780
|
+
return {
|
|
1781
|
+
// Polygon styling
|
|
1782
|
+
fill: true,
|
|
1783
|
+
fillColor: finalFillColor,
|
|
1784
|
+
outline: true,
|
|
1785
|
+
outlineColor: finalStrokeColor,
|
|
1786
|
+
outlineWidth: style.strokeWidth ?? 2,
|
|
1787
|
+
extrudedHeight: style.extrudeHeight,
|
|
1788
|
+
heightReference: style.zOffset
|
|
1789
|
+
? this.Cesium.HeightReference.RELATIVE_TO_GROUND
|
|
1790
|
+
: this.Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
1791
|
+
// Point styling
|
|
1792
|
+
pixelSize: style.pointRadius ?? 8,
|
|
1793
|
+
color: finalPointColor,
|
|
1794
|
+
scaleByDistance: style.pointRadius
|
|
1795
|
+
? new this.Cesium.NearFarScalar(1.5e2, 2.0, 1.5e7, 0.5)
|
|
1796
|
+
: undefined,
|
|
1797
|
+
// Line styling
|
|
1798
|
+
width: style.strokeWidth ?? 2,
|
|
1799
|
+
clampToGround: !style.zOffset,
|
|
1800
|
+
// Text/Label styling
|
|
1801
|
+
labelText: style.textProperty,
|
|
1802
|
+
labelFont: style.textSize
|
|
1803
|
+
? `${style.textSize}pt monospace`
|
|
1804
|
+
: '12pt monospace',
|
|
1805
|
+
labelFillColor: style.textColor
|
|
1806
|
+
? this.parseCesiumColor(style.textColor, this.Cesium.Color.WHITE)
|
|
1807
|
+
: this.Cesium.Color.WHITE,
|
|
1808
|
+
labelOutlineColor: style.textHaloColor
|
|
1809
|
+
? this.parseCesiumColor(style.textHaloColor, this.Cesium.Color.BLACK)
|
|
1810
|
+
: this.Cesium.Color.BLACK,
|
|
1811
|
+
labelOutlineWidth: style.textHaloWidth ?? 1,
|
|
1812
|
+
labelPixelOffset: style.textOffset
|
|
1813
|
+
? new this.Cesium.Cartesian2(style.textOffset[0], style.textOffset[1])
|
|
1814
|
+
: this.Cesium.Cartesian2.ZERO,
|
|
1815
|
+
// 3D specific
|
|
1816
|
+
height: style.zOffset ?? 0,
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
/**
|
|
1820
|
+
* Apply enhanced styling to a GeoJsonDataSource
|
|
1821
|
+
*/
|
|
1822
|
+
applyEnhancedStyling(dataSource, style = {}) {
|
|
1823
|
+
const cesiumStyle = this.createCesiumStyle(style);
|
|
1824
|
+
const entities = dataSource.entities.values;
|
|
1825
|
+
for (let i = 0; i < entities.length; i++) {
|
|
1826
|
+
const entity = entities[i];
|
|
1827
|
+
let finalStyle = cesiumStyle;
|
|
1828
|
+
if (style.styleFunction && entity.properties) {
|
|
1829
|
+
const feature = {
|
|
1830
|
+
properties: entity.properties._propertyNames.reduce((props, name) => {
|
|
1831
|
+
props[name] = entity.properties[name]?._value;
|
|
1832
|
+
return props;
|
|
1833
|
+
}, {}),
|
|
1834
|
+
geometry: entity,
|
|
1835
|
+
};
|
|
1836
|
+
const conditionalStyle = style.styleFunction(feature);
|
|
1837
|
+
if (conditionalStyle) {
|
|
1838
|
+
finalStyle = {
|
|
1839
|
+
...cesiumStyle,
|
|
1840
|
+
...this.createCesiumStyle(conditionalStyle),
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
if (entity.polygon) {
|
|
1845
|
+
entity.polygon.fill = new this.Cesium.ConstantProperty(finalStyle.fill);
|
|
1846
|
+
entity.polygon.material = new this.Cesium.ColorMaterialProperty(finalStyle.fillColor);
|
|
1847
|
+
entity.polygon.outline = new this.Cesium.ConstantProperty(finalStyle.outline);
|
|
1848
|
+
entity.polygon.outlineColor = new this.Cesium.ConstantProperty(finalStyle.outlineColor);
|
|
1849
|
+
entity.polygon.outlineWidth = new this.Cesium.ConstantProperty(finalStyle.outlineWidth);
|
|
1850
|
+
entity.polygon.height =
|
|
1851
|
+
finalStyle.height !== undefined
|
|
1852
|
+
? new this.Cesium.ConstantProperty(finalStyle.height)
|
|
1853
|
+
: undefined;
|
|
1854
|
+
entity.polygon.extrudedHeight =
|
|
1855
|
+
finalStyle.extrudedHeight !== undefined
|
|
1856
|
+
? new this.Cesium.ConstantProperty(finalStyle.extrudedHeight)
|
|
1857
|
+
: undefined;
|
|
1858
|
+
entity.polygon.heightReference =
|
|
1859
|
+
finalStyle.heightReference !== undefined
|
|
1860
|
+
? new this.Cesium.ConstantProperty(finalStyle.heightReference)
|
|
1861
|
+
: undefined;
|
|
1862
|
+
}
|
|
1863
|
+
if (entity.polyline) {
|
|
1864
|
+
entity.polyline.material = new this.Cesium.ColorMaterialProperty(finalStyle.outlineColor);
|
|
1865
|
+
entity.polyline.width = new this.Cesium.ConstantProperty(finalStyle.width);
|
|
1866
|
+
entity.polyline.clampToGround = new this.Cesium.ConstantProperty(finalStyle.clampToGround);
|
|
1867
|
+
}
|
|
1868
|
+
if (entity.point) {
|
|
1869
|
+
entity.point.pixelSize = new this.Cesium.ConstantProperty(finalStyle.pixelSize);
|
|
1870
|
+
entity.point.color = new this.Cesium.ConstantProperty(finalStyle.color);
|
|
1871
|
+
const scaleByDistance = finalStyle.scaleByDistance;
|
|
1872
|
+
entity.point.scaleByDistance = scaleByDistance
|
|
1873
|
+
? new this.Cesium.ConstantProperty(scaleByDistance)
|
|
1874
|
+
: undefined;
|
|
1875
|
+
if (style.iconUrl) {
|
|
1876
|
+
entity.billboard = new this.Cesium.BillboardGraphics({
|
|
1877
|
+
image: new this.Cesium.ConstantProperty(style.iconUrl),
|
|
1878
|
+
width: new this.Cesium.ConstantProperty(style.iconSize ? style.iconSize[0] : 32),
|
|
1879
|
+
height: new this.Cesium.ConstantProperty(style.iconSize ? style.iconSize[1] : 32),
|
|
1880
|
+
verticalOrigin: new this.Cesium.ConstantProperty(this.Cesium.VerticalOrigin.BOTTOM),
|
|
1881
|
+
scaleByDistance: scaleByDistance
|
|
1882
|
+
? new this.Cesium.ConstantProperty(scaleByDistance)
|
|
1883
|
+
: undefined,
|
|
1884
|
+
});
|
|
1885
|
+
entity.point.show = new this.Cesium.ConstantProperty(false);
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
if (style.textProperty &&
|
|
1889
|
+
entity.properties &&
|
|
1890
|
+
entity.properties[style.textProperty]) {
|
|
1891
|
+
const textValue = entity.properties[style.textProperty]?.getValue?.(this.viewer.clock.currentTime) ??
|
|
1892
|
+
entity.properties[style.textProperty]?._value ??
|
|
1893
|
+
'';
|
|
1894
|
+
entity.label = new this.Cesium.LabelGraphics({
|
|
1895
|
+
text: new this.Cesium.ConstantProperty(String(textValue)),
|
|
1896
|
+
font: new this.Cesium.ConstantProperty(finalStyle.labelFont),
|
|
1897
|
+
fillColor: new this.Cesium.ConstantProperty(finalStyle.labelFillColor),
|
|
1898
|
+
outlineColor: new this.Cesium.ConstantProperty(finalStyle.labelOutlineColor),
|
|
1899
|
+
outlineWidth: new this.Cesium.ConstantProperty(finalStyle.labelOutlineWidth),
|
|
1900
|
+
pixelOffset: new this.Cesium.ConstantProperty(finalStyle.labelPixelOffset),
|
|
1901
|
+
verticalOrigin: new this.Cesium.ConstantProperty(this.Cesium.VerticalOrigin.BOTTOM),
|
|
1902
|
+
});
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
async createWKTLayer(config, options) {
|
|
1907
|
+
const geoJsonData = await this.wktToGeoJSON(config);
|
|
1908
|
+
const dataSource = await this.Cesium.GeoJsonDataSource.load(geoJsonData, options);
|
|
1909
|
+
// Apply geostyler style if provided, otherwise use enhanced styling
|
|
1910
|
+
if (config.geostylerStyle) {
|
|
1911
|
+
this.applyGeostylerStyling(dataSource, config.geostylerStyle);
|
|
1912
|
+
}
|
|
1913
|
+
else if (config.style) {
|
|
1914
|
+
this.applyEnhancedStyling(dataSource, config.style);
|
|
1915
|
+
}
|
|
1916
|
+
return dataSource;
|
|
1917
|
+
}
|
|
1918
|
+
async wktToGeoJSON(config) {
|
|
1919
|
+
const wktText = await this.resolveWktText(config);
|
|
1920
|
+
const wellknownModule = await import('./index-BUHa4Jj0.js').then(function (n) { return n.i; });
|
|
1921
|
+
const parseFn = typeof wellknownModule.default === 'function'
|
|
1922
|
+
? wellknownModule.default
|
|
1923
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- wellknown has inconsistent module exports across bundlers
|
|
1924
|
+
: wellknownModule.parse;
|
|
1925
|
+
if (typeof parseFn !== 'function') {
|
|
1926
|
+
throw new Error('wellknown parser not available');
|
|
1927
|
+
}
|
|
1928
|
+
const geometry = parseFn(wktText);
|
|
1929
|
+
if (!geometry) {
|
|
1930
|
+
throw new Error('Failed to parse WKT');
|
|
1931
|
+
}
|
|
1932
|
+
return {
|
|
1933
|
+
type: 'FeatureCollection',
|
|
1934
|
+
features: [
|
|
1935
|
+
{
|
|
1936
|
+
type: 'Feature',
|
|
1937
|
+
properties: {},
|
|
1938
|
+
geometry,
|
|
1939
|
+
},
|
|
1940
|
+
],
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
async resolveWktText(config) {
|
|
1944
|
+
if (config.wkt)
|
|
1945
|
+
return config.wkt;
|
|
1946
|
+
if (config.url) {
|
|
1947
|
+
const response = await fetch(config.url);
|
|
1948
|
+
if (!response.ok)
|
|
1949
|
+
throw new Error(`Failed to fetch WKT: ${response.status}`);
|
|
1950
|
+
return await response.text();
|
|
1951
|
+
}
|
|
1952
|
+
throw new Error('Either wkt or url must be provided');
|
|
1953
|
+
}
|
|
1954
|
+
async createGeoJSONLayer(config, options) {
|
|
1955
|
+
let geojson_or_url = null;
|
|
1956
|
+
if (config.geojson) {
|
|
1957
|
+
geojson_or_url = JSON.parse(config.geojson);
|
|
1958
|
+
}
|
|
1959
|
+
else {
|
|
1960
|
+
geojson_or_url = config.url;
|
|
1961
|
+
}
|
|
1962
|
+
//https://cesium.com/learn/ion-sdk/ref-doc/GeoJsonDataSource.html
|
|
1963
|
+
const dataSource = await this.Cesium.GeoJsonDataSource.load(geojson_or_url, options);
|
|
1964
|
+
// Apply geostyler style if provided, otherwise use enhanced styling
|
|
1965
|
+
if (config.geostylerStyle) {
|
|
1966
|
+
this.applyGeostylerStyling(dataSource, config.geostylerStyle);
|
|
1967
|
+
}
|
|
1968
|
+
else if (config.style) {
|
|
1969
|
+
this.applyEnhancedStyling(dataSource, config.style);
|
|
1970
|
+
}
|
|
1971
|
+
return dataSource;
|
|
1972
|
+
}
|
|
1973
|
+
async createWFSLayer(config, options) {
|
|
1974
|
+
// Fetch GeoJSON from WFS server
|
|
1975
|
+
const geojson = await this.fetchWFSFromUrl(config);
|
|
1976
|
+
// Load GeoJSON into Cesium DataSource
|
|
1977
|
+
const dataSource = await this.Cesium.GeoJsonDataSource.load(geojson, options);
|
|
1978
|
+
// Apply geostyler style if provided, otherwise use enhanced styling
|
|
1979
|
+
if (config.geostylerStyle) {
|
|
1980
|
+
this.applyGeostylerStyling(dataSource, config.geostylerStyle);
|
|
1981
|
+
}
|
|
1982
|
+
else if (config.style) {
|
|
1983
|
+
this.applyEnhancedStyling(dataSource, config.style);
|
|
1984
|
+
}
|
|
1985
|
+
return dataSource;
|
|
1986
|
+
}
|
|
1987
|
+
async createOSMLayer(cfg) {
|
|
1988
|
+
return new this.Cesium.ImageryLayer(new this.Cesium.OpenStreetMapImageryProvider({
|
|
1989
|
+
url: cfg.url || 'https://a.tile.openstreetmap.org',
|
|
1990
|
+
}));
|
|
1991
|
+
}
|
|
1992
|
+
async createGoogleLayer(config) {
|
|
1993
|
+
if (!config.apiKey) {
|
|
1994
|
+
throw new Error("Google-Layer benötigt 'apiKey' (Google Maps Platform).");
|
|
1995
|
+
}
|
|
1996
|
+
// Load Google Maps JavaScript API
|
|
1997
|
+
await this.loadGoogleMapsApi(config.apiKey, {
|
|
1998
|
+
language: config.language,
|
|
1999
|
+
region: config.region,
|
|
2000
|
+
libraries: config.libraries,
|
|
2001
|
+
});
|
|
2002
|
+
const mapType = config.mapType || 'roadmap';
|
|
2003
|
+
const googleMapTypeId = this.getGoogleMapTypeId(mapType);
|
|
2004
|
+
// Use a simpler approach with UrlTemplateImageryProvider and custom URL generator
|
|
2005
|
+
const Cesium = this.Cesium;
|
|
2006
|
+
// Create a custom URL template that we'll handle in the urlSchemeZeroPadding function
|
|
2007
|
+
const customUrlTemplate = 'https://maps.googleapis.com/maps/api/staticmap?template';
|
|
2008
|
+
const googleImageryProvider = new Cesium.UrlTemplateImageryProvider({
|
|
2009
|
+
url: customUrlTemplate,
|
|
2010
|
+
maximumLevel: config.maxZoom || 19,
|
|
2011
|
+
minimumLevel: 0,
|
|
2012
|
+
tilingScheme: new Cesium.WebMercatorTilingScheme(),
|
|
2013
|
+
credit: 'Google Maps',
|
|
2014
|
+
// Override URL generation using urlSchemeZeroPadding as a custom URL builder
|
|
2015
|
+
urlSchemeZeroPadding: {
|
|
2016
|
+
'{x}': '',
|
|
2017
|
+
'{y}': '',
|
|
2018
|
+
'{z}': '',
|
|
2019
|
+
},
|
|
2020
|
+
});
|
|
2021
|
+
// Override the buildImageResource method to use Google Static Maps API
|
|
2022
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- monkey-patching internal Cesium method not exposed in typings
|
|
2023
|
+
googleImageryProvider.buildImageResource = function (x, y, level) {
|
|
2024
|
+
const tilingScheme = new Cesium.WebMercatorTilingScheme();
|
|
2025
|
+
const rectangle = tilingScheme.tileXYToRectangle(x, y, level);
|
|
2026
|
+
const west = Cesium.Math.toDegrees(rectangle.west);
|
|
2027
|
+
const south = Cesium.Math.toDegrees(rectangle.south);
|
|
2028
|
+
const east = Cesium.Math.toDegrees(rectangle.east);
|
|
2029
|
+
const north = Cesium.Math.toDegrees(rectangle.north);
|
|
2030
|
+
// Center point of the tile
|
|
2031
|
+
const centerLat = (south + north) / 2;
|
|
2032
|
+
const centerLng = (west + east) / 2;
|
|
2033
|
+
// Build Google Static Maps API URL
|
|
2034
|
+
const params = new URLSearchParams({
|
|
2035
|
+
center: `${centerLat},${centerLng}`,
|
|
2036
|
+
zoom: level.toString(),
|
|
2037
|
+
size: '256x256',
|
|
2038
|
+
scale: config.scale === 'scaleFactor1x' ? '1' : '2',
|
|
2039
|
+
maptype: googleMapTypeId,
|
|
2040
|
+
key: config.apiKey,
|
|
2041
|
+
format: 'png',
|
|
2042
|
+
});
|
|
2043
|
+
if (config.language) {
|
|
2044
|
+
params.set('language', config.language);
|
|
2045
|
+
}
|
|
2046
|
+
if (config.region) {
|
|
2047
|
+
params.set('region', config.region);
|
|
2048
|
+
}
|
|
2049
|
+
const url = `https://maps.googleapis.com/maps/api/staticmap?${params.toString()}`;
|
|
2050
|
+
return new Cesium.Resource({ url });
|
|
2051
|
+
};
|
|
2052
|
+
// Add Google logo for compliance
|
|
2053
|
+
this.ensureGoogleLogo();
|
|
2054
|
+
return new this.Cesium.ImageryLayer(googleImageryProvider, {
|
|
2055
|
+
alpha: config.opacity ?? 1,
|
|
2056
|
+
show: config.visible ?? true,
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2059
|
+
getGoogleMapTypeId(mapType) {
|
|
2060
|
+
switch (mapType) {
|
|
2061
|
+
case 'roadmap':
|
|
2062
|
+
return 'roadmap';
|
|
2063
|
+
case 'satellite':
|
|
2064
|
+
return 'satellite';
|
|
2065
|
+
case 'terrain':
|
|
2066
|
+
return 'terrain';
|
|
2067
|
+
case 'hybrid':
|
|
2068
|
+
return 'hybrid';
|
|
2069
|
+
default:
|
|
2070
|
+
return 'roadmap';
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* Load Google Maps JavaScript API
|
|
2075
|
+
*/
|
|
2076
|
+
async loadGoogleMapsApi(apiKey, opts) {
|
|
2077
|
+
const w = window;
|
|
2078
|
+
const mockLoader = w.__mockGoogleMapsApi;
|
|
2079
|
+
if (typeof mockLoader === 'function') {
|
|
2080
|
+
await mockLoader(apiKey, opts);
|
|
2081
|
+
return;
|
|
2082
|
+
}
|
|
2083
|
+
if (w.google?.maps)
|
|
2084
|
+
return;
|
|
2085
|
+
await new Promise((resolve, reject) => {
|
|
2086
|
+
const cbName = '___cesiumGoogleInit___' + Math.random().toString(36).slice(2);
|
|
2087
|
+
w[cbName] = () => resolve();
|
|
2088
|
+
const script = document.createElement('script');
|
|
2089
|
+
const params = new URLSearchParams({
|
|
2090
|
+
key: apiKey,
|
|
2091
|
+
callback: cbName,
|
|
2092
|
+
v: 'weekly',
|
|
2093
|
+
});
|
|
2094
|
+
if (opts?.language)
|
|
2095
|
+
params.set('language', opts.language);
|
|
2096
|
+
if (opts?.region)
|
|
2097
|
+
params.set('region', opts.region);
|
|
2098
|
+
if (opts?.libraries?.length)
|
|
2099
|
+
params.set('libraries', opts.libraries.join(','));
|
|
2100
|
+
script.src = `https://maps.googleapis.com/maps/api/js?${params.toString()}`;
|
|
2101
|
+
script.async = true;
|
|
2102
|
+
script.onerror = () => reject(new Error('Google Maps JS API failed to load'));
|
|
2103
|
+
document.head.appendChild(script);
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2106
|
+
/**
|
|
2107
|
+
* Add Google logo for compliance
|
|
2108
|
+
*/
|
|
2109
|
+
ensureGoogleLogo() {
|
|
2110
|
+
if (!this.viewer?.container ||
|
|
2111
|
+
this.viewer.container._googleLogoAdded)
|
|
2112
|
+
return;
|
|
2113
|
+
const logo = document.createElement('img');
|
|
2114
|
+
logo.src =
|
|
2115
|
+
'https://developers.google.com/static/maps/documentation/images/google_on_white.png';
|
|
2116
|
+
logo.alt = 'Google';
|
|
2117
|
+
logo.style.position = 'absolute';
|
|
2118
|
+
logo.style.bottom = '6px';
|
|
2119
|
+
logo.style.left = '6px';
|
|
2120
|
+
logo.style.height = '18px';
|
|
2121
|
+
logo.style.pointerEvents = 'none';
|
|
2122
|
+
logo.style.zIndex = '1000';
|
|
2123
|
+
this.viewer.container.appendChild(logo);
|
|
2124
|
+
this.viewer.container._googleLogoAdded = true;
|
|
2125
|
+
}
|
|
2126
|
+
async createXYZLayer(config) {
|
|
2127
|
+
if (!config.url) {
|
|
2128
|
+
throw new Error('XYZ layer requires a url');
|
|
2129
|
+
}
|
|
2130
|
+
const credit = Array.isArray(config.attributions)
|
|
2131
|
+
? config.attributions.join(', ')
|
|
2132
|
+
: config.attributions;
|
|
2133
|
+
const providerOptions = {
|
|
2134
|
+
url: config.url,
|
|
2135
|
+
credit,
|
|
2136
|
+
maximumLevel: config.maxZoom,
|
|
2137
|
+
...(config.options || {}),
|
|
2138
|
+
};
|
|
2139
|
+
const provider = new this.Cesium.UrlTemplateImageryProvider(providerOptions);
|
|
2140
|
+
const layerOptions = {
|
|
2141
|
+
alpha: config.opacity ?? 1,
|
|
2142
|
+
show: config.visible ?? true,
|
|
2143
|
+
};
|
|
2144
|
+
return new this.Cesium.ImageryLayer(provider, layerOptions);
|
|
2145
|
+
}
|
|
2146
|
+
async createTerrainLayer(config) {
|
|
2147
|
+
let provider;
|
|
2148
|
+
if (config.elevationData) {
|
|
2149
|
+
provider = await this.Cesium.CesiumTerrainProvider.fromUrl(config.elevationData);
|
|
2150
|
+
}
|
|
2151
|
+
else {
|
|
2152
|
+
provider = await this.Cesium.createWorldTerrainAsync();
|
|
2153
|
+
}
|
|
2154
|
+
const layer = new CesiumTerrainLayer(this.Cesium, this.viewer, provider, config);
|
|
2155
|
+
if (config.visible !== undefined) {
|
|
2156
|
+
layer.setVisible(config.visible);
|
|
2157
|
+
}
|
|
2158
|
+
if (config.opacity !== undefined) {
|
|
2159
|
+
layer.setOpacity(config.opacity);
|
|
2160
|
+
}
|
|
2161
|
+
return layer;
|
|
2162
|
+
}
|
|
2163
|
+
/**
|
|
2164
|
+
* Create GeoTIFF Terrain Layer
|
|
2165
|
+
* Loads GeoTIFF elevation data and provides it as terrain
|
|
2166
|
+
*/
|
|
2167
|
+
async createGeoTIFFTerrainLayer(config) {
|
|
2168
|
+
// If no URL is set, return a fallback layer with EllipsoidTerrainProvider
|
|
2169
|
+
if (!config.url) {
|
|
2170
|
+
log(`${TERRAIN_GEOTIFF_LOG_PREFIX}layer created without URL, waiting for URL to load`);
|
|
2171
|
+
const fallbackProvider = new this.Cesium.EllipsoidTerrainProvider();
|
|
2172
|
+
const layer = new CesiumTerrainLayer(this.Cesium, this.viewer, fallbackProvider, config);
|
|
2173
|
+
// Set to invisible since there's no terrain data
|
|
2174
|
+
layer.setVisible(false);
|
|
2175
|
+
return layer;
|
|
2176
|
+
}
|
|
2177
|
+
try {
|
|
2178
|
+
log(`${TERRAIN_GEOTIFF_LOG_PREFIX}create layer: url=${config.url}`);
|
|
2179
|
+
// Create the custom GeoTIFF terrain provider
|
|
2180
|
+
const provider = await createCesiumGeoTIFFTerrainProvider({
|
|
2181
|
+
url: config.url,
|
|
2182
|
+
projection: config.projection,
|
|
2183
|
+
forceProjection: config.forceProjection,
|
|
2184
|
+
nodata: config.nodata,
|
|
2185
|
+
Cesium: this.Cesium,
|
|
2186
|
+
});
|
|
2187
|
+
// Wrap it in a CesiumTerrainLayer
|
|
2188
|
+
// Cast config to terrain type since CesiumTerrainLayer expects it
|
|
2189
|
+
const layer = new CesiumTerrainLayer(this.Cesium, this.viewer, provider, config);
|
|
2190
|
+
if (config.visible !== undefined) {
|
|
2191
|
+
layer.setVisible(config.visible);
|
|
2192
|
+
}
|
|
2193
|
+
if (config.opacity !== undefined) {
|
|
2194
|
+
layer.setOpacity(config.opacity);
|
|
2195
|
+
}
|
|
2196
|
+
log(`${TERRAIN_GEOTIFF_LOG_PREFIX}layer created successfully`);
|
|
2197
|
+
return layer;
|
|
2198
|
+
}
|
|
2199
|
+
catch (err) {
|
|
2200
|
+
error(`${TERRAIN_GEOTIFF_LOG_PREFIX}failed to create terrain layer:`, err);
|
|
2201
|
+
// Return a fallback with EllipsoidTerrainProvider
|
|
2202
|
+
const fallbackProvider = new this.Cesium.EllipsoidTerrainProvider();
|
|
2203
|
+
return new CesiumTerrainLayer(this.Cesium, this.viewer, fallbackProvider, config);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
async addWMSLayer(config) {
|
|
2207
|
+
return new this.Cesium.ImageryLayer(new this.Cesium.WebMapServiceImageryProvider({
|
|
2208
|
+
url: config.url,
|
|
2209
|
+
layers: config.layers,
|
|
2210
|
+
parameters: config.extraParams,
|
|
2211
|
+
}));
|
|
2212
|
+
}
|
|
2213
|
+
/**
|
|
2214
|
+
* Create WCS (Web Coverage Service) ImageryLayer
|
|
2215
|
+
* Supports WCS 2.0.1 (subset) and 1.x.x (BBOX) versions
|
|
2216
|
+
*/
|
|
2217
|
+
async createWCSLayer(config) {
|
|
2218
|
+
if (!config.url || !config.coverageName) {
|
|
2219
|
+
throw new Error('WCS layer requires url and coverageName');
|
|
2220
|
+
}
|
|
2221
|
+
const version = config.version ?? '2.0.1';
|
|
2222
|
+
const format = config.format ?? 'image/tiff';
|
|
2223
|
+
const projection = config.projection ?? 'EPSG:4326';
|
|
2224
|
+
const tileSize = config.tileSize ?? 256;
|
|
2225
|
+
const Cesium = this.Cesium;
|
|
2226
|
+
// Create a custom URL template - will be overridden by buildImageResource
|
|
2227
|
+
const customUrlTemplate = `${config.url}?wcs_placeholder`;
|
|
2228
|
+
const wcsImageryProvider = new Cesium.UrlTemplateImageryProvider({
|
|
2229
|
+
url: customUrlTemplate,
|
|
2230
|
+
maximumLevel: config.maxZoom ?? 18,
|
|
2231
|
+
minimumLevel: config.minZoom ?? 0,
|
|
2232
|
+
tileWidth: tileSize,
|
|
2233
|
+
tileHeight: tileSize,
|
|
2234
|
+
tilingScheme: new Cesium.GeographicTilingScheme(),
|
|
2235
|
+
credit: 'WCS',
|
|
2236
|
+
});
|
|
2237
|
+
// Override the buildImageResource method to generate WCS GetCoverage URLs
|
|
2238
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- monkey-patching internal Cesium method not exposed in typings
|
|
2239
|
+
wcsImageryProvider.buildImageResource = function (x, y, level) {
|
|
2240
|
+
const tilingScheme = new Cesium.GeographicTilingScheme();
|
|
2241
|
+
const rectangle = tilingScheme.tileXYToRectangle(x, y, level);
|
|
2242
|
+
// Convert to degrees
|
|
2243
|
+
const west = Cesium.Math.toDegrees(rectangle.west);
|
|
2244
|
+
const south = Cesium.Math.toDegrees(rectangle.south);
|
|
2245
|
+
const east = Cesium.Math.toDegrees(rectangle.east);
|
|
2246
|
+
const north = Cesium.Math.toDegrees(rectangle.north);
|
|
2247
|
+
const baseParams = {
|
|
2248
|
+
SERVICE: 'WCS',
|
|
2249
|
+
REQUEST: 'GetCoverage',
|
|
2250
|
+
VERSION: version,
|
|
2251
|
+
FORMAT: format,
|
|
2252
|
+
};
|
|
2253
|
+
let url;
|
|
2254
|
+
// WCS 2.0.1 uses subset parameters
|
|
2255
|
+
if (version.startsWith('2.0')) {
|
|
2256
|
+
const params = {
|
|
2257
|
+
...baseParams,
|
|
2258
|
+
coverageId: config.coverageName,
|
|
2259
|
+
...(config.params || {}),
|
|
2260
|
+
};
|
|
2261
|
+
// Add GeoTIFF compression if format is tiff
|
|
2262
|
+
if (format.includes('tiff') || format.includes('geotiff')) {
|
|
2263
|
+
params['geotiff:compression'] = 'LZW';
|
|
2264
|
+
}
|
|
2265
|
+
// Build query string
|
|
2266
|
+
const query = new URLSearchParams();
|
|
2267
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2268
|
+
if (value !== undefined && value !== null) {
|
|
2269
|
+
query.set(key, String(value));
|
|
2270
|
+
}
|
|
2271
|
+
});
|
|
2272
|
+
const queryString = query.toString();
|
|
2273
|
+
const subsetX = `subset=X(${west},${east})`;
|
|
2274
|
+
const subsetY = `subset=Y(${south},${north})`;
|
|
2275
|
+
url = `${config.url}${config.url.includes('?') ? '&' : '?'}${queryString}&${subsetX}&${subsetY}`;
|
|
2276
|
+
}
|
|
2277
|
+
// WCS 1.x.x uses BBOX parameter
|
|
2278
|
+
else {
|
|
2279
|
+
const params = {
|
|
2280
|
+
...baseParams,
|
|
2281
|
+
COVERAGE: config.coverageName,
|
|
2282
|
+
BBOX: `${west},${south},${east},${north}`,
|
|
2283
|
+
CRS: projection,
|
|
2284
|
+
WIDTH: String(tileSize),
|
|
2285
|
+
HEIGHT: String(tileSize),
|
|
2286
|
+
...(config.params || {}),
|
|
2287
|
+
};
|
|
2288
|
+
const query = new URLSearchParams();
|
|
2289
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2290
|
+
if (value !== undefined && value !== null) {
|
|
2291
|
+
query.set(key, String(value));
|
|
2292
|
+
}
|
|
2293
|
+
});
|
|
2294
|
+
url = `${config.url}${config.url.includes('?') ? '&' : '?'}${query.toString()}`;
|
|
2295
|
+
}
|
|
2296
|
+
return new Cesium.Resource({ url });
|
|
2297
|
+
};
|
|
2298
|
+
return new this.Cesium.ImageryLayer(wcsImageryProvider, {
|
|
2299
|
+
alpha: config.opacity ?? 1,
|
|
2300
|
+
show: config.visible ?? true,
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
async addArcGISLayer(config) {
|
|
2304
|
+
//"https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
|
|
2305
|
+
const provider = await this.Cesium.ArcGisMapServerImageryProvider.fromUrl(config.url);
|
|
2306
|
+
this.viewer.imageryLayers.addImageryProvider(provider);
|
|
2307
|
+
}
|
|
2308
|
+
async createGeoTIFFLayer(config) {
|
|
2309
|
+
if (!config.url) {
|
|
2310
|
+
throw new Error('GeoTIFF layer requires a URL');
|
|
2311
|
+
}
|
|
2312
|
+
// The GeoTIFFImageryProvider always uses WebMercatorTilingScheme,
|
|
2313
|
+
// so the tile processor must reproject into EPSG:3857 to match
|
|
2314
|
+
// the tile coordinate math (x,y,z → bounds).
|
|
2315
|
+
const viewProjection = 'EPSG:3857';
|
|
2316
|
+
try {
|
|
2317
|
+
const geotiffExtra = config;
|
|
2318
|
+
const source = await getGeoTIFFSource(config.url, geotiffExtra.projection, geotiffExtra.forceProjection, config.nodata);
|
|
2319
|
+
const tileProcessorConfig = await getTileProcessorConfig(source, viewProjection);
|
|
2320
|
+
const tileProcessor = new GeoTIFFTileProcessor(tileProcessorConfig);
|
|
2321
|
+
tileProcessor.createGlobalTriangulation();
|
|
2322
|
+
let colorStops;
|
|
2323
|
+
if (config.colorMap) {
|
|
2324
|
+
const { stops } = getColorStops(config.colorMap, config.valueRange);
|
|
2325
|
+
colorStops = stops;
|
|
2326
|
+
}
|
|
2327
|
+
const geotiffRenderExtra = config;
|
|
2328
|
+
const tileSize = geotiffRenderExtra.tileSize ?? 256;
|
|
2329
|
+
const resolution = geotiffRenderExtra.resolution ?? 1.0;
|
|
2330
|
+
const resampleMethod = geotiffRenderExtra.resampleMethod ?? 'bilinear';
|
|
2331
|
+
const imageryProvider = new GeoTIFFImageryProvider({
|
|
2332
|
+
Cesium: this.Cesium,
|
|
2333
|
+
rectangleDegrees: source.wgs84Bounds,
|
|
2334
|
+
tileProcessor,
|
|
2335
|
+
tileSize,
|
|
2336
|
+
resolution,
|
|
2337
|
+
resampleMethod,
|
|
2338
|
+
colorStops,
|
|
2339
|
+
});
|
|
2340
|
+
const layer = new this.Cesium.ImageryLayer(imageryProvider, {
|
|
2341
|
+
alpha: config.opacity ?? 1.0,
|
|
2342
|
+
show: config.visible ?? true,
|
|
2343
|
+
});
|
|
2344
|
+
layer.__vmapGeoTIFFMeta = {
|
|
2345
|
+
url: config.url,
|
|
2346
|
+
width: source.width,
|
|
2347
|
+
height: source.height,
|
|
2348
|
+
samplesPerPixel: source.samplesPerPixel,
|
|
2349
|
+
noData: source.noDataValue,
|
|
2350
|
+
};
|
|
2351
|
+
return layer;
|
|
2352
|
+
}
|
|
2353
|
+
catch (err) {
|
|
2354
|
+
error('v-map - provider - cesium - Failed to create GeoTIFF layer', err);
|
|
2355
|
+
// Return a placeholder layer in case of error
|
|
2356
|
+
const provider = new this.Cesium.SingleTileImageryProvider({
|
|
2357
|
+
url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
|
|
2358
|
+
rectangle: this.Cesium.Rectangle.fromDegrees(-180, -90, 180, 90),
|
|
2359
|
+
});
|
|
2360
|
+
return new this.Cesium.ImageryLayer(provider, {
|
|
2361
|
+
alpha: 0,
|
|
2362
|
+
show: false,
|
|
2363
|
+
});
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
async createTile3DLayer(config) {
|
|
2367
|
+
if (!config.url) {
|
|
2368
|
+
throw new Error('Tile3D layer requires a URL');
|
|
2369
|
+
}
|
|
2370
|
+
const tileset = await this.Cesium.Cesium3DTileset.fromUrl(config.url, config.tilesetOptions ?? {});
|
|
2371
|
+
if (config.cesiumStyle) {
|
|
2372
|
+
tileset.style = new this.Cesium.Cesium3DTileStyle(config.cesiumStyle);
|
|
2373
|
+
}
|
|
2374
|
+
return tileset;
|
|
2375
|
+
}
|
|
2376
|
+
async updateLayer(layerId, update) {
|
|
2377
|
+
return await this.layerManagerMutex.runExclusive(async () => {
|
|
2378
|
+
const hadErrorListener = this.layerErrorCallbacks.has(layerId);
|
|
2379
|
+
if (hadErrorListener)
|
|
2380
|
+
this.offLayerError(layerId);
|
|
2381
|
+
const oldLayer = this.layerManager.getLayer(layerId);
|
|
2382
|
+
switch (update.type) {
|
|
2383
|
+
case 'geojson':
|
|
2384
|
+
{
|
|
2385
|
+
const data = update.data;
|
|
2386
|
+
const options = oldLayer.getOptions();
|
|
2387
|
+
const dataSource = await this.createGeoJSONLayer({
|
|
2388
|
+
geojson: data.geojson,
|
|
2389
|
+
url: data.url,
|
|
2390
|
+
style: data.style,
|
|
2391
|
+
geostylerStyle: data.geostylerStyle,
|
|
2392
|
+
}, options);
|
|
2393
|
+
const layer = this.layerManager.replaceLayer(layerId, oldLayer, dataSource);
|
|
2394
|
+
layer.setOptions(options);
|
|
2395
|
+
}
|
|
2396
|
+
break;
|
|
2397
|
+
case 'wfs':
|
|
2398
|
+
{
|
|
2399
|
+
const data = update.data;
|
|
2400
|
+
const options = oldLayer.getOptions();
|
|
2401
|
+
const dataSource = await this.createWFSLayer(data, options);
|
|
2402
|
+
const layer = this.layerManager.replaceLayer(layerId, oldLayer, dataSource);
|
|
2403
|
+
layer.setOptions(options);
|
|
2404
|
+
}
|
|
2405
|
+
break;
|
|
2406
|
+
case 'osm':
|
|
2407
|
+
{
|
|
2408
|
+
const osmOptions = oldLayer.getOptions();
|
|
2409
|
+
const osmLayer = new this.Cesium.ImageryLayer(new this.Cesium.OpenStreetMapImageryProvider({
|
|
2410
|
+
url: update.data.url || 'https://a.tile.openstreetmap.org',
|
|
2411
|
+
}));
|
|
2412
|
+
const updatedOsmlayer = this.layerManager.replaceLayer(layerId, oldLayer, osmLayer);
|
|
2413
|
+
updatedOsmlayer.setOptions(osmOptions);
|
|
2414
|
+
}
|
|
2415
|
+
break;
|
|
2416
|
+
case 'google':
|
|
2417
|
+
{
|
|
2418
|
+
const googleOptions = oldLayer.getOptions();
|
|
2419
|
+
const googleLayer = await this.createGoogleLayer(update.data);
|
|
2420
|
+
const updatedGoogleLayer = this.layerManager.replaceLayer(layerId, oldLayer, googleLayer);
|
|
2421
|
+
updatedGoogleLayer.setOptions(googleOptions);
|
|
2422
|
+
}
|
|
2423
|
+
break;
|
|
2424
|
+
case 'xyz':
|
|
2425
|
+
{
|
|
2426
|
+
const xyzOptions = oldLayer.getOptions();
|
|
2427
|
+
const xyzLayer = await this.createXYZLayer(update.data);
|
|
2428
|
+
const updatedXyzLayer = this.layerManager.replaceLayer(layerId, oldLayer, xyzLayer);
|
|
2429
|
+
updatedXyzLayer.setOptions(xyzOptions);
|
|
2430
|
+
}
|
|
2431
|
+
break;
|
|
2432
|
+
case 'wcs':
|
|
2433
|
+
{
|
|
2434
|
+
const wcsOptions = oldLayer.getOptions();
|
|
2435
|
+
const wcsLayer = await this.createWCSLayer(update.data);
|
|
2436
|
+
const updatedWcsLayer = this.layerManager.replaceLayer(layerId, oldLayer, wcsLayer);
|
|
2437
|
+
updatedWcsLayer.setOptions(wcsOptions);
|
|
2438
|
+
}
|
|
2439
|
+
break;
|
|
2440
|
+
case 'wkt':
|
|
2441
|
+
{
|
|
2442
|
+
const data = update.data;
|
|
2443
|
+
const options = oldLayer.getOptions();
|
|
2444
|
+
const dataSource = await this.createWKTLayer({
|
|
2445
|
+
wkt: data.wkt,
|
|
2446
|
+
url: data.url,
|
|
2447
|
+
style: data.style,
|
|
2448
|
+
geostylerStyle: data.geostylerStyle,
|
|
2449
|
+
}, options);
|
|
2450
|
+
const layer = this.layerManager.replaceLayer(layerId, oldLayer, dataSource);
|
|
2451
|
+
layer.setOptions(options);
|
|
2452
|
+
}
|
|
2453
|
+
break;
|
|
2454
|
+
case 'geotiff':
|
|
2455
|
+
{
|
|
2456
|
+
const data = update.data;
|
|
2457
|
+
const iLayer = await this.createGeoTIFFLayer({
|
|
2458
|
+
url: data.url,
|
|
2459
|
+
});
|
|
2460
|
+
this.layerManager.replaceLayer(layerId, oldLayer, iLayer);
|
|
2461
|
+
}
|
|
2462
|
+
break;
|
|
2463
|
+
case 'tile3d':
|
|
2464
|
+
{
|
|
2465
|
+
const data = update.data ?? {};
|
|
2466
|
+
if (!data.url) {
|
|
2467
|
+
throw new Error('tile3d update requires a url');
|
|
2468
|
+
}
|
|
2469
|
+
const layer = await this.createTile3DLayer({
|
|
2470
|
+
type: 'tile3d',
|
|
2471
|
+
url: data.url,
|
|
2472
|
+
tilesetOptions: data.tilesetOptions,
|
|
2473
|
+
cesiumStyle: data.cesiumStyle,
|
|
2474
|
+
});
|
|
2475
|
+
const updatedLayer = this.layerManager.replaceLayer(layerId, oldLayer, layer);
|
|
2476
|
+
updatedLayer.setOptions(data.tilesetOptions ?? {});
|
|
2477
|
+
if (data.cesiumStyle && 'setStyle' in updatedLayer) {
|
|
2478
|
+
updatedLayer.setStyle(data.cesiumStyle);
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
break;
|
|
2482
|
+
case 'tile3d-style':
|
|
2483
|
+
{
|
|
2484
|
+
const data = update.data ?? {};
|
|
2485
|
+
if ('setStyle' in oldLayer) {
|
|
2486
|
+
const stylePayload = data.style ?? {};
|
|
2487
|
+
oldLayer.setStyle(stylePayload);
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
break;
|
|
2491
|
+
case 'terrain':
|
|
2492
|
+
{
|
|
2493
|
+
const previousOptions = oldLayer.getOptions();
|
|
2494
|
+
const visible = oldLayer.getVisible();
|
|
2495
|
+
const opacity = oldLayer.getOpacity();
|
|
2496
|
+
oldLayer.remove();
|
|
2497
|
+
const terrainLayer = await this.createTerrainLayer({
|
|
2498
|
+
type: 'terrain',
|
|
2499
|
+
...previousOptions,
|
|
2500
|
+
...(update.data ?? {}),
|
|
2501
|
+
});
|
|
2502
|
+
const wrapped = this.layerManager.addCustomLayer(layerId, terrainLayer);
|
|
2503
|
+
wrapped.setVisible(visible);
|
|
2504
|
+
wrapped.setOpacity(opacity);
|
|
2505
|
+
}
|
|
2506
|
+
break;
|
|
2507
|
+
case 'terrain-geotiff':
|
|
2508
|
+
{
|
|
2509
|
+
//const previousOptions = oldLayer.getOptions();
|
|
2510
|
+
//const visible = oldLayer.getVisible();
|
|
2511
|
+
//const opacity = oldLayer.getOpacity();
|
|
2512
|
+
oldLayer.remove();
|
|
2513
|
+
const terrainLayer = await this.createGeoTIFFTerrainLayer({
|
|
2514
|
+
type: 'terrain-geotiff',
|
|
2515
|
+
...(update.data ?? {}),
|
|
2516
|
+
});
|
|
2517
|
+
this.layerManager.addCustomLayer(layerId, terrainLayer);
|
|
2518
|
+
//wrapped.setVisible(visible);
|
|
2519
|
+
//wrapped.setOpacity(opacity);
|
|
2520
|
+
}
|
|
2521
|
+
break;
|
|
2522
|
+
}
|
|
2523
|
+
// Re-attach error listeners after layer replacement
|
|
2524
|
+
if (hadErrorListener)
|
|
2525
|
+
this.attachCesiumErrorListeners(layerId);
|
|
2526
|
+
});
|
|
2527
|
+
}
|
|
2528
|
+
async setView(center, zoom) {
|
|
2529
|
+
if (!this.viewer)
|
|
2530
|
+
return;
|
|
2531
|
+
const [lon, lat] = center;
|
|
2532
|
+
this.viewer.camera.flyTo({
|
|
2533
|
+
destination: this.Cesium.Cartesian3.fromDegrees(lon, lat, 1000000 / zoom),
|
|
2534
|
+
duration: 2.0, // Sekunden, anpassbar
|
|
2535
|
+
orientation: {
|
|
2536
|
+
heading: this.Cesium.Math.toRadians(0.0), // Blickrichtung nach Norden
|
|
2537
|
+
pitch: this.Cesium.Math.toRadians(-30), // leicht nach unten schauen
|
|
2538
|
+
roll: 0.0,
|
|
2539
|
+
},
|
|
2540
|
+
// optional: onComplete / onCancel callbacks
|
|
2541
|
+
complete: () => log('v-map - provider - cesium - Fly‑to finished'),
|
|
2542
|
+
cancel: () => warn('v-map - provider - cesium - Fly‑to cancelled'),
|
|
2543
|
+
});
|
|
2544
|
+
}
|
|
2545
|
+
async fetchWFSFromUrl(config) {
|
|
2546
|
+
const baseParams = {
|
|
2547
|
+
service: 'WFS',
|
|
2548
|
+
request: 'GetFeature',
|
|
2549
|
+
version: config.version ?? '1.1.0',
|
|
2550
|
+
typeName: config.typeName,
|
|
2551
|
+
outputFormat: config.outputFormat ?? 'application/json',
|
|
2552
|
+
srsName: config.srsName ?? 'EPSG:4326',
|
|
2553
|
+
};
|
|
2554
|
+
const params = { ...baseParams, ...(config.params ?? {}) };
|
|
2555
|
+
const requestUrl = this.appendParams(config.url, params);
|
|
2556
|
+
const response = await fetch(requestUrl);
|
|
2557
|
+
if (!response.ok) {
|
|
2558
|
+
throw new Error(`WFS request failed (${response.status} ${response.statusText})`);
|
|
2559
|
+
}
|
|
2560
|
+
const outputFormat = (config.outputFormat ?? 'application/json').toLowerCase();
|
|
2561
|
+
// Handle JSON formats
|
|
2562
|
+
if (outputFormat.includes('json') ||
|
|
2563
|
+
outputFormat.includes('geojson') ||
|
|
2564
|
+
outputFormat === 'application/json') {
|
|
2565
|
+
const contentType = response.headers.get('content-type');
|
|
2566
|
+
if (contentType?.includes('application/json')) {
|
|
2567
|
+
return await response.json();
|
|
2568
|
+
}
|
|
2569
|
+
// Try to parse as JSON anyway
|
|
2570
|
+
const text = await response.text();
|
|
2571
|
+
return JSON.parse(text);
|
|
2572
|
+
}
|
|
2573
|
+
// Handle GML formats - parse XML to GeoJSON using @npm9912/s-gml
|
|
2574
|
+
if (outputFormat.includes('gml') || outputFormat.includes('xml')) {
|
|
2575
|
+
const xml = await response.text();
|
|
2576
|
+
const { GmlParser } = await import('./index.browser-DhQAXuA7.js');
|
|
2577
|
+
const parser = new GmlParser();
|
|
2578
|
+
return await parser.parse(xml);
|
|
2579
|
+
}
|
|
2580
|
+
// Default: try to parse as JSON
|
|
2581
|
+
return await response.json();
|
|
2582
|
+
}
|
|
2583
|
+
appendParams(baseUrl, params) {
|
|
2584
|
+
const query = new URLSearchParams();
|
|
2585
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
2586
|
+
if (value !== undefined && value !== null) {
|
|
2587
|
+
query.set(key, String(value));
|
|
2588
|
+
}
|
|
2589
|
+
});
|
|
2590
|
+
if (!query.toString())
|
|
2591
|
+
return baseUrl;
|
|
2592
|
+
return `${baseUrl}${baseUrl.includes('?') ? '&' : '?'}${query.toString()}`;
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2596
|
+
export { CesiumProvider };
|