isard 2.4.1 → 2.5.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/CHANGELOG.md +32 -0
- package/README.md +7 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/isard_tess_bg.wasm +0 -0
- package/dist/isard_webgl2_bg.wasm +0 -0
- package/dist/isard_webgpu_bg.wasm +0 -0
- package/dist/layers/tiles3d.d.ts +19 -1
- package/dist/layers/tiles3d.js +44 -0
- package/dist/layers/tiles3d.js.map +1 -1
- package/dist/map/engines.d.ts +8 -4
- package/dist/map/engines.js +16 -2
- package/dist/map/engines.js.map +1 -1
- package/dist/map/events.js +1 -0
- package/dist/map/events.js.map +1 -1
- package/dist/map.d.ts +23 -3
- package/dist/map.js +80 -10
- package/dist/map.js.map +1 -1
- package/dist/react/IsardMap.d.ts +1 -0
- package/dist/react/IsardMap.js +1 -0
- package/dist/react/IsardMap.js.map +1 -1
- package/dist/types.d.ts +33 -0
- package/dist/types.js.map +1 -1
- package/dist/wasm/isard_webgl2.d.ts +27 -2
- package/dist/wasm/isard_webgl2.js +89 -11
- package/dist/wasm/isard_webgpu.d.ts +27 -2
- package/dist/wasm/isard_webgpu.js +89 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ versions [Semantic Versioning](https://semver.org) (before 1.0.0, a minor versio
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [2.5.0] - 2026-11-02
|
|
9
|
+
|
|
10
|
+
With `isard-react-native` and `isard-map` (Python) 2.5.0.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Finding a feature and framing it (#176): `map.fitBounds(box, options)` frames a box on the ground or in space (its
|
|
15
|
+
bottom and top altitudes: a building, a pipe underground), all of it within the canvas less the padding, at the pitch
|
|
16
|
+
and bearing given; `tiles3d.refine(box)` loads the tiles meeting a box to their finest level, first, in view or not,
|
|
17
|
+
resolved once they are there; `tiles3d.find(matches)` gives the first feature of the tiles drawn whose properties
|
|
18
|
+
match; `map.geoidHeight([lon, lat])`. The example Find a building, in its four versions.
|
|
19
|
+
- `onGpuLost` on `<IsardMap>` (the `'gpulost'` event).
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- The API page listed `map.camera`, `map.query` and `map.effects`, gone since the public API was made consistent.
|
|
24
|
+
|
|
25
|
+
## [2.4.2] - 2026-11-02
|
|
26
|
+
|
|
27
|
+
With `isard-react-native` and `isard-map` (Python) 2.4.2.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- `map.renderer` (`'webgpu'` or `'webgl2'`) and the `'gpulost'` event: `{ reason, message, losses, recovery }`; in
|
|
32
|
+
`isard-react-native`, the view's `onError` hears it, and the examples' app too.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- A map whose WebGPU device is lost (an iPhone taking its memory back: Paris by night went black and stayed so) is made
|
|
37
|
+
again lighter so as not to lose it again: the low quality and half the GPU memory budget at the first loss, the WebGL2
|
|
38
|
+
fallback at the next one, or when WebGPU gives no new device.
|
|
39
|
+
|
|
8
40
|
## [2.4.1] - 2026-11-02
|
|
9
41
|
|
|
10
42
|
With `isard-react-native` and `isard-map` (Python) 2.4.1.
|
package/README.md
CHANGED
|
@@ -187,10 +187,13 @@ More in [Develop and release](https://ideal-adventure-zqn6y6p.pages.github.io/gu
|
|
|
187
187
|
By priority:
|
|
188
188
|
|
|
189
189
|
- **P1**, next: the memory budget measured on a phone (a phone closes a page past about a gigabyte).
|
|
190
|
-
- **P2**, then:
|
|
191
|
-
|
|
192
|
-
- **
|
|
193
|
-
|
|
190
|
+
- **P2**, then: OGC API - Features and Tiles (#177); virtual point clouds (#183); Cloud-Optimized GeoTIFF (#184);
|
|
191
|
+
measured against iTowns on 3D data (#178); rasters draped within an area; a performance report.
|
|
192
|
+
- **P3**, later: several elevation sources (#179); a time for layers (#180); objects moving along paths (#181); photos
|
|
193
|
+
projected onto the meshes (#187) and video in the scene; composable effects over the frame (#182).
|
|
194
|
+
- **P4**, when time allows: Gaussian splats (#186), WebXR (#185), the whole MapLibre style drawn as vectors, a 3D
|
|
195
|
+
vector map to walk through, Panoramax's street-level photos, fluids on the globe, several projections on the globe,
|
|
196
|
+
smaller items.
|
|
194
197
|
|
|
195
198
|
See [Roadmap](https://ideal-adventure-zqn6y6p.pages.github.io/guide/roadmap).
|
|
196
199
|
|
package/dist/index.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ export { type VectorFeature, VectorLayer, type VectorSublayer } from './layers/v
|
|
|
67
67
|
export type { HoverPicking } from './map/hover-pick.ts';
|
|
68
68
|
export { GeoMap, type LayerSpec } from './map.ts';
|
|
69
69
|
export { PANORAMAX_API, type PanoramaxPicture, type PanoramaxSequenceOptions, panoramaxPanoramas, panoramaxPhoto, panoramaxPicture, panoramaxSequence, panoramaxStyle, } from './panoramax.ts';
|
|
70
|
-
export type { AnimationOptions, AtmosphereOptions, Basemap, BasemapName, BodyOptions, CelestialBody, ClipBox, ClipCylinder, ClipPolygon, ClipVolume, Drape, FeatureColor, FeatureHit, FirstPersonView, FlyToOptions, GeoMapOptions, LoadingMode, LonLat, MapEvents, MapGpuTimings, MapHoverFeatureEvent, MapMemory, MapPointerEvent, NetworkOptions, NetworkStyle, PickOptions, Placement, Point, Projection, Quality, RasterGrid, RasterOptions, RasterStyle, SunOptions, SwipeOptions, TerrainEncoding, TerrainModel, TerrainOptions, Tiles3dOptions, Tiles3dStyle, ViewshedOptions, } from './types.ts';
|
|
70
|
+
export type { AnimationOptions, AtmosphereOptions, Basemap, BasemapName, BodyOptions, CelestialBody, ClipBox, ClipCylinder, ClipPolygon, ClipVolume, Drape, FeatureColor, FeatureHit, FirstPersonView, FitBoundsOptions, FitBox, FlyToOptions, GeoMapOptions, LoadingMode, LonLat, MapEvents, MapGpuTimings, MapHoverFeatureEvent, MapMemory, MapPointerEvent, NetworkOptions, NetworkStyle, PickOptions, Placement, Point, Projection, Quality, RasterGrid, RasterOptions, RasterStyle, SunOptions, SwipeOptions, TerrainEncoding, TerrainModel, TerrainOptions, Tiles3dOptions, Tiles3dStyle, ViewshedOptions, } from './types.ts';
|
|
71
71
|
export { AttributionControl, type AttributionOptions, type Control, type ControlPosition, NavigationControl, type NavigationOptions, } from './ui/controls.ts';
|
|
72
72
|
export { MinimapControl, type MinimapOptions } from './ui/minimap.ts';
|
|
73
73
|
export { type Anchor, Marker, type MarkerEvent, type MarkerEvents, type MarkerOptions, Panel, type PanelOptions, Popup, type PopupEvents, type PopupOptions, } from './ui/overlay.ts';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAE3F,OAAO,EAAE,YAAY,EAAmB,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EACL,OAAO,EAIP,WAAW,EACX,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAuB,MAAM,2BAA2B,CAAC;AAiB5E,OAAO,EAAE,QAAQ,EAAuB,MAAM,kCAAkC,CAAC;AAEjF,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACxF,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAsB,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAGL,MAAM,EACN,qBAAqB,EACrB,WAAW,EACX,SAAS,EACT,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAOL,OAAO,EACP,OAAO,GACR,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,aAAa,EAAoC,MAAM,oBAAoB,CAAC;AAErF,OAAO,EACL,gBAAgB,EAEhB,WAAW,EACX,eAAe,EACf,WAAW,EAEX,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,WAAW,EAEX,aAAa,GACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAa,MAAM,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAoBxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEhH,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEtF,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAKL,SAAS,GAEV,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAqB,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEnE,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAmC,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAsB,WAAW,EAAuB,MAAM,qBAAqB,CAAC;AAE3F,OAAO,EAAE,MAAM,EAAkB,MAAM,UAAU,CAAC;AAClD,OAAO,EACL,aAAa,EAGb,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,GACf,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * isard: a WebGL2 map engine for large, interactive data layers, labels and 3D Tiles.\n *\n * ```ts\n * import { GeoMap } from 'isard';\n * const map = await GeoMap.create(container, { center: [2.4246, 48.8457], zoom: 13 });\n * const network = map.addNetwork({ nodes, edges, max: 1800, contour: 300 });\n * map.on('hover', ({ lonLat }) => lonLat && network.setValues(travelTimes(lonLat)));\n * map.addTiles3d({ url: 'https://…/tileset.json' });\n * map.addControl(new NavigationControl());\n * new Marker().setLonLat([2.4246, 48.8457]).setPopup(new Popup({ offset: [0, -34] }).setText('Here')).addTo(map);\n * ```\n */\nexport { OPENFREEMAP_ATTRIBUTION, TERRAIN_TILES_ATTRIBUTION } from './basemap/basemaps.ts';\nexport type { TileGrid, TileMatrix } from './basemap/grid.ts';\nexport { coniferModel, type TreeColors, treeModel } from './basemap/models/trees.ts';\nexport {\n PMTiles,\n type PmtilesEntry,\n type PmtilesHeader,\n type PmtilesTileType,\n tileIdToZxy,\n zxyToTileId,\n} from './basemap/pmtiles.ts';\nexport { basicStyle, type PmtilesOptions } from './basemap/pmtileslayer.ts';\nexport type {\n CandidateIcon,\n CandidateOverlap,\n Json,\n LabelCandidate,\n RasterSource,\n Style,\n StyleLayer,\n} from './basemap/vectorstyle.ts';\nexport type { VectorExtrusionOptions } from './basemap/vectortiles/extrusions.ts';\nexport type { FurnitureOptions } from './basemap/vectortiles/furniture.ts';\nexport type { LabelsOptions } from './basemap/vectortiles/labels.ts';\nexport type { LampsOptions } from './basemap/vectortiles/lamps.ts';\nexport type { StreetWindLayer, StreetWindOptions } from './basemap/vectortiles/street-wind.ts';\nexport type { LoadedStyle } from './basemap/vectortiles/style.ts';\nexport type { TreesOptions } from './basemap/vectortiles/trees.ts';\nexport { isStreet, type VectorsOptions } from './basemap/vectortiles/vectors.ts';\nexport type { VectorRasterOptions, VectorTilesOptions } from './basemap/vectortiles.ts';\nexport { OPENFREEMAP_STYLES, PLAN_STYLES, VectorTiles } from './basemap/vectortiles.ts';\nexport { parseWmtsGrid, wmtsGrid } from './basemap/wmts.ts';\nexport { type ColladaImages, colladaImages, loadCollada, parseCollada } from './data/collada.ts';\nexport {\n type Crs,\n type CrsLike,\n getCrs,\n lambertConformalConic,\n registerCrs,\n reproject,\n transverseMercator,\n} from './data/crs.ts';\nexport { parseGpx } from './data/gpx.ts';\nexport {\n type IfcElement,\n type IfcModel,\n type IfcOptions,\n type IfcPlace,\n type IfcProperties,\n type IfcStorey,\n loadIfc,\n WEB_IFC,\n} from './data/ifc.ts';\nexport { parseKml } from './data/kml.ts';\nexport { parseTopoJson, type TopoGeometry, type Topology } from './data/topojson.ts';\nexport type { DecoderUrls } from './decoding/decoders.ts';\nexport {\n BATIMENTS_3D_URL,\n type BdTopoBuilding,\n batiments3d,\n bdtopoBuildings,\n bdtopoRoofs,\n type GeocodedPlace,\n geoplateformeGeocode,\n geoplateformeWfs,\n geoplateformeWms,\n geoplateformeWmts,\n IGN_ATTRIBUTION,\n IGN_PRESETS,\n type IgnPreset,\n lambert93Grid,\n} from './geoplateforme.ts';\nexport { type Grid, windAt, windFields } from './grids.ts';\nexport type { CustomFrame, CustomLayerInterface } from './layers/custom.ts';\nexport { CustomLayer } from './layers/custom.ts';\nexport type { ExtrusionOptions, ExtrusionStyle, PolygonArrays, TileKey } from './layers/extrusions.ts';\nexport { ExtrusionLayer } from './layers/extrusions.ts';\nexport type {\n CircleOptions,\n CircleStyle,\n Feature,\n FeatureCollection,\n FeatureData,\n FeatureLayerStyle,\n FillOptions,\n FillStyle,\n Geometry,\n LineOptions,\n LineStyle,\n Position,\n Properties,\n Ramp,\n Size,\n Stops,\n Styled,\n} from './layers/features.ts';\nexport { CircleLayer, FeatureLayer, FillLayer, interpolate, LineLayer, parseColor } from './layers/features.ts';\nexport type { FlowField, FlowOptions, FlowStyle, TimedField } from './layers/flow.ts';\nexport { FlowLayer, flowFieldFromImage, flowFieldsFromImage } from './layers/flow.ts';\nexport type { TextPart } from './layers/glyphs.ts';\nexport { DEFAULT_FONT, GLYPHS_URL } from './layers/glyphs.ts';\nexport type { GroundOptions, GroundTexture, GroundUniform } from './layers/ground.ts';\nexport { GroundLayer } from './layers/ground.ts';\nexport type { ImageOptions, Pixels, SpriteIcon } from './layers/icons.ts';\nexport { Layer } from './layers/layers.ts';\nexport type { ModelInstance, ModelOptions } from './layers/models.ts';\nexport { ModelLayer } from './layers/models.ts';\nexport { NetworkLayer } from './layers/network.ts';\nexport {\n type CalibratedPanoramaOptions,\n type Panorama,\n type PanoramaOptions,\n type PanoramaPhoto,\n Panoramas,\n type PhotoPanoramaOptions,\n} from './layers/panoramas.ts';\nexport { type PhotoOptions, photoModel } from './layers/photos.ts';\nexport type { ClassStyle, PointCloudOptions, PointCloudStyle, PointColor } from './layers/pointclouds.ts';\nexport { CLASSIFICATIONS, ELEVATION_RAMP, PointCloudLayer } from './layers/pointclouds.ts';\nexport { RasterLayer } from './layers/raster.ts';\nexport type { Overlap, SymbolOptions, SymbolStyle } from './layers/symbols.ts';\nexport { SymbolLayer } from './layers/symbols.ts';\nexport { Tiles3dLayer } from './layers/tiles3d.ts';\nexport { type TreeKind, type TreeOptions, treeKind } from './layers/trees.ts';\nexport { type VectorFeature, VectorLayer, type VectorSublayer } from './layers/vectors.ts';\nexport type { HoverPicking } from './map/hover-pick.ts';\nexport { GeoMap, type LayerSpec } from './map.ts';\nexport {\n PANORAMAX_API,\n type PanoramaxPicture,\n type PanoramaxSequenceOptions,\n panoramaxPanoramas,\n panoramaxPhoto,\n panoramaxPicture,\n panoramaxSequence,\n panoramaxStyle,\n} from './panoramax.ts';\nexport type {\n AnimationOptions,\n AtmosphereOptions,\n Basemap,\n BasemapName,\n BodyOptions,\n CelestialBody,\n ClipBox,\n ClipCylinder,\n ClipPolygon,\n ClipVolume,\n Drape,\n FeatureColor,\n FeatureHit,\n FirstPersonView,\n FitBoundsOptions,\n FitBox,\n FlyToOptions,\n GeoMapOptions,\n LoadingMode,\n LonLat,\n MapEvents,\n MapGpuTimings,\n MapHoverFeatureEvent,\n MapMemory,\n MapPointerEvent,\n NetworkOptions,\n NetworkStyle,\n PickOptions,\n Placement,\n Point,\n Projection,\n Quality,\n RasterGrid,\n RasterOptions,\n RasterStyle,\n SunOptions,\n SwipeOptions,\n TerrainEncoding,\n TerrainModel,\n TerrainOptions,\n Tiles3dOptions,\n Tiles3dStyle,\n ViewshedOptions,\n} from './types.ts';\nexport {\n AttributionControl,\n type AttributionOptions,\n type Control,\n type ControlPosition,\n NavigationControl,\n type NavigationOptions,\n} from './ui/controls.ts';\nexport { MinimapControl, type MinimapOptions } from './ui/minimap.ts';\nexport {\n type Anchor,\n Marker,\n type MarkerEvent,\n type MarkerEvents,\n type MarkerOptions,\n Panel,\n type PanelOptions,\n Popup,\n type PopupEvents,\n type PopupOptions,\n} from './ui/overlay.ts';\nexport { lengthLabel, roundLength, ScaleControl, type ScaleOptions } from './ui/scale.ts';\nexport { SearchControl, type SearchOptions } from './ui/search.ts';\nexport { setRequestHeaders } from './util/requests.ts';\nexport type { RoofMode } from './util/roofs.ts';\nexport { sunPosition } from './util/sun.ts';\nexport type {\n Camera,\n NetworkStats,\n PickHit,\n PickResult,\n PointCloudInfo,\n PointCloudPoint,\n PointCloudStats,\n RasterLayerStats,\n Tiles3dStats,\n} from './wasm/isard_webgpu.js';\n"]}
|
package/dist/isard_tess_bg.wasm
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/layers/tiles3d.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** A 3D Tiles tileset as a layer: its style, its features picked */
|
|
2
|
-
import type { Drape, Tiles3dStyle } from '../types.ts';
|
|
2
|
+
import type { Drape, FitBox, Tiles3dStyle } from '../types.ts';
|
|
3
3
|
import type { Tiles3dStats } from '../wasm/isard_webgpu.js';
|
|
4
|
+
import type { Feature } from './features.ts';
|
|
4
5
|
import { Layer } from './layers.ts';
|
|
5
6
|
/** Textured meshes in 3D Tiles */
|
|
6
7
|
export declare class Tiles3dLayer extends Layer {
|
|
@@ -9,6 +10,17 @@ export declare class Tiles3dLayer extends Layer {
|
|
|
9
10
|
private style;
|
|
10
11
|
private facades;
|
|
11
12
|
private drape;
|
|
13
|
+
/** The box loaded to its finest tiles (`refine`): west, south, east, north, bottom, top */
|
|
14
|
+
private focus;
|
|
15
|
+
/**
|
|
16
|
+
* Loads the tiles meeting a box to their finest level, before the others and whether the box is in view or not (a
|
|
17
|
+
* feature framed to be found in them: its finest geometry, its ID); resolved once they are all there. The box stays
|
|
18
|
+
* so until another one, or `refine(undefined)`. `box`: as `fitBounds` takes it, altitudes in metres above the
|
|
19
|
+
* ellipsoid; `timeout` (ms, default 30 s): rejected past it
|
|
20
|
+
*/
|
|
21
|
+
refine(box: FitBox | FitBox['bounds'] | undefined, { timeout }?: {
|
|
22
|
+
timeout?: number | undefined;
|
|
23
|
+
}): Promise<void>;
|
|
12
24
|
/** Whether the walls of its untextured meshes (buildings without their photos, as the IGN's Bâtiments 3D) show
|
|
13
25
|
* windows, as the vector tiles' buildings do: glass by day, some lit at night. Their faces near vertical are walls,
|
|
14
26
|
* bays of 3 metres along them and floors of 3.2 metres from the ellipsoid (a mesh tells neither foot nor top) */
|
|
@@ -16,6 +28,12 @@ export declare class Tiles3dLayer extends Layer {
|
|
|
16
28
|
/** A raster layer draped on its meshes, its roofs by default (see `Drape`); undefined: none */
|
|
17
29
|
setDrape(drape: Drape | undefined): void;
|
|
18
30
|
setStyle(style: Partial<Tiles3dStyle>): void;
|
|
31
|
+
/**
|
|
32
|
+
* The first feature of the tiles drawn whose properties `matches` takes (its ID, its attributes), the finest tiles
|
|
33
|
+
* first: a feature framed and loaded (`fitBounds`, `refine`) found in them, to show or color (`featureColor`);
|
|
34
|
+
* undefined if none drawn has it
|
|
35
|
+
*/
|
|
36
|
+
find(matches: (properties: Record<string, unknown>) => boolean): Feature<Record<string, unknown>> | undefined;
|
|
19
37
|
/** Loading counters; undefined once the layer is removed, and while the map waits for a new engine (the GPU lost) */
|
|
20
38
|
stats(): Tiles3dStats | undefined;
|
|
21
39
|
private applyStyle;
|
package/dist/layers/tiles3d.js
CHANGED
|
@@ -43,6 +43,35 @@ export class Tiles3dLayer extends Layer {
|
|
|
43
43
|
this.facades = facades;
|
|
44
44
|
this.drape = drape;
|
|
45
45
|
}
|
|
46
|
+
/** The box loaded to its finest tiles (`refine`): west, south, east, north, bottom, top */
|
|
47
|
+
focus = [];
|
|
48
|
+
/**
|
|
49
|
+
* Loads the tiles meeting a box to their finest level, before the others and whether the box is in view or not (a
|
|
50
|
+
* feature framed to be found in them: its finest geometry, its ID); resolved once they are all there. The box stays
|
|
51
|
+
* so until another one, or `refine(undefined)`. `box`: as `fitBounds` takes it, altitudes in metres above the
|
|
52
|
+
* ellipsoid; `timeout` (ms, default 30 s): rejected past it
|
|
53
|
+
*/
|
|
54
|
+
async refine(box, { timeout = 30_000 } = {}) {
|
|
55
|
+
const { bounds, bottom = -1e4, top = 1e4 } = !box || Array.isArray(box) ? { bounds: box } : box;
|
|
56
|
+
this.focus = bounds ? [...bounds, Math.min(bottom, top), Math.max(bottom, top)] : [];
|
|
57
|
+
if (this.id >= 0)
|
|
58
|
+
this.map.engine.setTiles3dFocus(this.id, Float64Array.from(this.focus));
|
|
59
|
+
this.map.requestRender();
|
|
60
|
+
if (!bounds)
|
|
61
|
+
return;
|
|
62
|
+
const focus = this.focus;
|
|
63
|
+
const until = performance.now() + timeout;
|
|
64
|
+
// Its tiles counted by the frames drawn with the box (undefined before), the box still this one
|
|
65
|
+
while (this.focus === focus) {
|
|
66
|
+
const pending = this.id < 0 ? undefined : this.map.engine.tiles3dFocusPending(this.id);
|
|
67
|
+
if (pending === 0)
|
|
68
|
+
return;
|
|
69
|
+
if (performance.now() >= until)
|
|
70
|
+
throw new Error("isard: the box's tiles were not loaded in time");
|
|
71
|
+
this.map.requestRender();
|
|
72
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
46
75
|
/** Whether the walls of its untextured meshes (buildings without their photos, as the IGN's Bâtiments 3D) show
|
|
47
76
|
* windows, as the vector tiles' buildings do: glass by day, some lit at night. Their faces near vertical are walls,
|
|
48
77
|
* bays of 3 metres along them and floors of 3.2 metres from the ellipsoid (a mesh tells neither foot nor top) */
|
|
@@ -85,6 +114,20 @@ export class Tiles3dLayer extends Layer {
|
|
|
85
114
|
const [properties, feature] = hit;
|
|
86
115
|
return { type: 'Feature', id: feature, properties: properties ?? {}, geometry: null };
|
|
87
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* The first feature of the tiles drawn whose properties `matches` takes (its ID, its attributes), the finest tiles
|
|
119
|
+
* first: a feature framed and loaded (`fitBounds`, `refine`) found in them, to show or color (`featureColor`);
|
|
120
|
+
* undefined if none drawn has it
|
|
121
|
+
*/
|
|
122
|
+
find(matches) {
|
|
123
|
+
if (this.id < 0)
|
|
124
|
+
return undefined;
|
|
125
|
+
const hit = this.map.engine.tiles3dFind(this.id, matches);
|
|
126
|
+
if (!hit)
|
|
127
|
+
return undefined;
|
|
128
|
+
const [properties, feature] = hit;
|
|
129
|
+
return { type: 'Feature', id: feature, properties, geometry: null };
|
|
130
|
+
}
|
|
88
131
|
/** Loading counters; undefined once the layer is removed, and while the map waits for a new engine (the GPU lost) */
|
|
89
132
|
stats() {
|
|
90
133
|
return this.id < 0 ? undefined : this.map.engine.tiles3dStats(this.id);
|
|
@@ -95,6 +138,7 @@ export class Tiles3dLayer extends Layer {
|
|
|
95
138
|
this.applyStyle(engine, id);
|
|
96
139
|
this.applyFeatureColor(engine, id);
|
|
97
140
|
engine.setTiles3dFacades(id, this.facades);
|
|
141
|
+
engine.setTiles3dFocus(id, Float64Array.from(this.focus));
|
|
98
142
|
// A raster created before (on a new engine, the map relinks once every layer is there)
|
|
99
143
|
sendDrape(engine, id, this.drape);
|
|
100
144
|
return id;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tiles3d.js","sourceRoot":"","sources":["../../src/layers/tiles3d.ts"],"names":[],"mappings":"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","sourcesContent":["/** A 3D Tiles tileset as a layer: its style, its features picked */\n\nimport { rgb } from '../settings.ts';\nimport type { Drape, FeatureColor, LayerHost, Tiles3dStyle } from '../types.ts';\nimport { parseColor } from '../util/color.ts';\nimport type { Engine, Tiles3dStats } from '../wasm/isard_webgpu.js';\nimport type { Feature } from './features.ts';\nimport { Layer } from './layers.ts';\nimport { sendDrape } from './raster.ts';\n\n/**\n * The engine's colors of a tile's features from a `featureColor`: RGBA bytes for each (alpha 0: the layer's color),\n * the CSS colors parsed once each\n */\nconst featureColors = (color: FeatureColor) => {\n const parsed = new Map<string, number[]>();\n const bytesOf = (css: string) => {\n const known = parsed.get(css);\n\n if (known) return known;\n\n const [r, g, b] = parseColor(css);\n const made = [r, g, b].map((c) => Math.round(c * 255)).concat(255);\n\n parsed.set(css, made);\n\n return made;\n };\n\n return (properties: Record<string, unknown>[] | undefined, count: number): Uint8Array => {\n const rgba = new Uint8Array(count * 4);\n\n Array.from({ length: count }, (_, i) => color(properties?.[i] ?? {}, i)).forEach((css, i) => {\n if (css) rgba.set(bytesOf(css), i * 4);\n });\n\n return rgba;\n };\n};\n\n/** Textured meshes in 3D Tiles */\nexport class Tiles3dLayer extends Layer {\n /** @internal */\n constructor(\n map: LayerHost,\n private readonly url: string,\n private readonly geoid: boolean,\n private style: Tiles3dStyle,\n private facades = false,\n private drape: Drape | undefined = undefined,\n ) {\n super(map);\n }\n\n /** Whether the walls of its untextured meshes (buildings without their photos, as the IGN's Bâtiments 3D) show\n * windows, as the vector tiles' buildings do: glass by day, some lit at night. Their faces near vertical are walls,\n * bays of 3 metres along them and floors of 3.2 metres from the ellipsoid (a mesh tells neither foot nor top) */\n setFacades(facades: boolean): void {\n this.facades = facades;\n // Kept for its creation in a new engine (the GPU lost and given back), none while it has no id\n if (this.id < 0) return;\n this.map.engine.setTiles3dFacades(this.id, facades);\n this.map.requestRender();\n }\n\n /** A raster layer draped on its meshes, its roofs by default (see `Drape`); undefined: none */\n setDrape(drape: Drape | undefined): void {\n this.drape = drape;\n // Kept for its creation in a new engine (the GPU lost and given back), none while it has no id\n if (this.id < 0) return;\n sendDrape(this.map.engine, this.id, drape);\n this.map.requestRender();\n }\n\n setStyle(style: Partial<Tiles3dStyle>): void {\n this.style = { ...this.style, ...style };\n // Kept for its creation in a new engine (the GPU lost and given back), none while it has no id\n if (this.id < 0) return;\n this.applyStyle(this.map.engine, this.id);\n // The features colored again only when their function changed: every tile asks for its colors then\n if ('featureColor' in style) this.applyFeatureColor(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** @internal The feature picked (`pickFeature`, 'hoverfeature'): the properties of its feature in the tile\n * (`EXT_structural_metadata`, a b3dm batch table), none for a mesh without features; its index in the tile as id */\n featureAt(index: number): Feature<Record<string, unknown>> | undefined {\n if (this.id < 0) return undefined;\n\n const hit = this.map.engine.tiles3dFeature(this.id, index);\n\n if (!hit) return undefined;\n\n const [properties, feature] = hit;\n\n return { type: 'Feature', id: feature, properties: properties ?? {}, geometry: null };\n }\n\n /** Loading counters; undefined once the layer is removed, and while the map waits for a new engine (the GPU lost) */\n stats(): Tiles3dStats | undefined {\n return this.id < 0 ? undefined : this.map.engine.tiles3dStats(this.id);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addTiles3d(this.url, this.style.maxScreenSpaceError * this.map.quality.errorScale, this.geoid);\n\n this.applyStyle(engine, id);\n this.applyFeatureColor(engine, id);\n engine.setTiles3dFacades(id, this.facades);\n // A raster created before (on a new engine, the map relinks once every layer is there)\n sendDrape(engine, id, this.drape);\n\n return id;\n }\n\n /** @internal On a new engine, the raster may come after the tiles: draped once both are there */\n override relink(engine: Engine): void {\n sendDrape(engine, this.id, this.drape);\n }\n\n /** @internal */\n override qualityChanged(): void {\n if (this.id >= 0) this.applyStyle(this.map.engine, this.id);\n }\n\n private applyStyle(engine: Engine, id: number): void {\n const { maxScreenSpaceError, opacity, pointSize, color } = this.style;\n // Coarser far away at a lower quality\n const error = maxScreenSpaceError * this.map.quality.errorScale;\n\n engine.setTiles3dStyle(id, error, opacity, pointSize, new Float32Array(color ? rgb(color) : []));\n }\n\n private applyFeatureColor(engine: Engine, id: number): void {\n const { featureColor } = this.style;\n\n engine.setTiles3dFeatureColors(id, featureColor ? featureColors(featureColor) : null);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tiles3d.js","sourceRoot":"","sources":["../../src/layers/tiles3d.ts"],"names":[],"mappings":"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","sourcesContent":["/** A 3D Tiles tileset as a layer: its style, its features picked */\n\nimport { rgb } from '../settings.ts';\nimport type { Drape, FeatureColor, FitBox, LayerHost, Tiles3dStyle } from '../types.ts';\nimport { parseColor } from '../util/color.ts';\nimport type { Engine, Tiles3dStats } from '../wasm/isard_webgpu.js';\nimport type { Feature } from './features.ts';\nimport { Layer } from './layers.ts';\nimport { sendDrape } from './raster.ts';\n\n/**\n * The engine's colors of a tile's features from a `featureColor`: RGBA bytes for each (alpha 0: the layer's color),\n * the CSS colors parsed once each\n */\nconst featureColors = (color: FeatureColor) => {\n const parsed = new Map<string, number[]>();\n const bytesOf = (css: string) => {\n const known = parsed.get(css);\n\n if (known) return known;\n\n const [r, g, b] = parseColor(css);\n const made = [r, g, b].map((c) => Math.round(c * 255)).concat(255);\n\n parsed.set(css, made);\n\n return made;\n };\n\n return (properties: Record<string, unknown>[] | undefined, count: number): Uint8Array => {\n const rgba = new Uint8Array(count * 4);\n\n Array.from({ length: count }, (_, i) => color(properties?.[i] ?? {}, i)).forEach((css, i) => {\n if (css) rgba.set(bytesOf(css), i * 4);\n });\n\n return rgba;\n };\n};\n\n/** Textured meshes in 3D Tiles */\nexport class Tiles3dLayer extends Layer {\n /** @internal */\n constructor(\n map: LayerHost,\n private readonly url: string,\n private readonly geoid: boolean,\n private style: Tiles3dStyle,\n private facades = false,\n private drape: Drape | undefined = undefined,\n ) {\n super(map);\n }\n\n /** The box loaded to its finest tiles (`refine`): west, south, east, north, bottom, top */\n private focus: number[] = [];\n\n /**\n * Loads the tiles meeting a box to their finest level, before the others and whether the box is in view or not (a\n * feature framed to be found in them: its finest geometry, its ID); resolved once they are all there. The box stays\n * so until another one, or `refine(undefined)`. `box`: as `fitBounds` takes it, altitudes in metres above the\n * ellipsoid; `timeout` (ms, default 30 s): rejected past it\n */\n async refine(box: FitBox | FitBox['bounds'] | undefined, { timeout = 30_000 } = {}): Promise<void> {\n const { bounds, bottom = -1e4, top = 1e4 } = !box || Array.isArray(box) ? { bounds: box } : box;\n\n this.focus = bounds ? [...bounds, Math.min(bottom, top), Math.max(bottom, top)] : [];\n if (this.id >= 0) this.map.engine.setTiles3dFocus(this.id, Float64Array.from(this.focus));\n this.map.requestRender();\n if (!bounds) return;\n\n const focus = this.focus;\n const until = performance.now() + timeout;\n\n // Its tiles counted by the frames drawn with the box (undefined before), the box still this one\n while (this.focus === focus) {\n const pending = this.id < 0 ? undefined : this.map.engine.tiles3dFocusPending(this.id);\n\n if (pending === 0) return;\n if (performance.now() >= until) throw new Error(\"isard: the box's tiles were not loaded in time\");\n this.map.requestRender();\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n }\n\n /** Whether the walls of its untextured meshes (buildings without their photos, as the IGN's Bâtiments 3D) show\n * windows, as the vector tiles' buildings do: glass by day, some lit at night. Their faces near vertical are walls,\n * bays of 3 metres along them and floors of 3.2 metres from the ellipsoid (a mesh tells neither foot nor top) */\n setFacades(facades: boolean): void {\n this.facades = facades;\n // Kept for its creation in a new engine (the GPU lost and given back), none while it has no id\n if (this.id < 0) return;\n this.map.engine.setTiles3dFacades(this.id, facades);\n this.map.requestRender();\n }\n\n /** A raster layer draped on its meshes, its roofs by default (see `Drape`); undefined: none */\n setDrape(drape: Drape | undefined): void {\n this.drape = drape;\n // Kept for its creation in a new engine (the GPU lost and given back), none while it has no id\n if (this.id < 0) return;\n sendDrape(this.map.engine, this.id, drape);\n this.map.requestRender();\n }\n\n setStyle(style: Partial<Tiles3dStyle>): void {\n this.style = { ...this.style, ...style };\n // Kept for its creation in a new engine (the GPU lost and given back), none while it has no id\n if (this.id < 0) return;\n this.applyStyle(this.map.engine, this.id);\n // The features colored again only when their function changed: every tile asks for its colors then\n if ('featureColor' in style) this.applyFeatureColor(this.map.engine, this.id);\n this.map.requestRender();\n }\n\n /** @internal The feature picked (`pickFeature`, 'hoverfeature'): the properties of its feature in the tile\n * (`EXT_structural_metadata`, a b3dm batch table), none for a mesh without features; its index in the tile as id */\n featureAt(index: number): Feature<Record<string, unknown>> | undefined {\n if (this.id < 0) return undefined;\n\n const hit = this.map.engine.tiles3dFeature(this.id, index);\n\n if (!hit) return undefined;\n\n const [properties, feature] = hit;\n\n return { type: 'Feature', id: feature, properties: properties ?? {}, geometry: null };\n }\n\n /**\n * The first feature of the tiles drawn whose properties `matches` takes (its ID, its attributes), the finest tiles\n * first: a feature framed and loaded (`fitBounds`, `refine`) found in them, to show or color (`featureColor`);\n * undefined if none drawn has it\n */\n find(matches: (properties: Record<string, unknown>) => boolean): Feature<Record<string, unknown>> | undefined {\n if (this.id < 0) return undefined;\n\n const hit = this.map.engine.tiles3dFind(this.id, matches);\n\n if (!hit) return undefined;\n\n const [properties, feature] = hit;\n\n return { type: 'Feature', id: feature, properties, geometry: null };\n }\n\n /** Loading counters; undefined once the layer is removed, and while the map waits for a new engine (the GPU lost) */\n stats(): Tiles3dStats | undefined {\n return this.id < 0 ? undefined : this.map.engine.tiles3dStats(this.id);\n }\n\n /** @internal */\n protected create(engine: Engine): number {\n const id = engine.addTiles3d(this.url, this.style.maxScreenSpaceError * this.map.quality.errorScale, this.geoid);\n\n this.applyStyle(engine, id);\n this.applyFeatureColor(engine, id);\n engine.setTiles3dFacades(id, this.facades);\n engine.setTiles3dFocus(id, Float64Array.from(this.focus));\n // A raster created before (on a new engine, the map relinks once every layer is there)\n sendDrape(engine, id, this.drape);\n\n return id;\n }\n\n /** @internal On a new engine, the raster may come after the tiles: draped once both are there */\n override relink(engine: Engine): void {\n sendDrape(engine, this.id, this.drape);\n }\n\n /** @internal */\n override qualityChanged(): void {\n if (this.id >= 0) this.applyStyle(this.map.engine, this.id);\n }\n\n private applyStyle(engine: Engine, id: number): void {\n const { maxScreenSpaceError, opacity, pointSize, color } = this.style;\n // Coarser far away at a lower quality\n const error = maxScreenSpaceError * this.map.quality.errorScale;\n\n engine.setTiles3dStyle(id, error, opacity, pointSize, new Float32Array(color ? rgb(color) : []));\n }\n\n private applyFeatureColor(engine: Engine, id: number): void {\n const { featureColor } = this.style;\n\n engine.setTiles3dFeatureColors(id, featureColor ? featureColors(featureColor) : null);\n }\n}\n"]}
|
package/dist/map/engines.d.ts
CHANGED
|
@@ -2,19 +2,23 @@
|
|
|
2
2
|
* The engine a map runs, made asynchronously (its device asked for), and the workers decoding its 3D Tiles, started
|
|
3
3
|
* with the first one.
|
|
4
4
|
*/
|
|
5
|
-
import { type EngineClass } from '../engine-loader.ts';
|
|
5
|
+
import { type EngineClass, type EngineKind } from '../engine-loader.ts';
|
|
6
6
|
import type { Settings } from '../settings.ts';
|
|
7
7
|
import type { GeoMapOptions } from '../types.ts';
|
|
8
8
|
import type { Engine } from '../wasm/isard_webgpu.js';
|
|
9
9
|
/** What making the engine and its workers needs */
|
|
10
|
-
export type Tiles3dEngineOptions = Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'tiles3dWasmUrl' | 'assetsUrl' | 'quality' | 'antialias'>;
|
|
10
|
+
export type Tiles3dEngineOptions = Pick<GeoMapOptions, 'workers' | 'workerUrl' | 'decoders' | 'pointsWasmUrl' | 'tiles3dWasmUrl' | 'webgl2WasmUrl' | 'assetsUrl' | 'quality' | 'antialias'>;
|
|
11
11
|
/** The engine class of a map (the engine on wgpu, through WebGPU or its WebGL2 fallback: one module, 3D Tiles
|
|
12
12
|
* included) and the workers decoding its 3D Tiles, started with the first engine */
|
|
13
13
|
export declare class MapEngines {
|
|
14
|
-
private
|
|
14
|
+
#private;
|
|
15
|
+
private engineClass;
|
|
15
16
|
private loader;
|
|
16
17
|
private readonly options;
|
|
17
|
-
constructor(engineClass: EngineClass, options: Tiles3dEngineOptions);
|
|
18
|
+
constructor(engineClass: EngineClass, renderer: EngineKind, options: Tiles3dEngineOptions);
|
|
19
|
+
get renderer(): EngineKind;
|
|
20
|
+
/** The next engines through WebGL2 (a device WebGPU keeps losing or no longer gives): its module loaded */
|
|
21
|
+
fallBack(): Promise<void>;
|
|
18
22
|
/** A new engine drawing on `canvas` (its device asked for), with the settings and the decoding workers */
|
|
19
23
|
create(canvas: HTMLCanvasElement, redraw: () => void, settings: Settings): Promise<Engine>;
|
|
20
24
|
/** Height of the geoid above the ellipsoid at a position, in metres */
|
package/dist/map/engines.js
CHANGED
|
@@ -2,18 +2,32 @@
|
|
|
2
2
|
* The engine a map runs, made asynchronously (its device asked for), and the workers decoding its 3D Tiles, started
|
|
3
3
|
* with the first one.
|
|
4
4
|
*/
|
|
5
|
-
import { startTileLoader } from "../engine-loader.js";
|
|
5
|
+
import { engineUrl, loadEngine, startTileLoader } from "../engine-loader.js";
|
|
6
6
|
import { applySettings } from "./engine-settings.js";
|
|
7
7
|
/** The engine class of a map (the engine on wgpu, through WebGPU or its WebGL2 fallback: one module, 3D Tiles
|
|
8
8
|
* included) and the workers decoding its 3D Tiles, started with the first engine */
|
|
9
9
|
export class MapEngines {
|
|
10
10
|
engineClass;
|
|
11
|
+
/** What the engine draws through: WebGPU, or its WebGL2 fallback (`fallBack`) */
|
|
12
|
+
#renderer;
|
|
11
13
|
loader;
|
|
12
14
|
options;
|
|
13
|
-
constructor(engineClass, options) {
|
|
15
|
+
constructor(engineClass, renderer, options) {
|
|
14
16
|
this.engineClass = engineClass;
|
|
17
|
+
this.#renderer = renderer;
|
|
15
18
|
this.options = { ...options };
|
|
16
19
|
}
|
|
20
|
+
get renderer() {
|
|
21
|
+
return this.#renderer;
|
|
22
|
+
}
|
|
23
|
+
/** The next engines through WebGL2 (a device WebGPU keeps losing or no longer gives): its module loaded */
|
|
24
|
+
async fallBack() {
|
|
25
|
+
if (this.#renderer === 'webgl2')
|
|
26
|
+
return;
|
|
27
|
+
const bindings = await loadEngine('webgl2', engineUrl('webgl2', this.options));
|
|
28
|
+
this.engineClass = bindings.Engine;
|
|
29
|
+
this.#renderer = 'webgl2';
|
|
30
|
+
}
|
|
17
31
|
/** A new engine drawing on `canvas` (its device asked for), with the settings and the decoding workers */
|
|
18
32
|
async create(canvas, redraw, settings) {
|
|
19
33
|
const engine = await this.engineClass.create(canvas, redraw, this.options.antialias);
|
package/dist/map/engines.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engines.js","sourceRoot":"","sources":["../../src/map/engines.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"engines.js","sourceRoot":"","sources":["../../src/map/engines.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAqC,SAAS,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAIhH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAgBrD;oFACoF;AACpF,MAAM,OAAO,UAAU;IACb,WAAW,CAAc;IACjC,iFAAiF;IACjF,SAAS,CAAa;IACd,MAAM,CAAyB;IACtB,OAAO,CAAuB;IAE/C,YAAY,WAAwB,EAAE,QAAoB,EAAE,OAA6B;QACvF,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;QAC1B,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,2GAA2G;IAC3G,KAAK,CAAC,QAAQ;QACZ,IAAI,IAAI,CAAC,SAAS,KAAK,QAAQ;YAAE,OAAO;QAExC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QAE/E,IAAI,CAAC,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC;IAC5B,CAAC;IAED,0GAA0G;IAC1G,KAAK,CAAC,MAAM,CAAC,MAAyB,EAAE,MAAkB,EAAE,QAAkB;QAC5E,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAErF,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,KAAK,eAAe,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACtD,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEnD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,uEAAuE;IACvE,WAAW,CAAC,GAAW,EAAE,GAAW;QAClC,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC;IAED,yDAAyD;IACzD,YAAY,CAAC,GAAW,EAAE,GAAW,EAAE,QAAgB;QACrD,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED,iCAAiC;IACjC,OAAO;QACL,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;IACzB,CAAC;CACF","sourcesContent":["/**\n * The engine a map runs, made asynchronously (its device asked for), and the workers decoding its 3D Tiles, started\n * with the first one.\n */\n\nimport type { TileLoader } from '../decoding/loader.ts';\nimport { type EngineClass, type EngineKind, engineUrl, loadEngine, startTileLoader } from '../engine-loader.ts';\nimport type { Settings } from '../settings.ts';\nimport type { GeoMapOptions } from '../types.ts';\nimport type { Engine } from '../wasm/isard_webgpu.js';\nimport { applySettings } from './engine-settings.ts';\n\n/** What making the engine and its workers needs */\nexport type Tiles3dEngineOptions = Pick<\n GeoMapOptions,\n | 'workers'\n | 'workerUrl'\n | 'decoders'\n | 'pointsWasmUrl'\n | 'tiles3dWasmUrl'\n | 'webgl2WasmUrl'\n | 'assetsUrl'\n | 'quality'\n | 'antialias'\n>;\n\n/** The engine class of a map (the engine on wgpu, through WebGPU or its WebGL2 fallback: one module, 3D Tiles\n * included) and the workers decoding its 3D Tiles, started with the first engine */\nexport class MapEngines {\n private engineClass: EngineClass;\n /** What the engine draws through: WebGPU, or its WebGL2 fallback (`fallBack`) */\n #renderer: EngineKind;\n private loader: TileLoader | undefined;\n private readonly options: Tiles3dEngineOptions;\n\n constructor(engineClass: EngineClass, renderer: EngineKind, options: Tiles3dEngineOptions) {\n this.engineClass = engineClass;\n this.#renderer = renderer;\n this.options = { ...options };\n }\n\n get renderer(): EngineKind {\n return this.#renderer;\n }\n\n /** The next engines through WebGL2 (a device WebGPU keeps losing or no longer gives): its module loaded */\n async fallBack(): Promise<void> {\n if (this.#renderer === 'webgl2') return;\n\n const bindings = await loadEngine('webgl2', engineUrl('webgl2', this.options));\n\n this.engineClass = bindings.Engine;\n this.#renderer = 'webgl2';\n }\n\n /** A new engine drawing on `canvas` (its device asked for), with the settings and the decoding workers */\n async create(canvas: HTMLCanvasElement, redraw: () => void, settings: Settings): Promise<Engine> {\n const engine = await this.engineClass.create(canvas, redraw, this.options.antialias);\n\n applySettings(engine, settings);\n this.loader ??= startTileLoader(this.options, engine);\n if (this.loader) engine.setTileLoader(this.loader);\n\n return engine;\n }\n\n /** Height of the geoid above the ellipsoid at a position, in metres */\n geoidHeight(lon: number, lat: number): number {\n return this.engineClass.geoidHeight(lon, lat);\n }\n\n /** The matrix of a custom layer's model at a position */\n customMatrix(lon: number, lat: number, altitude: number): Float32Array | undefined {\n return this.engineClass.customMatrix(lon, lat, altitude);\n }\n\n /** Stops the decoding workers */\n destroy(): void {\n this.loader?.destroy();\n }\n}\n"]}
|
package/dist/map/events.js
CHANGED
package/dist/map/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/map/events.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAG9E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,iDAAiD;AACjD,MAAM,OAAO,YAAY;IACN,SAAS,GAAc;QACtC,SAAS,EAAE,IAAI,GAAG,EAAE;QACpB,IAAI,EAAE,IAAI,GAAG,EAAE;QACf,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,YAAY,EAAE,IAAI,GAAG,EAAE;QACvB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,IAAI,EAAE,IAAI,GAAG,EAAE;QACf,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,UAAU,EAAE,IAAI,GAAG,EAAE;KACtB,CAAC;IAEF,qEAAqE;IACrE,EAAE,CAA4B,IAAO,EAAE,QAAuC;QAC5E,MAAM,SAAS,GAAuC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAE3E,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAExB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,kGAAkG;IAClG,IAAI,CAA4B,IAAO,EAAE,KAAmB;QAC1D,MAAM,SAAS,GAAuC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAE3E,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;YAC7B,IAAI,CAAC;gBACH,QAAQ,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kCAAkC;IAClC,GAAG,CAAC,IAAqB;QACvB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,6BAA6B;IAC7B,KAAK;QACH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;YAClD,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["/** The listeners of the map's events: added, called, cleared with the map. */\n\nimport type { MapEvents } from '../types.ts';\nimport { report } from './checks.ts';\n\ntype Listeners = { [K in keyof MapEvents]: Set<(event: MapEvents[K]) => void> };\n\n/** The listeners of the map's events, by type */\nexport class MapListeners {\n private readonly listeners: Listeners = {\n movestart: new Set(),\n move: new Set(),\n moveend: new Set(),\n resize: new Set(),\n hover: new Set(),\n hoverfeature: new Set(),\n click: new Set(),\n render: new Set(),\n quality: new Set(),\n idle: new Set(),\n leave: new Set(),\n clipvolume: new Set(),\n };\n\n /** Listens to an event; returns the function that stops listening */\n on<K extends keyof MapEvents>(type: K, listener: (event: MapEvents[K]) => void): () => void {\n const listeners: Set<(event: MapEvents[K]) => void> = this.listeners[type];\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n }\n\n /** Calls the listeners; one that throws is reported and does not stop the others nor the frame */\n emit<K extends keyof MapEvents>(type: K, event: MapEvents[K]): void {\n const listeners: Set<(event: MapEvents[K]) => void> = this.listeners[type];\n\n listeners.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n report(error);\n }\n });\n }\n\n /** Something listens to `type` */\n has(type: keyof MapEvents): boolean {\n return this.listeners[type].size > 0;\n }\n\n /** Forgets every listener */\n clear(): void {\n Object.values(this.listeners).forEach((listeners) => {\n listeners.clear();\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/map/events.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAG9E,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,iDAAiD;AACjD,MAAM,OAAO,YAAY;IACN,SAAS,GAAc;QACtC,SAAS,EAAE,IAAI,GAAG,EAAE;QACpB,IAAI,EAAE,IAAI,GAAG,EAAE;QACf,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,YAAY,EAAE,IAAI,GAAG,EAAE;QACvB,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,MAAM,EAAE,IAAI,GAAG,EAAE;QACjB,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,OAAO,EAAE,IAAI,GAAG,EAAE;QAClB,IAAI,EAAE,IAAI,GAAG,EAAE;QACf,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,UAAU,EAAE,IAAI,GAAG,EAAE;KACtB,CAAC;IAEF,qEAAqE;IACrE,EAAE,CAA4B,IAAO,EAAE,QAAuC;QAC5E,MAAM,SAAS,GAAuC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAE3E,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAExB,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED,kGAAkG;IAClG,IAAI,CAA4B,IAAO,EAAE,KAAmB;QAC1D,MAAM,SAAS,GAAuC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAE3E,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;YAC7B,IAAI,CAAC;gBACH,QAAQ,CAAC,KAAK,CAAC,CAAC;YAClB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kCAAkC;IAClC,GAAG,CAAC,IAAqB;QACvB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;IACvC,CAAC;IAED,6BAA6B;IAC7B,KAAK;QACH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,EAAE;YAClD,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["/** The listeners of the map's events: added, called, cleared with the map. */\n\nimport type { MapEvents } from '../types.ts';\nimport { report } from './checks.ts';\n\ntype Listeners = { [K in keyof MapEvents]: Set<(event: MapEvents[K]) => void> };\n\n/** The listeners of the map's events, by type */\nexport class MapListeners {\n private readonly listeners: Listeners = {\n movestart: new Set(),\n move: new Set(),\n moveend: new Set(),\n resize: new Set(),\n hover: new Set(),\n hoverfeature: new Set(),\n click: new Set(),\n render: new Set(),\n quality: new Set(),\n gpulost: new Set(),\n idle: new Set(),\n leave: new Set(),\n clipvolume: new Set(),\n };\n\n /** Listens to an event; returns the function that stops listening */\n on<K extends keyof MapEvents>(type: K, listener: (event: MapEvents[K]) => void): () => void {\n const listeners: Set<(event: MapEvents[K]) => void> = this.listeners[type];\n\n listeners.add(listener);\n\n return () => listeners.delete(listener);\n }\n\n /** Calls the listeners; one that throws is reported and does not stop the others nor the frame */\n emit<K extends keyof MapEvents>(type: K, event: MapEvents[K]): void {\n const listeners: Set<(event: MapEvents[K]) => void> = this.listeners[type];\n\n listeners.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n report(error);\n }\n });\n }\n\n /** Something listens to `type` */\n has(type: keyof MapEvents): boolean {\n return this.listeners[type].size > 0;\n }\n\n /** Forgets every listener */\n clear(): void {\n Object.values(this.listeners).forEach((listeners) => {\n listeners.clear();\n });\n }\n}\n"]}
|
package/dist/map.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ import { Tiles3dLayer } from './layers/tiles3d.ts';
|
|
|
26
26
|
import { type TreeOptions } from './layers/trees.ts';
|
|
27
27
|
import { type HoverPicking } from './map/hover-pick.ts';
|
|
28
28
|
import { type LayerSpec } from './map/layer-spec.ts';
|
|
29
|
-
import type { AnimationOptions, AtmosphereOptions, Basemap, ClipVolume, FeatureHit, FirstPersonView, FlyToOptions, GeoMapOptions, LoadingMode, LonLat, MapEvents, MapGpuTimings, MapMemory, NetworkOptions, PickOptions, Point, Projection, Quality, RasterOptions, SunOptions, SwipeOptions, TerrainModel, TerrainOptions, Tiles3dOptions, ViewshedOptions } from './types.ts';
|
|
29
|
+
import type { AnimationOptions, AtmosphereOptions, Basemap, ClipVolume, FeatureHit, FirstPersonView, FitBoundsOptions, FitBox, FlyToOptions, GeoMapOptions, LoadingMode, LonLat, MapEvents, MapGpuTimings, MapMemory, NetworkOptions, PickOptions, Point, Projection, Quality, RasterOptions, SunOptions, SwipeOptions, TerrainModel, TerrainOptions, Tiles3dOptions, ViewshedOptions } from './types.ts';
|
|
30
30
|
import { type Control, type ControlPosition } from './ui/controls.ts';
|
|
31
31
|
import type { Camera, PickHit, RasterLayerStats } from './wasm/isard_webgpu.js';
|
|
32
32
|
export type { LayerSpec } from './map/layer-spec.ts';
|
|
@@ -85,15 +85,25 @@ export declare class GeoMap {
|
|
|
85
85
|
private get layers();
|
|
86
86
|
/** Layers new layers go under */
|
|
87
87
|
private get onTop();
|
|
88
|
+
/** What the map draws through: `'webgpu'`, or `'webgl2'` (the fallback of a browser without WebGPU, or of a device
|
|
89
|
+
* WebGPU kept losing) */
|
|
90
|
+
get renderer(): 'webgpu' | 'webgl2';
|
|
88
91
|
/** The GPU is lost: nothing drawn, the engine dropped (`dropLostEngine`) */
|
|
89
92
|
private gpuLost;
|
|
90
93
|
/**
|
|
91
94
|
* Follows the loss of `engine`'s WebGPU device (a phone taking its memory back, a driver reset, the GPU process
|
|
92
95
|
* gone): while it is the map's, the map drops it and makes a new one at once, WebGPU having no event for the GPU
|
|
93
|
-
* given back. The device of an engine the map freed itself
|
|
94
|
-
* any more, left be
|
|
96
|
+
* given back, lighter so as not to lose it again (`lighten`). The device of an engine the map freed itself
|
|
97
|
+
* (replaced, the map destroyed) is lost too: not the map's any more, left be
|
|
95
98
|
*/
|
|
96
99
|
private watchDevice;
|
|
100
|
+
/**
|
|
101
|
+
* After a device lost, the next engine lighter, the same scene then holding less: at the first loss the low quality
|
|
102
|
+
* (one pixel a CSS pixel, no sun's shadows, one worker, fewer tiles far away) and half the GPU memory budget; at the
|
|
103
|
+
* next one, the WebGL2 fallback (a phone whose WebGPU keeps losing its device: Safari's GPU process taking its
|
|
104
|
+
* memory back) and half the budget again. What it did: `'lighter'` or `'webgl2'`
|
|
105
|
+
*/
|
|
106
|
+
private lighten;
|
|
97
107
|
/**
|
|
98
108
|
* The context is lost: its engine freed at once, the map's calls going to one that does nothing until `restore`
|
|
99
109
|
* builds the next. The old engine's GPU objects went with the context: deleted now, it is silent (on the context
|
|
@@ -148,6 +158,16 @@ export declare class GeoMap {
|
|
|
148
158
|
* `flyTo`): long moves stay readable. Pitch and bearing follow the progress.
|
|
149
159
|
*/
|
|
150
160
|
flyTo(camera: Partial<Camera>, options?: FlyToOptions): void;
|
|
161
|
+
/**
|
|
162
|
+
* Moves the camera to frame a box: a ground box (`[west, south, east, north]`), or a box in space (a building, a
|
|
163
|
+
* pipe underground: `{ bounds, bottom, top }`, altitudes in metres), all its corners within the canvas less the
|
|
164
|
+
* padding, at the pitch and bearing given (default the current ones); an ease, a flight with `fly`, a jump with
|
|
165
|
+
* `duration: 0`
|
|
166
|
+
*/
|
|
167
|
+
fitBounds(box: FitBox | FitBox['bounds'], options?: FitBoundsOptions): void;
|
|
168
|
+
/** Height of the RAF20 geoid above the ellipsoid at a position (metres; 0 away from mainland France): what turns an
|
|
169
|
+
* altitude (NGF-IGN69: the BD TOPO's, the RGE ALTI's) into a height above the ellipsoid (`fitBounds`, `refine`) */
|
|
170
|
+
geoidHeight([lon, lat]: LonLat): number;
|
|
151
171
|
/** Longitudes and latitudes the view covers on the ground: `[west, south, east, north]` */
|
|
152
172
|
getBounds(): [west: number, south: number, east: number, north: number];
|
|
153
173
|
/** Lowest zoom the camera accepts (the widest view) */
|
package/dist/map.js
CHANGED
|
@@ -61,6 +61,8 @@ const BODY_START = { center: [0, 0], zoom: 2, pitch: 0, bearing: 0 };
|
|
|
61
61
|
const FIRST_PERSON_PITCH = [1, 179];
|
|
62
62
|
/** The eye's field of view at street level (degrees): from a telephoto to a wide angle, the projection still sane */
|
|
63
63
|
const FIRST_PERSON_FOV = [10, 140];
|
|
64
|
+
/** The least GPU memory budget a lost device leaves the map (bytes, `lighten`) */
|
|
65
|
+
const MIN_MEMORY = 64 * 2 ** 20;
|
|
64
66
|
/** A network's defaults: the values past which it is unreached (half an hour of travel, in seconds), its halo's
|
|
65
67
|
* opacity at the middle of a line (a glow, not a second line) */
|
|
66
68
|
const NETWORK_MAX = 1800;
|
|
@@ -141,7 +143,7 @@ export class GeoMap {
|
|
|
141
143
|
// The engine on wgpu (#146): WebGPU, else wgpu's WebGL2 fallback
|
|
142
144
|
const kind = await rendererKind(options.renderer);
|
|
143
145
|
const bindings = await loadEngine(kind, engineUrl(kind, options));
|
|
144
|
-
const map = new GeoMap(container, options, bindings.Engine);
|
|
146
|
+
const map = new GeoMap(container, options, bindings.Engine, kind);
|
|
145
147
|
// Its device asked for: the map started on a placeholder meanwhile, its layers created on the engine once it is
|
|
146
148
|
// there (as after a context loss)
|
|
147
149
|
map.adopt(await map.engines.create(map.canvas, () => map.requestRender(), map.settings));
|
|
@@ -152,8 +154,8 @@ export class GeoMap {
|
|
|
152
154
|
}
|
|
153
155
|
return map;
|
|
154
156
|
}
|
|
155
|
-
constructor(container, options, engineClass) {
|
|
156
|
-
this.engines = new MapEngines(engineClass, options);
|
|
157
|
+
constructor(container, options, engineClass, renderer) {
|
|
158
|
+
this.engines = new MapEngines(engineClass, renderer, options);
|
|
157
159
|
const workerUrl = options.basemapWorkerUrl ?? defaultWorkerUrl(options.assetsUrl);
|
|
158
160
|
this.tessUrl = tessUrl(options);
|
|
159
161
|
this.gridUrl = gridUrl(options);
|
|
@@ -238,6 +240,13 @@ export class GeoMap {
|
|
|
238
240
|
get onTop() {
|
|
239
241
|
return this.stack.onTop;
|
|
240
242
|
}
|
|
243
|
+
/** WebGPU devices lost so far: each one makes the next engine lighter (`lighten`) */
|
|
244
|
+
#losses = 0;
|
|
245
|
+
/** What the map draws through: `'webgpu'`, or `'webgl2'` (the fallback of a browser without WebGPU, or of a device
|
|
246
|
+
* WebGPU kept losing) */
|
|
247
|
+
get renderer() {
|
|
248
|
+
return this.engines.renderer;
|
|
249
|
+
}
|
|
241
250
|
/** The GPU is lost: nothing drawn, the engine dropped (`dropLostEngine`) */
|
|
242
251
|
gpuLost() {
|
|
243
252
|
this.lost = true;
|
|
@@ -247,17 +256,40 @@ export class GeoMap {
|
|
|
247
256
|
/**
|
|
248
257
|
* Follows the loss of `engine`'s WebGPU device (a phone taking its memory back, a driver reset, the GPU process
|
|
249
258
|
* gone): while it is the map's, the map drops it and makes a new one at once, WebGPU having no event for the GPU
|
|
250
|
-
* given back. The device of an engine the map freed itself
|
|
251
|
-
* any more, left be
|
|
259
|
+
* given back, lighter so as not to lose it again (`lighten`). The device of an engine the map freed itself
|
|
260
|
+
* (replaced, the map destroyed) is lost too: not the map's any more, left be
|
|
252
261
|
*/
|
|
253
262
|
watchDevice(engine) {
|
|
254
|
-
void engine
|
|
263
|
+
void engine
|
|
264
|
+
.gpuDevice()
|
|
265
|
+
?.lost.then(async (info) => {
|
|
255
266
|
if (this.gone || this.#engine !== engine)
|
|
256
267
|
return;
|
|
257
|
-
console.warn(`isard: the GPU device was lost (${info.reason}: ${info.message}), the map made again`);
|
|
258
268
|
this.gpuLost();
|
|
269
|
+
const recovery = await this.lighten();
|
|
270
|
+
console.warn(`isard: the GPU device was lost (${info.reason}: ${info.message}), the map made again (${recovery})`);
|
|
271
|
+
this.emit('gpulost', { reason: info.reason, message: info.message, losses: this.#losses, recovery });
|
|
259
272
|
this.restore();
|
|
260
|
-
})
|
|
273
|
+
})
|
|
274
|
+
// The fallback's module not loaded: told, as a failed restore is
|
|
275
|
+
.catch(report);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* After a device lost, the next engine lighter, the same scene then holding less: at the first loss the low quality
|
|
279
|
+
* (one pixel a CSS pixel, no sun's shadows, one worker, fewer tiles far away) and half the GPU memory budget; at the
|
|
280
|
+
* next one, the WebGL2 fallback (a phone whose WebGPU keeps losing its device: Safari's GPU process taking its
|
|
281
|
+
* memory back) and half the budget again. What it did: `'lighter'` or `'webgl2'`
|
|
282
|
+
*/
|
|
283
|
+
async lighten() {
|
|
284
|
+
this.#losses += 1;
|
|
285
|
+
this.settings.memory = Math.max(MIN_MEMORY, this.settings.memory / 2);
|
|
286
|
+
if (this.#losses === 1 || this.engines.renderer === 'webgl2') {
|
|
287
|
+
this.qualityWatch = undefined;
|
|
288
|
+
this.applyQuality('low');
|
|
289
|
+
return 'lighter';
|
|
290
|
+
}
|
|
291
|
+
await this.engines.fallBack();
|
|
292
|
+
return 'webgl2';
|
|
261
293
|
}
|
|
262
294
|
/**
|
|
263
295
|
* The context is lost: its engine freed at once, the map's calls going to one that does nothing until `restore`
|
|
@@ -278,8 +310,17 @@ export class GeoMap {
|
|
|
278
310
|
restore() {
|
|
279
311
|
if (this.gone)
|
|
280
312
|
return;
|
|
281
|
-
this.engines
|
|
282
|
-
|
|
313
|
+
const make = () => this.engines.create(this.canvas, () => this.requestRender(), this.settings);
|
|
314
|
+
make()
|
|
315
|
+
.catch(async (error) => {
|
|
316
|
+
// WebGPU giving no new device after a loss (an adapter refused): the WebGL2 fallback
|
|
317
|
+
if (this.engines.renderer === 'webgl2')
|
|
318
|
+
throw error;
|
|
319
|
+
console.warn(`isard: no new WebGPU device (${String(error)}), the map made again through WebGL2`);
|
|
320
|
+
await this.engines.fallBack();
|
|
321
|
+
this.emit('gpulost', { reason: 'unknown', message: String(error), losses: this.#losses, recovery: 'webgl2' });
|
|
322
|
+
return make();
|
|
323
|
+
})
|
|
283
324
|
.then((engine) => this.adopt(engine))
|
|
284
325
|
.catch(report);
|
|
285
326
|
}
|
|
@@ -480,6 +521,35 @@ export class GeoMap {
|
|
|
480
521
|
this.animate(flyTo(() => this.engine, from, to, viewport, options));
|
|
481
522
|
this.engine.preload(to.center[0], to.center[1], to.zoom, to.pitch, to.bearing);
|
|
482
523
|
}
|
|
524
|
+
/**
|
|
525
|
+
* Moves the camera to frame a box: a ground box (`[west, south, east, north]`), or a box in space (a building, a
|
|
526
|
+
* pipe underground: `{ bounds, bottom, top }`, altitudes in metres), all its corners within the canvas less the
|
|
527
|
+
* padding, at the pitch and bearing given (default the current ones); an ease, a flight with `fly`, a jump with
|
|
528
|
+
* `duration: 0`
|
|
529
|
+
*/
|
|
530
|
+
fitBounds(box, options = {}) {
|
|
531
|
+
const { bounds, bottom = 0, top = bottom } = Array.isArray(box) ? { bounds: box } : box;
|
|
532
|
+
const current = this.getCamera();
|
|
533
|
+
const room = options.padding ?? 40;
|
|
534
|
+
const padding = typeof room === 'number'
|
|
535
|
+
? [room, room, room, room]
|
|
536
|
+
: [room.top ?? 0, room.right ?? 0, room.bottom ?? 0, room.left ?? 0];
|
|
537
|
+
const camera = this.engine.fitCamera(Float64Array.from(bounds), bottom, top, Float64Array.from(padding), options.pitch ?? current.pitch, options.bearing ?? current.bearing);
|
|
538
|
+
if (!camera)
|
|
539
|
+
throw new Error('isard: fitBounds needs a box, west not past east nor south past north');
|
|
540
|
+
const to = { ...camera, zoom: Math.min(camera.zoom, options.maxZoom ?? Number.POSITIVE_INFINITY) };
|
|
541
|
+
if (options.duration === 0)
|
|
542
|
+
this.setCamera(to);
|
|
543
|
+
else if (options.fly)
|
|
544
|
+
this.flyTo(to, options);
|
|
545
|
+
else
|
|
546
|
+
this.easeTo(to, { duration: 600, ...options });
|
|
547
|
+
}
|
|
548
|
+
/** Height of the RAF20 geoid above the ellipsoid at a position (metres; 0 away from mainland France): what turns an
|
|
549
|
+
* altitude (NGF-IGN69: the BD TOPO's, the RGE ALTI's) into a height above the ellipsoid (`fitBounds`, `refine`) */
|
|
550
|
+
geoidHeight([lon, lat]) {
|
|
551
|
+
return this.engines.geoidHeight(lon, lat);
|
|
552
|
+
}
|
|
483
553
|
/** Longitudes and latitudes the view covers on the ground: `[west, south, east, north]` */
|
|
484
554
|
getBounds() {
|
|
485
555
|
const [west = -180, south = -85, east = 180, north = 85] = this.engine.bounds();
|