isard 0.6.0 → 0.7.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 +62 -0
- package/dist/decoder.worker.js +3 -3
- package/dist/decoder.worker.js.map +3 -3
- package/dist/geoplateforme.d.ts +4 -3
- package/dist/geoplateforme.js +42 -19
- package/dist/geoplateforme.js.map +1 -1
- package/dist/isard_bg.wasm +0 -0
- package/dist/isard_core_bg.wasm +0 -0
- package/dist/map.d.ts +17 -4
- package/dist/map.js +33 -9
- package/dist/map.js.map +1 -1
- package/dist/overlay.d.ts +15 -0
- package/dist/overlay.js +66 -7
- package/dist/overlay.js.map +1 -1
- package/dist/style.js +2 -0
- package/dist/style.js.map +1 -1
- package/dist/types.d.ts +7 -2
- package/dist/types.js.map +1 -1
- package/dist/vectortiles.d.ts +6 -2
- package/dist/vectortiles.js +80 -32
- package/dist/vectortiles.js.map +1 -1
- package/dist/wasm/isard.d.ts +30 -8
- package/dist/wasm/isard.js +54 -16
- package/dist/wasm/isard_core.d.ts +30 -8
- package/dist/wasm/isard_core.js +58 -16
- package/package.json +1 -1
package/dist/geoplateforme.d.ts
CHANGED
|
@@ -40,9 +40,10 @@ export declare function geoplateformeWms(layers: string, options?: {
|
|
|
40
40
|
/**
|
|
41
41
|
* Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and
|
|
42
42
|
* latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features
|
|
43
|
-
* (default
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* (default 50 000), asked by pages of 5000: the first one tells how many there are, the others are asked together.
|
|
44
|
+
* The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName` (`'EPSG:2154'`), the
|
|
45
|
+
* features come in that CRS (the box stays in degrees), the collection naming it in its `crs` member: the feature
|
|
46
|
+
* layers reproject it by themselves
|
|
46
47
|
*/
|
|
47
48
|
export declare function geoplateformeWfs<P = Properties>(typeName: string, [west, south, east, north]: [number, number, number, number], options?: {
|
|
48
49
|
count?: number;
|
package/dist/geoplateforme.js
CHANGED
|
@@ -63,29 +63,52 @@ export function geoplateformeWms(layers, options = {}) {
|
|
|
63
63
|
`&STYLES=${encodeURIComponent(styles)}&FORMAT=${format}`,
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
+
/** Features the Géoplateforme's WFS returns per request at most */
|
|
67
|
+
const WFS_PAGE = 5000;
|
|
66
68
|
/**
|
|
67
69
|
* Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and
|
|
68
70
|
* latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features
|
|
69
|
-
* (default
|
|
70
|
-
*
|
|
71
|
-
*
|
|
71
|
+
* (default 50 000), asked by pages of 5000: the first one tells how many there are, the others are asked together.
|
|
72
|
+
* The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName` (`'EPSG:2154'`), the
|
|
73
|
+
* features come in that CRS (the box stays in degrees), the collection naming it in its `crs` member: the feature
|
|
74
|
+
* layers reproject it by themselves
|
|
72
75
|
*/
|
|
73
76
|
export async function geoplateformeWfs(typeName, [west, south, east, north], options = {}) {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
77
|
+
const limit = Math.max(1, options.count ?? 50_000);
|
|
78
|
+
const page = async (start, count) => {
|
|
79
|
+
const url = new URL('https://data.geopf.fr/wfs/ows');
|
|
80
|
+
url.search = new URLSearchParams({
|
|
81
|
+
SERVICE: 'WFS',
|
|
82
|
+
VERSION: '2.0.0',
|
|
83
|
+
REQUEST: 'GetFeature',
|
|
84
|
+
TYPENAMES: typeName,
|
|
85
|
+
OUTPUTFORMAT: 'application/json',
|
|
86
|
+
SRSNAME: options.srsName ?? 'EPSG:4326',
|
|
87
|
+
// WFS 2.0 in EPSG:4326: latitude first
|
|
88
|
+
BBOX: `${south},${west},${north},${east},urn:ogc:def:crs:EPSG::4326`,
|
|
89
|
+
COUNT: String(count),
|
|
90
|
+
// The first page as a single request always was
|
|
91
|
+
...(start > 0 ? { STARTINDEX: String(start) } : {}),
|
|
92
|
+
}).toString();
|
|
93
|
+
const response = await fetch(url, options.signal ? { signal: options.signal } : {});
|
|
94
|
+
if (!response.ok)
|
|
95
|
+
throw new Error(`isard: ${typeName}: ${response.status}`);
|
|
96
|
+
return response.json();
|
|
97
|
+
};
|
|
98
|
+
const first = await page(0, Math.min(WFS_PAGE, limit));
|
|
99
|
+
const matched = Number(first.numberMatched);
|
|
100
|
+
const total = Math.min(Number.isFinite(matched) ? matched : 0, limit);
|
|
101
|
+
if (first.features.length < WFS_PAGE || total <= first.features.length)
|
|
102
|
+
return first;
|
|
103
|
+
const starts = [];
|
|
104
|
+
for (let start = first.features.length; start < total; start += WFS_PAGE)
|
|
105
|
+
starts.push(start);
|
|
106
|
+
const rest = await Promise.all(starts.map((start) => page(start, Math.min(WFS_PAGE, total - start))));
|
|
107
|
+
// Pages may overlap where the server's order shifts: each feature once, by its id
|
|
108
|
+
const seen = new Set();
|
|
109
|
+
const features = [first, ...rest]
|
|
110
|
+
.flatMap((r) => r.features)
|
|
111
|
+
.filter((f) => f.id === undefined || (!seen.has(f.id) && seen.add(f.id) !== undefined));
|
|
112
|
+
return { ...first, features };
|
|
90
113
|
}
|
|
91
114
|
//# sourceMappingURL=geoplateforme.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geoplateforme.js","sourceRoot":"","sources":["../src/geoplateforme.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Géoplateforme's data (IGN, France; open, no key): its WMTS and WMS rasters as raster layers, its WFS features as\n * GeoJSON. Its basemaps, hillshade, terrain model and vector styles are named options of the map (`'ign-plan'`,\n * `hillshade`, `terrain: 'ign'`, `PLAN_STYLES`); the rasters credit the IGN by themselves.\n */\nimport type { FeatureCollection, Properties } from './features.ts';\nimport type { TileGrid, TileMatrix } from './grid.ts';\nimport type { RasterOptions } from './types.ts';\n\n/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */\nexport const IGN_ATTRIBUTION =\n '<a href=\"https://www.ign.fr/\">© IGN</a> – <a href=\"https://geoservices.ign.fr/\">Géoplateforme</a>';\n\n/** France (metropolitan, Corsica included) in longitudes and latitudes, where the Géoplateforme's Lambert-93 layers\n * lie */\nconst FRANCE: [number, number, number, number] = [-5.5, 41, 10, 51.5];\n\n/**\n * The Géoplateforme's Lambert-93 tile matrix sets of 5 and 10 cm (`2154_10cm_6_20`, `2154_5cm_6_22`…: one pyramid,\n * 209 715.2 m per pixel at level 0, halved at each level, from the corner (0, 12 000 000)), levels `min` to `max`, over\n * France\n */\nexport function lambert93Grid(name: string, min: number, max: number): TileGrid {\n const matrices: TileMatrix[] = [];\n for (let level = min; level <= max; level += 1) {\n matrices.push({ id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] });\n }\n return { crs: 'EPSG:2154', matrices, bounds: FRANCE, name };\n}\n\n/**\n * A layer of the Géoplateforme's WMTS as raster options for `addRaster`, crediting the IGN:\n * `geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' })`. The layer names are those of its\n * capabilities (https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetCapabilities). In its Web Mercator grid (`PM`) by\n * default; a Lambert-93 layer in its matrix set (`matrixSet: '2154_10cm_6_20'`, a set of 5 or 10 cm, read from the\n * capabilities) or another `grid` (from `wmtsGrid`, its set named) is reprojected by the map\n */\nexport function geoplateformeWmts(\n layer: string,\n options: { format?: string; style?: string; matrixSet?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', style = 'normal', matrixSet, ...raster } = options;\n const set = (typeof raster.grid === 'object' ? raster.grid.name : undefined) ?? matrixSet ?? 'PM';\n const lambert = /^2154_(?:5|10)cm_(\\d+)_(\\d+)$/.exec(set);\n if (lambert && raster.grid === undefined) raster.grid = lambert93Grid(set, Number(lambert[1]), Number(lambert[2]));\n else if (set !== 'PM' && raster.grid === undefined) {\n throw new Error(`isard: the grid of the matrix set ${set}: wmtsGrid(capabilities, '${layer}', '${set}')`);\n }\n return {\n ...(raster.grid === undefined ? { maxZoom: 19 } : {}),\n attribution: IGN_ATTRIBUTION,\n ...raster,\n url:\n `https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&STYLE=${encodeURIComponent(style)}` +\n `&TILEMATRIXSET=${encodeURIComponent(set)}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}` +\n `&LAYER=${encodeURIComponent(layer)}&FORMAT=${format}`,\n };\n}\n\n/**\n * Layers of the Géoplateforme's WMS (raster, `wms-r`) as raster options for `addRaster`, crediting the IGN: 256 px\n * images of each tile, transparent where empty. `geoplateformeWms('CADASTRALPARCELS.PARCELLAIRE_EXPRESS')`. Asked for\n * in EPSG:3857, or in `crs` (`'EPSG:2154'`: the box of each tile in Lambert-93, at the tile's `size`, reprojected by\n * the map; `'EPSG:4326'` is asked for as CRS:84, longitude first)\n */\nexport function geoplateformeWms(\n layers: string,\n options: { format?: string; styles?: string; crs?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', styles = '', crs = 'EPSG:3857', ...raster } = options;\n const projected = crs !== 'EPSG:3857';\n // WMS 1.3 puts the latitude first in EPSG:4326; {bbox} is x, y\n const asked = crs === 'EPSG:4326' ? 'CRS:84' : crs;\n return {\n maxZoom: 20,\n attribution: IGN_ATTRIBUTION,\n ...(projected ? { grid: { crs, ...(crs === 'EPSG:2154' ? { bounds: FRANCE } : {}) } } : {}),\n ...raster,\n url:\n `https://data.geopf.fr/wms-r/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=${asked}&BBOX={bbox}` +\n // Reprojected, the image of each tile at its size\n `&${projected ? 'WIDTH={width}&HEIGHT={height}' : 'WIDTH=256&HEIGHT=256'}&TRANSPARENT=TRUE` +\n `&LAYERS=${encodeURIComponent(layers)}` +\n `&STYLES=${encodeURIComponent(styles)}&FORMAT=${format}`,\n };\n}\n\n/**\n * Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and\n * latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features\n * (default 5000). The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName`\n * (`'EPSG:2154'`), the features come in that CRS (the box stays in degrees), the collection naming it in its `crs`\n * member: the feature layers reproject it by themselves\n */\nexport async function geoplateformeWfs<P = Properties>(\n typeName: string,\n [west, south, east, north]: [number, number, number, number],\n options: { count?: number; signal?: AbortSignal; srsName?: string } = {},\n): Promise<FeatureCollection<P>> {\n const url = new URL('https://data.geopf.fr/wfs/ows');\n url.search = new URLSearchParams({\n SERVICE: 'WFS',\n VERSION: '2.0.0',\n REQUEST: 'GetFeature',\n TYPENAMES: typeName,\n OUTPUTFORMAT: 'application/json',\n SRSNAME: options.srsName ?? 'EPSG:4326',\n // WFS 2.0 in EPSG:4326: latitude first\n BBOX: `${south},${west},${north},${east},urn:ogc:def:crs:EPSG::4326`,\n COUNT: String(options.count ?? 5000),\n }).toString();\n const response = await fetch(url, options.signal ? { signal: options.signal } : {});\n if (!response.ok) throw new Error(`isard: ${typeName}: ${response.status}`);\n return response.json() as Promise<FeatureCollection<P>>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"geoplateforme.js","sourceRoot":"","sources":["../src/geoplateforme.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The Géoplateforme's data (IGN, France; open, no key): its WMTS and WMS rasters as raster layers, its WFS features as\n * GeoJSON. Its basemaps, hillshade, terrain model and vector styles are named options of the map (`'ign-plan'`,\n * `hillshade`, `terrain: 'ign'`, `PLAN_STYLES`); the rasters credit the IGN by themselves.\n */\nimport type { FeatureCollection, Properties } from './features.ts';\nimport type { TileGrid, TileMatrix } from './grid.ts';\nimport type { RasterOptions } from './types.ts';\n\n/** Credits of the Géoplateforme's data: its basemaps, hillshade, terrain model, rasters and features */\nexport const IGN_ATTRIBUTION =\n '<a href=\"https://www.ign.fr/\">© IGN</a> – <a href=\"https://geoservices.ign.fr/\">Géoplateforme</a>';\n\n/** France (metropolitan, Corsica included) in longitudes and latitudes, where the Géoplateforme's Lambert-93 layers\n * lie */\nconst FRANCE: [number, number, number, number] = [-5.5, 41, 10, 51.5];\n\n/**\n * The Géoplateforme's Lambert-93 tile matrix sets of 5 and 10 cm (`2154_10cm_6_20`, `2154_5cm_6_22`…: one pyramid,\n * 209 715.2 m per pixel at level 0, halved at each level, from the corner (0, 12 000 000)), levels `min` to `max`, over\n * France\n */\nexport function lambert93Grid(name: string, min: number, max: number): TileGrid {\n const matrices: TileMatrix[] = [];\n for (let level = min; level <= max; level += 1) {\n matrices.push({ id: level, resolution: 209715.2 / 2 ** level, origin: [0, 12000000] });\n }\n return { crs: 'EPSG:2154', matrices, bounds: FRANCE, name };\n}\n\n/**\n * A layer of the Géoplateforme's WMTS as raster options for `addRaster`, crediting the IGN:\n * `geoplateformeWmts('ORTHOIMAGERY.ORTHOPHOTOS', { format: 'image/jpeg' })`. The layer names are those of its\n * capabilities (https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetCapabilities). In its Web Mercator grid (`PM`) by\n * default; a Lambert-93 layer in its matrix set (`matrixSet: '2154_10cm_6_20'`, a set of 5 or 10 cm, read from the\n * capabilities) or another `grid` (from `wmtsGrid`, its set named) is reprojected by the map\n */\nexport function geoplateformeWmts(\n layer: string,\n options: { format?: string; style?: string; matrixSet?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', style = 'normal', matrixSet, ...raster } = options;\n const set = (typeof raster.grid === 'object' ? raster.grid.name : undefined) ?? matrixSet ?? 'PM';\n const lambert = /^2154_(?:5|10)cm_(\\d+)_(\\d+)$/.exec(set);\n if (lambert && raster.grid === undefined) raster.grid = lambert93Grid(set, Number(lambert[1]), Number(lambert[2]));\n else if (set !== 'PM' && raster.grid === undefined) {\n throw new Error(`isard: the grid of the matrix set ${set}: wmtsGrid(capabilities, '${layer}', '${set}')`);\n }\n return {\n ...(raster.grid === undefined ? { maxZoom: 19 } : {}),\n attribution: IGN_ATTRIBUTION,\n ...raster,\n url:\n `https://data.geopf.fr/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&STYLE=${encodeURIComponent(style)}` +\n `&TILEMATRIXSET=${encodeURIComponent(set)}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}` +\n `&LAYER=${encodeURIComponent(layer)}&FORMAT=${format}`,\n };\n}\n\n/**\n * Layers of the Géoplateforme's WMS (raster, `wms-r`) as raster options for `addRaster`, crediting the IGN: 256 px\n * images of each tile, transparent where empty. `geoplateformeWms('CADASTRALPARCELS.PARCELLAIRE_EXPRESS')`. Asked for\n * in EPSG:3857, or in `crs` (`'EPSG:2154'`: the box of each tile in Lambert-93, at the tile's `size`, reprojected by\n * the map; `'EPSG:4326'` is asked for as CRS:84, longitude first)\n */\nexport function geoplateformeWms(\n layers: string,\n options: { format?: string; styles?: string; crs?: string } & Omit<RasterOptions, 'url'> = {},\n): RasterOptions {\n const { format = 'image/png', styles = '', crs = 'EPSG:3857', ...raster } = options;\n const projected = crs !== 'EPSG:3857';\n // WMS 1.3 puts the latitude first in EPSG:4326; {bbox} is x, y\n const asked = crs === 'EPSG:4326' ? 'CRS:84' : crs;\n return {\n maxZoom: 20,\n attribution: IGN_ATTRIBUTION,\n ...(projected ? { grid: { crs, ...(crs === 'EPSG:2154' ? { bounds: FRANCE } : {}) } } : {}),\n ...raster,\n url:\n `https://data.geopf.fr/wms-r/wms?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=${asked}&BBOX={bbox}` +\n // Reprojected, the image of each tile at its size\n `&${projected ? 'WIDTH={width}&HEIGHT={height}' : 'WIDTH=256&HEIGHT=256'}&TRANSPARENT=TRUE` +\n `&LAYERS=${encodeURIComponent(layers)}` +\n `&STYLES=${encodeURIComponent(styles)}&FORMAT=${format}`,\n };\n}\n\n/** Features the Géoplateforme's WFS returns per request at most */\nconst WFS_PAGE = 5000;\n\n/**\n * Features of the Géoplateforme's WFS in a box (west, south, east, north, degrees), as GeoJSON in longitudes and\n * latitudes: `await geoplateformeWfs('BDTOPO_V3:batiment', [2.41, 48.84, 2.43, 48.85])`. At most `count` features\n * (default 50 000), asked by pages of 5000: the first one tells how many there are, the others are asked together.\n * The type names are those of its capabilities (BD TOPO, ADMIN EXPRESS…). With `srsName` (`'EPSG:2154'`), the\n * features come in that CRS (the box stays in degrees), the collection naming it in its `crs` member: the feature\n * layers reproject it by themselves\n */\nexport async function geoplateformeWfs<P = Properties>(\n typeName: string,\n [west, south, east, north]: [number, number, number, number],\n options: { count?: number; signal?: AbortSignal; srsName?: string } = {},\n): Promise<FeatureCollection<P>> {\n const limit = Math.max(1, options.count ?? 50_000);\n const page = async (start: number, count: number) => {\n const url = new URL('https://data.geopf.fr/wfs/ows');\n url.search = new URLSearchParams({\n SERVICE: 'WFS',\n VERSION: '2.0.0',\n REQUEST: 'GetFeature',\n TYPENAMES: typeName,\n OUTPUTFORMAT: 'application/json',\n SRSNAME: options.srsName ?? 'EPSG:4326',\n // WFS 2.0 in EPSG:4326: latitude first\n BBOX: `${south},${west},${north},${east},urn:ogc:def:crs:EPSG::4326`,\n COUNT: String(count),\n // The first page as a single request always was\n ...(start > 0 ? { STARTINDEX: String(start) } : {}),\n }).toString();\n const response = await fetch(url, options.signal ? { signal: options.signal } : {});\n if (!response.ok) throw new Error(`isard: ${typeName}: ${response.status}`);\n return response.json() as Promise<FeatureCollection<P> & { numberMatched?: number | string }>;\n };\n const first = await page(0, Math.min(WFS_PAGE, limit));\n const matched = Number(first.numberMatched);\n const total = Math.min(Number.isFinite(matched) ? matched : 0, limit);\n if (first.features.length < WFS_PAGE || total <= first.features.length) return first;\n const starts: number[] = [];\n for (let start = first.features.length; start < total; start += WFS_PAGE) starts.push(start);\n const rest = await Promise.all(starts.map((start) => page(start, Math.min(WFS_PAGE, total - start))));\n // Pages may overlap where the server's order shifts: each feature once, by its id\n const seen = new Set<unknown>();\n const features = [first, ...rest]\n .flatMap((r) => r.features)\n .filter((f) => f.id === undefined || (!seen.has(f.id) && seen.add(f.id) !== undefined));\n return { ...first, features };\n}\n"]}
|
package/dist/isard_bg.wasm
CHANGED
|
Binary file
|
package/dist/isard_core_bg.wasm
CHANGED
|
Binary file
|
package/dist/map.d.ts
CHANGED
|
@@ -138,8 +138,9 @@ export declare class GeoMap {
|
|
|
138
138
|
setSky(enabled: boolean): void;
|
|
139
139
|
/** Tints what can be seen from a point and what is hidden from it, within a range, all around or within a cone
|
|
140
140
|
* (`direction`): the relief, extrusions, 3D Tiles and models hide what lies behind them (only what the map has
|
|
141
|
-
* loaded for its view).
|
|
142
|
-
|
|
141
|
+
* loaded for its view). Several observers (16 at most): what any of them sees is seen, what is hidden from all those
|
|
142
|
+
* that reach it is hidden, in the colors and opacity of the first. Undefined or none removes it */
|
|
143
|
+
setViewshed(options: ViewshedOptions | readonly ViewshedOptions[] | undefined): void;
|
|
143
144
|
/** Relief under the basemap: true for the body's terrain model (on the Earth the worldwide Terrain Tiles, NASA's
|
|
144
145
|
* on the Moon and Mars), one of the Earth's models by name (`'ign'`), its options, or false; on another body, its
|
|
145
146
|
* options with a `url` */
|
|
@@ -170,10 +171,22 @@ export declare class GeoMap {
|
|
|
170
171
|
private requestHoverPick;
|
|
171
172
|
private readonly pollHoverPick;
|
|
172
173
|
private cancelHoverPick;
|
|
173
|
-
/** Screen point (CSS pixels) of a position
|
|
174
|
-
|
|
174
|
+
/** Screen point (CSS pixels) of a position on the ground (the relief), or `height` metres above it, undefined
|
|
175
|
+
* behind the camera */
|
|
176
|
+
project(lonLat: LonLat, height?: number): Point | undefined;
|
|
175
177
|
/** Position under a screen point (CSS pixels), undefined above the horizon */
|
|
176
178
|
unproject(point: Point): LonLat | undefined;
|
|
179
|
+
/** What is drawn under a screen point (CSS pixels), on the relief or standing on it (a roof, a wall, a mesh): its
|
|
180
|
+
* position and its height above the relief, in metres; undefined where nothing was drawn. The last frame's scene is
|
|
181
|
+
* drawn again and read back, waiting for the GPU (a stall): for clicks and drags */
|
|
182
|
+
pickSurface(point: Point): {
|
|
183
|
+
lonLat: LonLat;
|
|
184
|
+
height: number;
|
|
185
|
+
} | undefined;
|
|
186
|
+
/** The height above the relief, in metres, of the top of what stands at a position: a roof, a mesh, 0 on the bare
|
|
187
|
+
* ground; undefined where nothing of the last frame is there. The scene is drawn from above into a single pixel and
|
|
188
|
+
* read back: cheap, but it waits for the GPU */
|
|
189
|
+
surfaceAt(lonLat: LonLat): number | undefined;
|
|
177
190
|
/** Adds a control in a corner of the map; controls stack from the corner inward */
|
|
178
191
|
addControl(control: Control, position?: ControlPosition): this;
|
|
179
192
|
removeControl(control: Control): this;
|
package/dist/map.js
CHANGED
|
@@ -513,16 +513,26 @@ export class GeoMap {
|
|
|
513
513
|
}
|
|
514
514
|
/** Tints what can be seen from a point and what is hidden from it, within a range, all around or within a cone
|
|
515
515
|
* (`direction`): the relief, extrusions, 3D Tiles and models hide what lies behind them (only what the map has
|
|
516
|
-
* loaded for its view).
|
|
516
|
+
* loaded for its view). Several observers (16 at most): what any of them sees is seen, what is hidden from all those
|
|
517
|
+
* that reach it is hidden, in the colors and opacity of the first. Undefined or none removes it */
|
|
517
518
|
setViewshed(options) {
|
|
518
|
-
|
|
519
|
+
let observers = [];
|
|
520
|
+
if (options)
|
|
521
|
+
observers = 'position' in options ? [options] : options;
|
|
522
|
+
const [first] = observers;
|
|
523
|
+
if (!first) {
|
|
519
524
|
this.engine.clearViewshed();
|
|
520
525
|
return;
|
|
521
526
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
527
|
+
this.engine.setViewshed(new Float64Array(observers.flatMap((o) => [
|
|
528
|
+
o.position[0],
|
|
529
|
+
o.position[1],
|
|
530
|
+
o.height ?? 1.7,
|
|
531
|
+
o.range ?? 1000,
|
|
532
|
+
...(o.direction === undefined
|
|
533
|
+
? [Number.NaN, 0, 0, 0]
|
|
534
|
+
: [o.direction, o.tilt ?? 0, o.fov ?? 60, o.verticalFov ?? 40]),
|
|
535
|
+
])), new Float32Array(rgb(first.visibleColor ?? '#2f9e44')), new Float32Array(rgb(first.hiddenColor ?? '#e03131')), first.opacity ?? 0.7, new Float32Array(first.coneColor ? rgb(first.coneColor) : []));
|
|
526
536
|
this.requestRender();
|
|
527
537
|
}
|
|
528
538
|
/** Relief under the basemap: true for the body's terrain model (on the Earth the worldwide Terrain Tiles, NASA's
|
|
@@ -624,14 +634,28 @@ export class GeoMap {
|
|
|
624
634
|
cancelAnimationFrame(this.hoverPoll);
|
|
625
635
|
this.hoverPoll = 0;
|
|
626
636
|
}
|
|
627
|
-
/** Screen point (CSS pixels) of a position
|
|
628
|
-
|
|
629
|
-
|
|
637
|
+
/** Screen point (CSS pixels) of a position on the ground (the relief), or `height` metres above it, undefined
|
|
638
|
+
* behind the camera */
|
|
639
|
+
project(lonLat, height = 0) {
|
|
640
|
+
return this.engine.project(lonLat[0], lonLat[1], height);
|
|
630
641
|
}
|
|
631
642
|
/** Position under a screen point (CSS pixels), undefined above the horizon */
|
|
632
643
|
unproject(point) {
|
|
633
644
|
return this.engine.ground(point[0], point[1]);
|
|
634
645
|
}
|
|
646
|
+
/** What is drawn under a screen point (CSS pixels), on the relief or standing on it (a roof, a wall, a mesh): its
|
|
647
|
+
* position and its height above the relief, in metres; undefined where nothing was drawn. The last frame's scene is
|
|
648
|
+
* drawn again and read back, waiting for the GPU (a stall): for clicks and drags */
|
|
649
|
+
pickSurface(point) {
|
|
650
|
+
const hit = this.engine.surface(point[0], point[1]);
|
|
651
|
+
return hit && { lonLat: [hit[0], hit[1]], height: hit[2] };
|
|
652
|
+
}
|
|
653
|
+
/** The height above the relief, in metres, of the top of what stands at a position: a roof, a mesh, 0 on the bare
|
|
654
|
+
* ground; undefined where nothing of the last frame is there. The scene is drawn from above into a single pixel and
|
|
655
|
+
* read back: cheap, but it waits for the GPU */
|
|
656
|
+
surfaceAt(lonLat) {
|
|
657
|
+
return this.engine.surfaceAt(lonLat[0], lonLat[1]);
|
|
658
|
+
}
|
|
635
659
|
// ── Overlays and controls ──
|
|
636
660
|
/** Adds a control in a corner of the map; controls stack from the corner inward */
|
|
637
661
|
addControl(control, position = 'top-right') {
|