isard 1.5.0 → 1.6.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 +165 -1
- package/README.md +3 -2
- package/dist/basemap/furniture.d.ts +8 -0
- package/dist/basemap/furniture.js +26 -0
- package/dist/basemap/furniture.js.map +1 -0
- package/dist/basemap/trees.d.ts +35 -8
- package/dist/basemap/trees.js +105 -52
- package/dist/basemap/trees.js.map +1 -1
- package/dist/basemap/vectorstyle.d.ts +9 -3
- package/dist/basemap/vectorstyle.js +5 -6
- package/dist/basemap/vectorstyle.js.map +1 -1
- package/dist/basemap/vectortiles/context.d.ts +3 -0
- package/dist/basemap/vectortiles/context.js.map +1 -1
- package/dist/basemap/vectortiles/extrusions.d.ts +4 -0
- package/dist/basemap/vectortiles/extrusions.js +17 -2
- package/dist/basemap/vectortiles/extrusions.js.map +1 -1
- package/dist/basemap/vectortiles/labels.d.ts +3 -0
- package/dist/basemap/vectortiles/labels.js +42 -17
- package/dist/basemap/vectortiles/labels.js.map +1 -1
- package/dist/basemap/vectortiles/lamps.d.ts +23 -0
- package/dist/basemap/vectortiles/lamps.js +90 -0
- package/dist/basemap/vectortiles/lamps.js.map +1 -0
- package/dist/basemap/vectortiles/requests.d.ts +4 -0
- package/dist/basemap/vectortiles/requests.js +15 -2
- package/dist/basemap/vectortiles/requests.js.map +1 -1
- package/dist/basemap/vectortiles/trees.d.ts +9 -0
- package/dist/basemap/vectortiles/trees.js +114 -29
- package/dist/basemap/vectortiles/trees.js.map +1 -1
- package/dist/basemap/vectortiles/vectors.d.ts +17 -0
- package/dist/basemap/vectortiles/vectors.js +72 -8
- package/dist/basemap/vectortiles/vectors.js.map +1 -1
- package/dist/basemap/vectortiles.d.ts +26 -6
- package/dist/basemap/vectortiles.js +43 -10
- package/dist/basemap/vectortiles.js.map +1 -1
- package/dist/basemap.worker.js +2 -2
- package/dist/basemap.worker.js.map +12 -10
- package/dist/bind/layers.js +1 -0
- package/dist/bind/layers.js.map +1 -1
- package/dist/data/collada.d.ts +19 -0
- package/dist/data/collada.js +319 -0
- package/dist/data/collada.js.map +1 -0
- package/dist/data/ifc.d.ts +100 -0
- package/dist/data/ifc.js +372 -0
- package/dist/data/ifc.js.map +1 -0
- package/dist/decoder.worker.js +5 -5
- package/dist/decoder.worker.js.map +3 -3
- package/dist/formats.d.ts +7 -2
- package/dist/formats.js +7 -2
- package/dist/formats.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/isard_bg.wasm +0 -0
- package/dist/isard_core_bg.wasm +0 -0
- package/dist/isard_grid_bg.wasm +0 -0
- package/dist/isard_tess_bg.wasm +0 -0
- package/dist/layers/extrusions.d.ts +10 -0
- package/dist/layers/extrusions.js +28 -2
- package/dist/layers/extrusions.js.map +1 -1
- package/dist/layers/layers.d.ts +12 -0
- package/dist/layers/layers.js +44 -1
- package/dist/layers/layers.js.map +1 -1
- package/dist/layers/photos.d.ts +48 -0
- package/dist/layers/photos.js +140 -0
- package/dist/layers/photos.js.map +1 -0
- package/dist/layers/symbols.d.ts +5 -1
- package/dist/layers/symbols.js +111 -32
- package/dist/layers/symbols.js.map +1 -1
- package/dist/layers/trees.d.ts +28 -0
- package/dist/layers/trees.js +51 -0
- package/dist/layers/trees.js.map +1 -0
- package/dist/layers/vectors.d.ts +28 -2
- package/dist/layers/vectors.js +81 -7
- package/dist/layers/vectors.js.map +1 -1
- package/dist/map/layer-spec.d.ts +3 -0
- package/dist/map/layer-spec.js +2 -0
- package/dist/map/layer-spec.js.map +1 -1
- package/dist/map.d.ts +8 -0
- package/dist/map.js +15 -2
- package/dist/map.js.map +1 -1
- package/dist/panoramax.d.ts +49 -0
- package/dist/panoramax.js +71 -0
- package/dist/panoramax.js.map +1 -0
- package/dist/react/Layer.d.ts +1 -0
- package/dist/react/Layer.js.map +1 -1
- package/dist/react/VectorGeometry.d.ts +5 -0
- package/dist/react/VectorGeometry.js +12 -4
- package/dist/react/VectorGeometry.js.map +1 -1
- package/dist/util/gltf.d.ts +9 -0
- package/dist/util/gltf.js +27 -0
- package/dist/util/gltf.js.map +1 -0
- package/dist/util/roofs.d.ts +10 -0
- package/dist/util/roofs.js +30 -0
- package/dist/util/roofs.js.map +1 -0
- package/dist/wasm/isard.d.ts +56 -17
- package/dist/wasm/isard.js +128 -18
- package/dist/wasm/isard_core.d.ts +44 -17
- package/dist/wasm/isard_core.js +104 -18
- package/dist/wasm/isard_tess.d.ts +6 -3
- package/dist/wasm/isard_tess.js +27 -4
- package/dist/workers/basemap/geometry.d.ts +38 -22
- package/dist/workers/basemap/labels.d.ts +14 -1
- package/dist/workers/basemap/lamps.d.ts +10 -0
- package/dist/workers/basemap/trees.d.ts +3 -1
- package/dist/workers/basemap.worker.d.ts +43 -3
- package/dist/workers/basemap.worker.js +14 -2
- package/dist/workers/basemap.worker.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"labels.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/labels.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The labels of a vector basemap (`VectorTiles.labels`): the label candidates the workers list for each vector tile in\n * view, shaped in the page once per tile, placed by the engine in a symbol layer of their own.\n */\n\nimport type { Feature, Size } from '../../layers/features.ts';\nimport { readPixels } from '../../layers/icons.ts';\nimport type { SymbolLayer } from '../../layers/symbols.ts';\nimport type { Anchor } from '../../ui/overlay.ts';\nimport { isRecord } from '../../util/guards.ts';\nimport { Lru } from '../../util/lru.ts';\nimport type { BasemapWork } from '../../workers/basemap.worker.ts';\nimport type { Json, LabelCandidate, StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { styleFonts } from './style.ts';\nimport { MAX_TILES, nearPriority, parseTileKey, tileKey, tilesAround, tileTriples } from './tiles.ts';\n\n/** Pause before the labels of tiles that failed are asked for again, when no move brings an update (ms) */\nconst RETRY_LABELS_MS = 3000;\n\n/** Milliseconds between two updates of the labels while the camera moves */\nconst LABELS_MOVE_REFRESH_MS = 250;\n\n/** Vector tiles' labels kept, shaped, the least recently used dropped past it */\nconst CACHED_TILES = 256;\n\n/** Text or icon size of a style (a number, legacy stops, or the stops of a zoom expression made by the worker) as a\n * size for the symbol layer */\nexport const size = (value: Json, fallback = 16): Size => {\n const stop = (s: Json): [number, number] => {\n const [z, v] = Array.isArray(s) ? s : [];\n\n return [Number(z), Number(v)];\n };\n\n if (typeof value === 'number') return value;\n if (Array.isArray(value) && value.length > 0 && value.every(Array.isArray)) return value.map(stop);\n if (isRecord(value) && Array.isArray(value.stops)) return value.stops.map(stop);\n\n return fallback;\n};\n\n/** The anchors of the symbol layer */\nconst ANCHORS: ReadonlySet<string> = new Set<Anchor>([\n 'center',\n 'top',\n 'bottom',\n 'left',\n 'right',\n 'top-left',\n 'top-right',\n 'bottom-left',\n 'bottom-right',\n]);\n\nconst isAnchor = (value: string | undefined): value is Anchor => value !== undefined && ANCHORS.has(value);\n\n/** A style's anchor (`text-anchor`, `icon-anchor`) for the symbol layer: `center` if it is none */\nconst anchor = (value: string | undefined): Anchor => (isAnchor(value) ? value : 'center');\n\n/** The labels of a vector tile: features by style layer (its index in the style), the higher layers first */\ntype TileLabels = [layer: number, features: Feature<LabelCandidate>[]][];\n\n/** A tile's label candidates as features, by style layer */\nexport const tileLabels = (candidates: readonly LabelCandidate[]): TileLabels => {\n const byLayer = new Map<number, Feature<LabelCandidate>[]>();\n\n candidates.forEach((p) => {\n const feature: Feature<LabelCandidate> = {\n type: 'Feature',\n properties: p,\n geometry: p.along\n ? {\n type: 'LineString',\n coordinates: [\n [p.lon - p.along[0] / 2, p.lat - p.along[1] / 2],\n [p.lon + p.along[0] / 2, p.lat + p.along[1] / 2],\n ],\n }\n : { type: 'Point', coordinates: [p.lon, p.lat] },\n };\n const list = byLayer.get(p.layer);\n\n if (list) list.push(feature);\n else byLayer.set(p.layer, [feature]);\n });\n\n return [...byLayer].sort((a, b) => b[0] - a[0]);\n};\n\n/** The key of a vector tile's labels: `z/x/y`, then `@zoom` when they are those of a deeper zoom than the tile's */\nconst labelsKey = (z: number, x: number, y: number, zoom: number): string =>\n `${tileKey(z, x, y)}${zoom > z ? `@${zoom}` : ''}`;\n\n/** The options of `VectorTiles.labels` */\nexport interface LabelsOptions {\n layers?: (layer: StyleLayer) => boolean;\n maxTiles?: number;\n}\n\nexport const labels = (context: VectorTilesContext, options: LabelsOptions = {}): SymbolLayer<LabelCandidate> => {\n const { map } = context;\n const { layers = () => true, maxTiles = MAX_TILES } = options;\n const symbol = map.addSymbols<LabelCandidate>({\n data: [],\n text: (p) => p.text,\n font: (p) => p.font,\n size: (p) => size(p.size),\n color: (p) => p.color,\n haloColor: (p) => p.haloColor,\n haloWidth: (p) => p.haloWidth,\n anchor: (p) => anchor(p.anchor),\n offset: (p) => p.offset,\n maxWidth: (p) => p.maxWidth,\n lineHeight: (p) => p.lineHeight,\n overlap: (p) => p.overlap,\n placement: (p) => (p.textAlong ? 'line' : 'point'),\n textOptional: (p) => p.textOptional === true,\n icon: (p) => (p.icon ? context.iconPrefix + p.icon.image : ''),\n iconSize: (p) => size(p.icon?.size ?? 1, 1),\n iconAnchor: (p) => anchor(p.icon?.anchor),\n iconOffset: (p) => p.icon?.offset ?? [0, 0],\n iconRotate: (p) => p.icon?.rotate ?? 0,\n iconRotationAlignment: (p) => p.icon?.alignment ?? 'viewport',\n iconOverlap: (p) => p.icon?.overlap ?? false,\n iconOptional: (p) => p.icon?.optional ?? false,\n iconTextFit: (p) => p.icon?.fit ?? 'none',\n iconTextFitPadding: (p) => p.icon?.padding ?? [0, 0, 0, 0],\n iconColor: (p) => p.icon?.color ?? '#000',\n iconOpacity: (p) => p.icon?.opacity ?? 1,\n });\n\n map.keepOnTop(symbol);\n context.layers.push(symbol);\n\n const renderer = context.ready.then(async ({ style }) => {\n // The style's fonts from its own glyphs\n if (style.glyphs) map.glyphs.register(style.glyphs, styleFonts(style));\n\n // Its icons from its sprites, before the first labels\n const icons = style.layers.some((l) => l.type === 'symbol' && l.layout?.['icon-image'] !== undefined);\n\n if (icons && style.sprite) {\n (await context.loadSprites(style.sprite)).forEach((sprite) => {\n if (!context.destroyed()) map.icons.addSprite(context.iconPrefix, sprite.icons, () => readPixels(sprite.image));\n });\n }\n\n return context.renderer((l) => l.type === 'symbol' && layers(l), []);\n });\n\n renderer.catch(() => undefined);\n\n /** The labels of the tiles, as features by style layer, the higher layers first: each list is given to the symbol\n * layer as a group, shaped once while the tile is kept */\n const tiles = new Lru<string, Promise<TileLabels>>(CACHED_TILES);\n let generation = 0;\n /** The tiles whose labels are shown */\n let shown = '';\n /** The update asked again after tiles failed */\n let retry = 0;\n const update = async () => {\n if (context.destroyed()) return;\n\n const { key, maxzoom } = await renderer;\n const run = ++generation;\n const camera = map.getCamera();\n const zoom = Math.max(0, Math.min(Math.floor(camera.zoom), 24));\n const ground = context.ground();\n const groundTiles = ground && map.hasLayer(ground) ? tileTriples(map.engine.wantedTiles(ground.id)) : [];\n const keys: string[] = [];\n\n if (groundTiles.length > 0) {\n // The ground's tiles, the nearest first: a tile so many levels coarser than the finest in view has its\n // labels of a zoom as many under the view's, past the source's deepest level those of that level at the zoom\n const top = groundTiles.reduce((t, [z]) => Math.max(t, z), 0);\n\n groundTiles.forEach(([z, x, y]) => {\n if (keys.length >= maxTiles) return;\n\n const at = Math.max(0, zoom - (top - z));\n const tz = Math.min(at, maxzoom, z);\n const shift = 2 ** (z - tz);\n const key = labelsKey(tz, Math.floor(x / shift), Math.floor(y / shift), at);\n\n if (!keys.includes(key)) keys.push(key);\n });\n } else {\n const z = Math.min(zoom, maxzoom);\n const wanted = tilesAround(map, camera, z, maxTiles);\n\n // Past the source's deepest level, its tiles' labels at the zoom of the view (the layers of the deeper zooms)\n keys.push(...wanted.map(([x, y]) => labelsKey(z, x, y, zoom)));\n }\n\n // The same tiles as the labels shown: nothing to do\n const set = keys.join(' ');\n\n if (set === shown) return;\n\n const lists = await Promise.all(\n keys.map((k, index) => {\n const cached = tiles.get(k);\n\n if (cached) return cached;\n\n const [tile = '', deeper] = k.split('@');\n const [tz, x, y] = parseTileKey(tile);\n // The nearest tiles first: the others wait for the raster tiles\n const work: BasemapWork = {\n type: 'labels',\n key,\n z: tz,\n x,\n y,\n priority: nearPriority(index),\n ...(deeper === undefined ? {} : { zoom: Number(deeper) }),\n };\n const p = context.request(tz, x, y, work).then(\n (r) => tileLabels('labels' in r ? r.labels : []),\n () => {\n // A network error is not kept: the tile is asked for again on the next update\n tiles.delete(k);\n\n return [];\n },\n );\n\n // A bounded cache of tiles' labels, the least recently used dropped\n tiles.set(k, p);\n\n return p;\n }),\n );\n\n if (run !== generation || context.destroyed()) return;\n // A tile that failed is missing: the next update asks for it again, after a pause if no move brings one\n shown = keys.every((k) => tiles.has(k)) ? set : '';\n if (shown === '' && !retry) {\n retry = window.setTimeout(() => {\n retry = 0;\n refresh();\n }, RETRY_LABELS_MS);\n }\n\n // The labels of the higher style layers first: they win the collisions; for each style layer, the tiles nearest\n // to the center first\n const layerIds = [...new Set(lists.flatMap((list) => list.map(([layer]) => layer)))].sort((a, b) => b - a);\n const groups = layerIds.flatMap((layer) =>\n lists.map((list) => list.find(([l]) => l === layer)?.[1]).filter((group) => group !== undefined),\n );\n\n symbol.setGroups(groups);\n };\n // The style failed to load: reported by `ready`\n const refresh = () => {\n update().catch(() => undefined);\n };\n let timer = 0;\n const schedule = () => {\n if (timer) return;\n timer = window.setTimeout(() => {\n timer = 0;\n refresh();\n }, LABELS_MOVE_REFRESH_MS);\n };\n\n context.cleanup.push(map.on('move', schedule), map.on('moveend', refresh), () => {\n clearTimeout(timer);\n clearTimeout(retry);\n });\n refresh();\n\n return symbol;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"labels.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/labels.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The labels of a vector basemap (`VectorTiles.labels`): the label candidates the workers list for each vector tile in\n * view, shaped in the page once per tile, placed by the engine in a symbol layer of their own.\n */\n\nimport { ExtrusionLayer } from '../../layers/extrusions.ts';\nimport type { Feature, Size } from '../../layers/features.ts';\nimport type { Layer } from '../../layers/layers.ts';\nimport type { SymbolLayer } from '../../layers/symbols.ts';\nimport { VectorLayer } from '../../layers/vectors.ts';\nimport type { Anchor } from '../../ui/overlay.ts';\nimport { isRecord } from '../../util/guards.ts';\nimport { Lru } from '../../util/lru.ts';\nimport type { BasemapWork } from '../../workers/basemap.worker.ts';\nimport type { Json, LabelCandidate, StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { styleFonts } from './style.ts';\nimport { MAX_TILES, nearPriority, parseTileKey, tileKey, tilesAround, tileTriples } from './tiles.ts';\n\n/** Pause before the labels of tiles that failed are asked for again, when no move brings an update (ms) */\nconst RETRY_LABELS_MS = 3000;\n\n/** Milliseconds between two updates of the labels while the camera moves */\nconst LABELS_MOVE_REFRESH_MS = 250;\n\n/** Vector tiles' labels kept, shaped, the least recently used dropped past it */\nconst CACHED_TILES = 256;\n\n/** Text or icon size of a style (a number, legacy stops, or the stops of a zoom expression made by the worker) as a\n * size for the symbol layer */\nexport const size = (value: Json, fallback = 16): Size => {\n const stop = (s: Json): [number, number] => {\n const [z, v] = Array.isArray(s) ? s : [];\n\n return [Number(z), Number(v)];\n };\n\n if (typeof value === 'number') return value;\n if (Array.isArray(value) && value.length > 0 && value.every(Array.isArray)) return value.map(stop);\n if (isRecord(value) && Array.isArray(value.stops)) return value.stops.map(stop);\n\n return fallback;\n};\n\n/** The anchors of the symbol layer */\nconst ANCHORS: ReadonlySet<string> = new Set<Anchor>([\n 'center',\n 'top',\n 'bottom',\n 'left',\n 'right',\n 'top-left',\n 'top-right',\n 'bottom-left',\n 'bottom-right',\n]);\n\nconst isAnchor = (value: string | undefined): value is Anchor => value !== undefined && ANCHORS.has(value);\n\n/** A style's anchor (`text-anchor`, `icon-anchor`) for the symbol layer: `center` if it is none */\nconst anchor = (value: string | undefined): Anchor => (isAnchor(value) ? value : 'center');\n\n/** The labels of a vector tile: features by style layer (its index in the style), the higher layers first */\ntype TileLabels = [layer: number, features: Feature<LabelCandidate>[]][];\n\n/** Where a candidate is labelled: the line around a text that follows it, a short line along a line's direction (its\n * middle the anchor), or its point */\nconst geometryOf = (p: LabelCandidate): Feature<LabelCandidate>['geometry'] => {\n const { path, along } = p;\n\n if (path) {\n return {\n type: 'LineString',\n coordinates: Array.from({ length: path.length / 2 }, (_, i) => [path[i * 2] ?? 0, path[i * 2 + 1] ?? 0]),\n };\n }\n if (along) {\n return {\n type: 'LineString',\n coordinates: [\n [p.lon - along[0] / 2, p.lat - along[1] / 2],\n [p.lon + along[0] / 2, p.lat + along[1] / 2],\n ],\n };\n }\n\n return { type: 'Point', coordinates: [p.lon, p.lat] };\n};\n\n/** A tile's label candidates as features, by style layer */\nexport const tileLabels = (candidates: readonly LabelCandidate[]): TileLabels => {\n const byLayer = new Map<number, Feature<LabelCandidate>[]>();\n\n candidates.forEach((p) => {\n const feature: Feature<LabelCandidate> = {\n type: 'Feature',\n properties: p,\n geometry: geometryOf(p),\n };\n const list = byLayer.get(p.layer);\n\n if (list) list.push(feature);\n else byLayer.set(p.layer, [feature]);\n });\n\n return [...byLayer].sort((a, b) => b[0] - a[0]);\n};\n\n/** The key of a vector tile's labels: `z/x/y`, then `@zoom` when they are those of a deeper zoom than the tile's */\nconst labelsKey = (z: number, x: number, y: number, zoom: number): string =>\n `${tileKey(z, x, y)}${zoom > z ? `@${zoom}` : ''}`;\n\n/** Whether a layer of the basemap raises its buildings: its extrusions, or a style layer `fill-extrusion` of its\n * vectors shown */\nconst raisesBuildings = (layer: Layer): boolean =>\n layer instanceof ExtrusionLayer ||\n (layer instanceof VectorLayer && layer.layers.some((l) => l.kind === 'extrusion' && l.visible));\n\n/** The options of `VectorTiles.labels` */\nexport interface LabelsOptions {\n layers?: (layer: StyleLayer) => boolean;\n maxTiles?: number;\n /** Hidden by the solids before them (the buildings, the trees, the models) and lifted onto the roofs (default: when\n * these tiles raise buildings; `true` for buildings raised by others, a `<VectorGeometry>` of the same style) */\n occluded?: boolean;\n}\n\nexport const labels = (context: VectorTilesContext, options: LabelsOptions = {}): SymbolLayer<LabelCandidate> => {\n const { map } = context;\n const { layers = () => true, maxTiles = MAX_TILES } = options;\n const symbol = map.addSymbols<LabelCandidate>({\n data: [],\n text: (p) => p.text,\n font: (p) => p.font,\n size: (p) => size(p.size),\n color: (p) => p.color,\n haloColor: (p) => p.haloColor,\n haloWidth: (p) => p.haloWidth,\n anchor: (p) => anchor(p.anchor),\n offset: (p) => p.offset,\n maxWidth: (p) => p.maxWidth,\n lineHeight: (p) => p.lineHeight,\n overlap: (p) => p.overlap,\n placement: (p) => (p.textAlong ? 'line' : 'point'),\n textOptional: (p) => p.textOptional === true,\n icon: (p) => (p.icon ? context.iconPrefix + p.icon.image : ''),\n iconSize: (p) => size(p.icon?.size ?? 1, 1),\n iconAnchor: (p) => anchor(p.icon?.anchor),\n iconOffset: (p) => p.icon?.offset ?? [0, 0],\n iconRotate: (p) => p.icon?.rotate ?? 0,\n iconRotationAlignment: (p) => p.icon?.alignment ?? 'viewport',\n iconOverlap: (p) => p.icon?.overlap ?? false,\n iconOptional: (p) => p.icon?.optional ?? false,\n iconTextFit: (p) => p.icon?.fit ?? 'none',\n iconTextFitPadding: (p) => p.icon?.padding ?? [0, 0, 0, 0],\n iconColor: (p) => p.icon?.color ?? '#000',\n iconOpacity: (p) => p.icon?.opacity ?? 1,\n });\n\n map.keepOnTop(symbol);\n context.layers.push(symbol);\n\n const renderer = context.ready.then(async ({ style }) => {\n // The style's fonts from its own glyphs\n if (style.glyphs) map.glyphs.register(style.glyphs, styleFonts(style));\n\n // Its icons from its sprites, before the first labels\n const icons = style.layers.some((l) => l.type === 'symbol' && l.layout?.['icon-image'] !== undefined);\n\n if (icons) await context.addSprites();\n\n // With the buildings: a label in one stands on its roof\n return context.renderer((l) => (l.type === 'symbol' && layers(l)) || l.type === 'fill-extrusion', []);\n });\n\n renderer.catch(() => undefined);\n\n /** The labels of the tiles, as features by style layer, the higher layers first: each list is given to the symbol\n * layer as a group, shaped once while the tile is kept */\n const tiles = new Lru<string, Promise<TileLabels>>(CACHED_TILES);\n let generation = 0;\n /** The tiles whose labels are shown */\n let shown = '';\n /** The update asked again after tiles failed */\n let retry = 0;\n /** The labels hidden by the buildings the basemap raises, those in one standing on its roof */\n let occluded = false;\n const update = async () => {\n if (context.destroyed()) return;\n\n const { key, maxzoom } = await renderer;\n const others = context.layers.filter((l) => l !== symbol);\n\n // Its vectors' style layers known first\n await Promise.all(others.map((l) => (l instanceof VectorLayer ? l.styled : undefined)));\n\n const raised = options.occluded ?? others.some(raisesBuildings);\n\n if (raised !== occluded) {\n occluded = raised;\n symbol.setStyle({ occluded, height: occluded ? (p) => p.height ?? 0 : 0 });\n }\n\n const run = ++generation;\n const camera = map.getCamera();\n const zoom = Math.max(0, Math.min(Math.floor(camera.zoom), 24));\n const ground = context.ground();\n const groundTiles = ground && map.hasLayer(ground) ? tileTriples(map.engine.wantedTiles(ground.id)) : [];\n const keys: string[] = [];\n\n if (groundTiles.length > 0) {\n // The ground's tiles, the nearest first: a tile so many levels coarser than the finest in view has its\n // labels of a zoom as many under the view's, past the source's deepest level those of that level at the zoom\n const top = groundTiles.reduce((t, [z]) => Math.max(t, z), 0);\n\n groundTiles.forEach(([z, x, y]) => {\n if (keys.length >= maxTiles) return;\n\n const at = Math.max(0, zoom - (top - z));\n const tz = Math.min(at, maxzoom, z);\n const shift = 2 ** (z - tz);\n const key = labelsKey(tz, Math.floor(x / shift), Math.floor(y / shift), at);\n\n if (!keys.includes(key)) keys.push(key);\n });\n } else {\n const z = Math.min(zoom, maxzoom);\n const wanted = tilesAround(map, camera, z, maxTiles);\n\n // Past the source's deepest level, its tiles' labels at the zoom of the view (the layers of the deeper zooms)\n keys.push(...wanted.map(([x, y]) => labelsKey(z, x, y, zoom)));\n }\n\n // The same tiles as the labels shown: nothing to do\n const set = keys.join(' ');\n\n if (set === shown) return;\n\n const lists = await Promise.all(\n keys.map((k, index) => {\n const cached = tiles.get(k);\n\n if (cached) return cached;\n\n const [tile = '', deeper] = k.split('@');\n const [tz, x, y] = parseTileKey(tile);\n // The nearest tiles first: the others wait for the raster tiles\n const work: BasemapWork = {\n type: 'labels',\n key,\n z: tz,\n x,\n y,\n priority: nearPriority(index),\n ...(deeper === undefined ? {} : { zoom: Number(deeper) }),\n };\n const p = context.request(tz, x, y, work).then(\n (r) => tileLabels('labels' in r ? r.labels : []),\n () => {\n // A network error is not kept: the tile is asked for again on the next update\n tiles.delete(k);\n\n return [];\n },\n );\n\n // A bounded cache of tiles' labels, the least recently used dropped\n tiles.set(k, p);\n\n return p;\n }),\n );\n\n if (run !== generation || context.destroyed()) return;\n // A tile that failed is missing: the next update asks for it again, after a pause if no move brings one\n shown = keys.every((k) => tiles.has(k)) ? set : '';\n if (shown === '' && !retry) {\n retry = window.setTimeout(() => {\n retry = 0;\n refresh();\n }, RETRY_LABELS_MS);\n }\n\n // The labels of the higher style layers first: they win the collisions; for each style layer, the tiles nearest\n // to the center first\n const layerIds = [...new Set(lists.flatMap((list) => list.map(([layer]) => layer)))].sort((a, b) => b - a);\n const groups = layerIds.flatMap((layer) =>\n lists.map((list) => list.find(([l]) => l === layer)?.[1]).filter((group) => group !== undefined),\n );\n\n symbol.setGroups(groups);\n };\n // The style failed to load: reported by `ready`\n const refresh = () => {\n update().catch(() => undefined);\n };\n let timer = 0;\n const schedule = () => {\n if (timer) return;\n timer = window.setTimeout(() => {\n timer = 0;\n refresh();\n }, LABELS_MOVE_REFRESH_MS);\n };\n\n context.cleanup.push(map.on('move', schedule), map.on('moveend', refresh), () => {\n clearTimeout(timer);\n clearTimeout(retry);\n });\n refresh();\n\n return symbol;\n};\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** The street lamps of a vector basemap (`VectorTiles.lamps`): 3D models placed by the workers along its streets, lit at
|
|
2
|
+
* night */
|
|
3
|
+
import type { Layer, ModelLayer } from '../../layers/layers.ts';
|
|
4
|
+
import type { StyleLayer } from '../vectorstyle.ts';
|
|
5
|
+
import type { VectorTilesContext } from './context.ts';
|
|
6
|
+
/** The options of `VectorTiles.lamps` */
|
|
7
|
+
export interface LampsOptions {
|
|
8
|
+
/** The line layers of the streets lit (default: the roads, as the streets glowing at night) */
|
|
9
|
+
layers?: (layer: StyleLayer) => boolean;
|
|
10
|
+
/** Metres between two lamps along a street (default 30, every other one on its other side) */
|
|
11
|
+
spacing?: number;
|
|
12
|
+
/** From this zoom on (default 16) */
|
|
13
|
+
minZoom?: number;
|
|
14
|
+
maxTiles?: number;
|
|
15
|
+
/** Lamps in a tile at most (default 20000) */
|
|
16
|
+
maxLamps?: number;
|
|
17
|
+
/** Lamps drawn at most (default 15000) */
|
|
18
|
+
maxInstances?: number;
|
|
19
|
+
/** The color of their light at night (CSS; default a warm white) */
|
|
20
|
+
light?: string;
|
|
21
|
+
before?: Layer;
|
|
22
|
+
}
|
|
23
|
+
export declare const lamps: (context: VectorTilesContext, options?: LampsOptions) => ModelLayer;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/** The street lamps of a vector basemap (`VectorTiles.lamps`): 3D models placed by the workers along its streets, lit at
|
|
2
|
+
* night */
|
|
3
|
+
import { LAMP_HEAD, lampModel } from "../furniture.js";
|
|
4
|
+
import { TREE_NUMBERS } from "../trees.js";
|
|
5
|
+
import { TileRequests } from "./requests.js";
|
|
6
|
+
import { nearPriority, tileKey, tilesAround } from "./tiles.js";
|
|
7
|
+
import { followWhenMoved, groundUnderCamera, METRES_PER_DEGREE } from "./trees.js";
|
|
8
|
+
import { isStreet } from "./vectors.js";
|
|
9
|
+
/** Metres around the ground under the camera where every lamp is drawn at zoom 17 (twice as far a zoom level out);
|
|
10
|
+
* past them, fewer and fewer */
|
|
11
|
+
const LAMPS_NEAR_METRES = 250;
|
|
12
|
+
export const lamps = (context, options = {}) => {
|
|
13
|
+
const { map } = context;
|
|
14
|
+
const { layers = isStreet, spacing = 30, minZoom = 16, maxTiles = 9, maxLamps = 20000, maxInstances = 15000, light = '#ffd9a0', } = options;
|
|
15
|
+
const layer = map.addModels({
|
|
16
|
+
data: lampModel(),
|
|
17
|
+
instances: [],
|
|
18
|
+
...(options.before ? { before: options.before } : {}),
|
|
19
|
+
});
|
|
20
|
+
const renderer = context.renderer((l) => l.type === 'line' && layers(l), []);
|
|
21
|
+
layer.setGlow(LAMP_HEAD, light);
|
|
22
|
+
renderer.catch(() => undefined);
|
|
23
|
+
context.layers.push(layer);
|
|
24
|
+
const requests = new TileRequests();
|
|
25
|
+
const found = new Map();
|
|
26
|
+
/** The lamps drawn: all of them near the ground under the camera, past it those of a rank under (near / distance)²,
|
|
27
|
+
* at most `maxInstances` (past it, the rank kept lowered in proportion: no sort) */
|
|
28
|
+
const send = () => {
|
|
29
|
+
const { center, zoom } = map.getCamera();
|
|
30
|
+
const cos = Math.cos((center[1] * Math.PI) / 180);
|
|
31
|
+
const [ex, ey, back] = groundUnderCamera(map);
|
|
32
|
+
const near = LAMPS_NEAR_METRES * 2 ** (17 - zoom) + back;
|
|
33
|
+
const each = (keep) => {
|
|
34
|
+
found.forEach((t) => {
|
|
35
|
+
for (let i = 0; i < t.length / TREE_NUMBERS; i += 1) {
|
|
36
|
+
const dx = ((t[i * TREE_NUMBERS] ?? 0) - center[0]) * METRES_PER_DEGREE * cos - ex;
|
|
37
|
+
const dy = ((t[i * TREE_NUMBERS + 1] ?? 0) - center[1]) * METRES_PER_DEGREE - ey;
|
|
38
|
+
const score = (t[i * TREE_NUMBERS + 4] ?? 0) * Math.max(1, (dx * dx + dy * dy) / (near * near));
|
|
39
|
+
if (score < 1)
|
|
40
|
+
keep(t, i, score);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
let count = 0;
|
|
45
|
+
each(() => {
|
|
46
|
+
count += 1;
|
|
47
|
+
});
|
|
48
|
+
const limit = Math.min(1, maxInstances / Math.max(count, 1));
|
|
49
|
+
const out = [];
|
|
50
|
+
each((t, i, score) => {
|
|
51
|
+
const at = i * TREE_NUMBERS;
|
|
52
|
+
if (score < limit)
|
|
53
|
+
out.push(t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1);
|
|
54
|
+
});
|
|
55
|
+
layer.setInstanceNumbers(Float64Array.from(out));
|
|
56
|
+
};
|
|
57
|
+
const update = async () => {
|
|
58
|
+
if (context.destroyed())
|
|
59
|
+
return;
|
|
60
|
+
const { key, maxzoom } = await renderer;
|
|
61
|
+
const camera = map.getCamera();
|
|
62
|
+
const z = maxzoom;
|
|
63
|
+
const wanted = camera.zoom < minZoom ? [] : tilesAround(map, camera, z, maxTiles);
|
|
64
|
+
const keys = new Set(wanted.map(([x, y]) => tileKey(z, x, y)));
|
|
65
|
+
// Out of view: dropped, or no longer asked for
|
|
66
|
+
requests
|
|
67
|
+
.keys()
|
|
68
|
+
.filter((k) => !keys.has(k))
|
|
69
|
+
.forEach((k) => {
|
|
70
|
+
requests.drop(k);
|
|
71
|
+
found.delete(k);
|
|
72
|
+
});
|
|
73
|
+
send();
|
|
74
|
+
wanted.forEach(([x, y], index) => {
|
|
75
|
+
const k = tileKey(z, x, y);
|
|
76
|
+
if (requests.has(k))
|
|
77
|
+
return;
|
|
78
|
+
const work = { type: 'lamps', key, z, x, y, spacing, maxLamps, priority: nearPriority(index) };
|
|
79
|
+
requests.ask(k, (signal) => context.request(z, x, y, work, signal), (r) => {
|
|
80
|
+
if (!('lamps' in r))
|
|
81
|
+
return;
|
|
82
|
+
found.set(k, r.lamps);
|
|
83
|
+
send();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
context.followView(update, requests, followWhenMoved(map, (zoom) => LAMPS_NEAR_METRES * 2 ** (17 - zoom), send));
|
|
88
|
+
return layer;
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=lamps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lamps.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/lamps.ts"],"names":[],"mappings":"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","sourcesContent":["/** The street lamps of a vector basemap (`VectorTiles.lamps`): 3D models placed by the workers along its streets, lit at\n * night */\n\nimport type { Layer, ModelLayer } from '../../layers/layers.ts';\nimport type { BasemapWork } from '../../workers/basemap.worker.ts';\nimport { LAMP_HEAD, lampModel } from '../furniture.ts';\nimport { TREE_NUMBERS } from '../trees.ts';\nimport type { StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { TileRequests } from './requests.ts';\nimport { nearPriority, tileKey, tilesAround } from './tiles.ts';\nimport { followWhenMoved, groundUnderCamera, METRES_PER_DEGREE } from './trees.ts';\nimport { isStreet } from './vectors.ts';\n\n/** Metres around the ground under the camera where every lamp is drawn at zoom 17 (twice as far a zoom level out);\n * past them, fewer and fewer */\nconst LAMPS_NEAR_METRES = 250;\n\n/** The options of `VectorTiles.lamps` */\nexport interface LampsOptions {\n /** The line layers of the streets lit (default: the roads, as the streets glowing at night) */\n layers?: (layer: StyleLayer) => boolean;\n /** Metres between two lamps along a street (default 30, every other one on its other side) */\n spacing?: number;\n /** From this zoom on (default 16) */\n minZoom?: number;\n maxTiles?: number;\n /** Lamps in a tile at most (default 20000) */\n maxLamps?: number;\n /** Lamps drawn at most (default 15000) */\n maxInstances?: number;\n /** The color of their light at night (CSS; default a warm white) */\n light?: string;\n before?: Layer;\n}\n\nexport const lamps = (context: VectorTilesContext, options: LampsOptions = {}): ModelLayer => {\n const { map } = context;\n const {\n layers = isStreet,\n spacing = 30,\n minZoom = 16,\n maxTiles = 9,\n maxLamps = 20000,\n maxInstances = 15000,\n light = '#ffd9a0',\n } = options;\n const layer = map.addModels({\n data: lampModel(),\n instances: [],\n ...(options.before ? { before: options.before } : {}),\n });\n const renderer = context.renderer((l) => l.type === 'line' && layers(l), []);\n\n layer.setGlow(LAMP_HEAD, light);\n renderer.catch(() => undefined);\n context.layers.push(layer);\n\n const requests = new TileRequests();\n const found = new Map<string, Float64Array>();\n /** The lamps drawn: all of them near the ground under the camera, past it those of a rank under (near / distance)²,\n * at most `maxInstances` (past it, the rank kept lowered in proportion: no sort) */\n const send = () => {\n const { center, zoom } = map.getCamera();\n const cos = Math.cos((center[1] * Math.PI) / 180);\n const [ex, ey, back] = groundUnderCamera(map);\n const near = LAMPS_NEAR_METRES * 2 ** (17 - zoom) + back;\n const each = (keep: (t: Float64Array, i: number, score: number) => void) => {\n found.forEach((t) => {\n for (let i = 0; i < t.length / TREE_NUMBERS; i += 1) {\n const dx = ((t[i * TREE_NUMBERS] ?? 0) - center[0]) * METRES_PER_DEGREE * cos - ex;\n const dy = ((t[i * TREE_NUMBERS + 1] ?? 0) - center[1]) * METRES_PER_DEGREE - ey;\n const score = (t[i * TREE_NUMBERS + 4] ?? 0) * Math.max(1, (dx * dx + dy * dy) / (near * near));\n\n if (score < 1) keep(t, i, score);\n }\n });\n };\n let count = 0;\n\n each(() => {\n count += 1;\n });\n\n const limit = Math.min(1, maxInstances / Math.max(count, 1));\n const out: number[] = [];\n\n each((t, i, score) => {\n const at = i * TREE_NUMBERS;\n\n if (score < limit) out.push(t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1);\n });\n layer.setInstanceNumbers(Float64Array.from(out));\n };\n const update = async () => {\n if (context.destroyed()) return;\n\n const { key, maxzoom } = await renderer;\n const camera = map.getCamera();\n const z = maxzoom;\n const wanted = camera.zoom < minZoom ? [] : tilesAround(map, camera, z, maxTiles);\n const keys = new Set(wanted.map(([x, y]) => tileKey(z, x, y)));\n\n // Out of view: dropped, or no longer asked for\n requests\n .keys()\n .filter((k) => !keys.has(k))\n .forEach((k) => {\n requests.drop(k);\n found.delete(k);\n });\n send();\n wanted.forEach(([x, y], index) => {\n const k = tileKey(z, x, y);\n\n if (requests.has(k)) return;\n\n const work: BasemapWork = { type: 'lamps', key, z, x, y, spacing, maxLamps, priority: nearPriority(index) };\n\n requests.ask(\n k,\n (signal) => context.request(z, x, y, work, signal),\n (r) => {\n if (!('lamps' in r)) return;\n found.set(k, r.lamps);\n send();\n },\n );\n });\n };\n\n context.followView(\n update,\n requests,\n followWhenMoved(map, (zoom) => LAMPS_NEAR_METRES * 2 ** (17 - zoom), send),\n );\n\n return layer;\n};\n"]}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export declare class TileRequests {
|
|
6
6
|
private readonly held;
|
|
7
|
+
/** The requests not answered yet, by key */
|
|
8
|
+
private readonly pending;
|
|
7
9
|
/** Whether the tile is held or asked for */
|
|
8
10
|
has(key: string): boolean;
|
|
9
11
|
/** The keys of the tiles held or asked for (a copy: the tiles can be dropped while it is gone through) */
|
|
@@ -16,6 +18,8 @@ export declare class TileRequests {
|
|
|
16
18
|
* refusing the tile) is reported, never left unhandled
|
|
17
19
|
*/
|
|
18
20
|
ask<T>(key: string, request: (signal: AbortSignal) => Promise<T>, use: (answer: T) => unknown): Promise<void>;
|
|
21
|
+
/** Resolves once the tiles of `keys` asked for, by this update or an earlier one, are answered (or dropped) */
|
|
22
|
+
answered(keys: Iterable<string>): Promise<void>;
|
|
19
23
|
/** Aborts the tile's request and forgets it */
|
|
20
24
|
drop(key: string): void;
|
|
21
25
|
/** Aborts every request and forgets every tile */
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export class TileRequests {
|
|
6
6
|
held = new Map();
|
|
7
|
+
/** The requests not answered yet, by key */
|
|
8
|
+
pending = new Map();
|
|
7
9
|
/** Whether the tile is held or asked for */
|
|
8
10
|
has(key) {
|
|
9
11
|
return this.held.has(key);
|
|
@@ -28,7 +30,8 @@ export class TileRequests {
|
|
|
28
30
|
if (this.held.get(key) === controller)
|
|
29
31
|
this.held.delete(key);
|
|
30
32
|
};
|
|
31
|
-
|
|
33
|
+
const answered = request(controller.signal)
|
|
34
|
+
.then(async (answer) => {
|
|
32
35
|
if (controller.signal.aborted)
|
|
33
36
|
return;
|
|
34
37
|
try {
|
|
@@ -38,7 +41,17 @@ export class TileRequests {
|
|
|
38
41
|
console.warn('isard: a vector tile not drawn', error);
|
|
39
42
|
forget();
|
|
40
43
|
}
|
|
41
|
-
}, forget)
|
|
44
|
+
}, forget)
|
|
45
|
+
.finally(() => {
|
|
46
|
+
if (this.pending.get(key) === answered)
|
|
47
|
+
this.pending.delete(key);
|
|
48
|
+
});
|
|
49
|
+
this.pending.set(key, answered);
|
|
50
|
+
return answered;
|
|
51
|
+
}
|
|
52
|
+
/** Resolves once the tiles of `keys` asked for, by this update or an earlier one, are answered (or dropped) */
|
|
53
|
+
answered(keys) {
|
|
54
|
+
return Promise.all([...keys].map((k) => this.pending.get(k))).then(() => undefined);
|
|
42
55
|
}
|
|
43
56
|
/** Aborts the tile's request and forgets it */
|
|
44
57
|
drop(key) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requests.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/requests.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,OAAO,YAAY;IACN,IAAI,GAAG,IAAI,GAAG,EAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"requests.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/requests.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The requests of a layer whose tiles follow the view (`VectorTiles`' extrusions, streets' wind, trees, vectors): the\n * tiles held or asked for, by key, each with the controller that aborts its request.\n */\n\nexport class TileRequests {\n private readonly held = new Map<string, AbortController>();\n /** The requests not answered yet, by key */\n private readonly pending = new Map<string, Promise<void>>();\n\n /** Whether the tile is held or asked for */\n has(key: string): boolean {\n return this.held.has(key);\n }\n\n /** The keys of the tiles held or asked for (a copy: the tiles can be dropped while it is gone through) */\n keys(): string[] {\n return [...this.held.keys()];\n }\n\n /** Holds a new request under `key` (the one it held before is forgotten, not aborted); returns its signal */\n start(key: string): AbortSignal {\n return this.open(key).signal;\n }\n\n /**\n * Asks for a tile (`request`) and does with its answer what `use` does, unless the request was aborted meanwhile. On\n * a failure of either, the tile is forgotten (the next update asks for it again); an error of `use` (the engine\n * refusing the tile) is reported, never left unhandled\n */\n ask<T>(key: string, request: (signal: AbortSignal) => Promise<T>, use: (answer: T) => unknown): Promise<void> {\n const controller = this.open(key);\n // A later request under the same key is not forgotten by this one's failure\n const forget = () => {\n if (this.held.get(key) === controller) this.held.delete(key);\n };\n\n const answered = request(controller.signal)\n .then(async (answer) => {\n if (controller.signal.aborted) return;\n\n try {\n await use(answer);\n } catch (error) {\n console.warn('isard: a vector tile not drawn', error);\n forget();\n }\n }, forget)\n .finally(() => {\n if (this.pending.get(key) === answered) this.pending.delete(key);\n });\n\n this.pending.set(key, answered);\n\n return answered;\n }\n\n /** Resolves once the tiles of `keys` asked for, by this update or an earlier one, are answered (or dropped) */\n answered(keys: Iterable<string>): Promise<void> {\n return Promise.all([...keys].map((k) => this.pending.get(k))).then(() => undefined);\n }\n\n /** Aborts the tile's request and forgets it */\n drop(key: string): void {\n this.held.get(key)?.abort();\n this.held.delete(key);\n }\n\n /** Aborts every request and forgets every tile */\n abortAll(): void {\n this.held.forEach((controller) => {\n controller.abort();\n });\n this.held.clear();\n }\n\n private open(key: string): AbortController {\n const controller = new AbortController();\n\n this.held.set(key, controller);\n\n return controller;\n }\n}\n"]}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/** The trees of a vector basemap (`VectorTiles.trees`): 3D models scattered by the workers over its woods and grass */
|
|
2
2
|
import type { Layer, ModelLayer } from '../../layers/layers.ts';
|
|
3
|
+
import type { GeoMap } from '../../map.ts';
|
|
3
4
|
import { type TreeColors } from '../trees.ts';
|
|
4
5
|
import type { StyleLayer } from '../vectorstyle.ts';
|
|
5
6
|
import type { VectorTilesContext } from './context.ts';
|
|
7
|
+
/** Metres in a degree of latitude (and of longitude at the equator), near enough for the trees' distances */
|
|
8
|
+
export declare const METRES_PER_DEGREE = 111320;
|
|
6
9
|
/** The options of `VectorTiles.trees` */
|
|
7
10
|
export interface TreesOptions {
|
|
8
11
|
layers?: (layer: StyleLayer) => boolean;
|
|
@@ -16,4 +19,10 @@ export interface TreesOptions {
|
|
|
16
19
|
data?: ArrayBuffer | ArrayBufferView<ArrayBuffer>;
|
|
17
20
|
before?: Layer;
|
|
18
21
|
}
|
|
22
|
+
/** The ground under the camera: east and north metres from the view's center, and its distance from it (the camera
|
|
23
|
+
* stands behind the center of a tilted view, `FOV` its field of view) */
|
|
24
|
+
export declare const groundUnderCamera: (map: GeoMap) => [east: number, north: number, distance: number];
|
|
25
|
+
/** What follows the camera as it moves: `send` called again once it has gone `RESEND_SHARE` of `radius` metres (or
|
|
26
|
+
* turned or zoomed as much), not at every frame of a drag */
|
|
27
|
+
export declare const followWhenMoved: (map: GeoMap, radius: (zoom: number) => number, send: () => void) => (() => void);
|
|
19
28
|
export declare const trees: (context: VectorTilesContext, options?: TreesOptions) => ModelLayer;
|
|
@@ -1,51 +1,135 @@
|
|
|
1
1
|
/** The trees of a vector basemap (`VectorTiles.trees`): 3D models scattered by the workers over its woods and grass */
|
|
2
|
-
import { isWoodland, TREE_NUMBERS, treeModel, treeSpacing } from "../trees.js";
|
|
2
|
+
import { coniferModel, isWoodland, TREE_NUMBERS, treeModel, treeSpacing } from "../trees.js";
|
|
3
3
|
import { TileRequests } from "./requests.js";
|
|
4
4
|
import { nearPriority, STREET_ZOOM, tileKey, tilesAround } from "./tiles.js";
|
|
5
|
-
/** Metres around the view's center where every tree is drawn at zoom 16 (twice as far a zoom level out)
|
|
5
|
+
/** Metres around the view's center where every tree is drawn in full at zoom 16 (twice as far a zoom level out);
|
|
6
|
+
* past them, simplified (`treeModel(…, true)`) */
|
|
6
7
|
const TREES_NEAR_METRES = 350;
|
|
8
|
+
/** The engine's vertical field of view (radians, `camera::FOV`): where the camera stands behind the view's center */
|
|
9
|
+
const FOV = 0.6435011087932844;
|
|
10
|
+
/** How much denser the simplified trees far away stay than the full ones would (four times fewer triangles each): a
|
|
11
|
+
* tree twice as far kept as often */
|
|
12
|
+
const FAR_DENSITY = 4;
|
|
13
|
+
/** The simplified trees drawn at most, for so many full ones (`maxInstances`) */
|
|
14
|
+
const FAR_INSTANCES = 3;
|
|
15
|
+
/** While the camera moves, the trees chosen again once it has gone this share of the full trees' radius (or turned
|
|
16
|
+
* or zoomed as much): going through the tiles' trees at every frame of a drag would hold the main thread */
|
|
17
|
+
const RESEND_SHARE = 0.05;
|
|
7
18
|
/** Metres in a degree of latitude (and of longitude at the equator), near enough for the trees' distances */
|
|
8
|
-
const METRES_PER_DEGREE = 111320;
|
|
19
|
+
export const METRES_PER_DEGREE = 111320;
|
|
20
|
+
/** The ground under the camera: east and north metres from the view's center, and its distance from it (the camera
|
|
21
|
+
* stands behind the center of a tilted view, `FOV` its field of view) */
|
|
22
|
+
export const groundUnderCamera = (map) => {
|
|
23
|
+
const { pitch, bearing } = map.getCamera();
|
|
24
|
+
const back = ((0.5 * map.getCanvas().clientHeight) / Math.tan(FOV / 2)) *
|
|
25
|
+
Math.sin((pitch * Math.PI) / 180) *
|
|
26
|
+
(map.metersPerPixel() ?? 0);
|
|
27
|
+
return [-back * Math.sin((bearing * Math.PI) / 180), -back * Math.cos((bearing * Math.PI) / 180), back];
|
|
28
|
+
};
|
|
29
|
+
/** What follows the camera as it moves: `send` called again once it has gone `RESEND_SHARE` of `radius` metres (or
|
|
30
|
+
* turned or zoomed as much), not at every frame of a drag */
|
|
31
|
+
export const followWhenMoved = (map, radius, send) => {
|
|
32
|
+
/** The view of the last call: center (metres), zoom, bearing, pitch */
|
|
33
|
+
let sent;
|
|
34
|
+
return () => {
|
|
35
|
+
const { center, zoom, bearing, pitch } = map.getCamera();
|
|
36
|
+
const [x, y] = [
|
|
37
|
+
center[0] * METRES_PER_DEGREE * Math.cos((center[1] * Math.PI) / 180),
|
|
38
|
+
center[1] * METRES_PER_DEGREE,
|
|
39
|
+
];
|
|
40
|
+
if (sent &&
|
|
41
|
+
Math.hypot(x - sent[0], y - sent[1]) < RESEND_SHARE * radius(zoom) &&
|
|
42
|
+
Math.abs(zoom - sent[2]) < RESEND_SHARE &&
|
|
43
|
+
Math.abs(bearing - sent[3]) < 45 * RESEND_SHARE &&
|
|
44
|
+
Math.abs(pitch - sent[4]) < 45 * RESEND_SHARE)
|
|
45
|
+
return;
|
|
46
|
+
sent = [x, y, zoom, bearing, pitch];
|
|
47
|
+
send();
|
|
48
|
+
};
|
|
49
|
+
};
|
|
9
50
|
export const trees = (context, options = {}) => {
|
|
10
51
|
const { map } = context;
|
|
11
52
|
const { layers = isWoodland, spacing = treeSpacing, minZoom = STREET_ZOOM, maxTiles = 9, maxTrees = 30000, maxInstances = 25000, } = options;
|
|
53
|
+
const own = options.url !== undefined || options.data !== undefined;
|
|
12
54
|
const model = options.url ? { url: options.url } : { data: options.data ?? treeModel(options.colors) };
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
55
|
+
const before = options.before ? { before: options.before } : {};
|
|
56
|
+
const layer = map.addModels({ ...model, instances: [], ...before });
|
|
57
|
+
const add = (data) => map.addModels({ data, instances: [], ...before });
|
|
58
|
+
// The other kinds and the simplified trees far away on layers of their own, with it: conifers near, the broadleaved
|
|
59
|
+
// and the conifers far away (a model of the page's: every tree, in full)
|
|
60
|
+
const others = own
|
|
61
|
+
? undefined
|
|
62
|
+
: {
|
|
63
|
+
conifers: add(coniferModel(options.colors)),
|
|
64
|
+
farBroadleaved: add(treeModel(options.colors, true)),
|
|
65
|
+
farConifers: add(coniferModel(options.colors, true)),
|
|
66
|
+
};
|
|
67
|
+
if (others)
|
|
68
|
+
layer.companions.push(others.conifers, others.farBroadleaved, others.farConifers);
|
|
18
69
|
const renderer = context.renderer((l) => l.type === 'fill' && layers(l), []);
|
|
19
70
|
renderer.catch(() => undefined);
|
|
20
71
|
context.layers.push(layer);
|
|
21
72
|
/** The tiles held or asked for, by key, and the trees of those that came */
|
|
22
73
|
const requests = new TileRequests();
|
|
23
74
|
const found = new Map();
|
|
24
|
-
/** The trees drawn to the engine (longitude, latitude, altitude, heading, pitch, roll, scale each): all of them
|
|
25
|
-
* near the
|
|
75
|
+
/** The trees drawn to the engine (longitude, latitude, altitude, heading, pitch, roll, scale each): all of them in
|
|
76
|
+
* full near the camera (as far as `TREES_NEAR_METRES` past the view's center), at most `maxInstances`; past `near`
|
|
77
|
+
* metres, simplified, those of a rank under
|
|
78
|
+
* `FAR_DENSITY` (near / distance)², at most `FAR_INSTANCES` times as many (a model of the page's: thinned as the
|
|
79
|
+
* full ones would be, none simplified) */
|
|
26
80
|
const send = () => {
|
|
27
81
|
const { center, zoom } = map.getCamera();
|
|
28
|
-
const near = TREES_NEAR_METRES * 2 ** (16 - zoom);
|
|
29
82
|
const cos = Math.cos((center[1] * Math.PI) / 180);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
83
|
+
// The trees near the ground under the camera in full, as far as some way past the center
|
|
84
|
+
const [ex, ey, back] = groundUnderCamera(map);
|
|
85
|
+
const near = TREES_NEAR_METRES * 2 ** (16 - zoom) + back;
|
|
86
|
+
const density = others ? FAR_DENSITY : 1;
|
|
87
|
+
/** Each tree of the tiles that may be drawn: in full (near, or every one with a model of the page's) or
|
|
88
|
+
* simplified, with its score (the lowest kept first) */
|
|
89
|
+
const visit = (each) => {
|
|
90
|
+
found.forEach((t) => {
|
|
91
|
+
for (let i = 0; i < t.length / TREE_NUMBERS; i += 1) {
|
|
92
|
+
const dx = ((t[i * TREE_NUMBERS] ?? 0) - center[0]) * METRES_PER_DEGREE * cos - ex;
|
|
93
|
+
const dy = ((t[i * TREE_NUMBERS + 1] ?? 0) - center[1]) * METRES_PER_DEGREE - ey;
|
|
94
|
+
const distance = (dx * dx + dy * dy) / (near * near);
|
|
95
|
+
const rank = t[i * TREE_NUMBERS + 4] ?? 0;
|
|
96
|
+
if (distance <= 1)
|
|
97
|
+
each(t, i, true, rank);
|
|
98
|
+
else if (rank * (distance / density) < 1)
|
|
99
|
+
each(t, i, !others, rank * (distance / density));
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
// How many would be drawn: past a cap, the score kept lowered in proportion (the ranks are even, no sort needed)
|
|
104
|
+
let [fullCount, farCount] = [0, 0];
|
|
105
|
+
visit((_, __, full) => {
|
|
106
|
+
if (full)
|
|
107
|
+
fullCount += 1;
|
|
108
|
+
else
|
|
109
|
+
farCount += 1;
|
|
40
110
|
});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
111
|
+
const limits = [
|
|
112
|
+
Math.min(1, maxInstances / Math.max(fullCount, 1)),
|
|
113
|
+
Math.min(1, (maxInstances * FAR_INSTANCES) / Math.max(farCount, 1)),
|
|
114
|
+
];
|
|
115
|
+
// The engine's numbers (longitude, latitude, altitude, heading, pitch, roll, scale): broadleaved and conifers in
|
|
116
|
+
// full, then simplified
|
|
117
|
+
const out = [[], [], [], []];
|
|
118
|
+
visit((t, i, full, score) => {
|
|
119
|
+
if (score >= (limits[full ? 0 : 1] ?? 1))
|
|
120
|
+
return;
|
|
45
121
|
const at = i * TREE_NUMBERS;
|
|
46
|
-
|
|
122
|
+
const conifer = others && t[at + 5] === 1 ? 1 : 0;
|
|
123
|
+
out[(full ? 0 : 2) + conifer]?.push(t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1);
|
|
47
124
|
});
|
|
48
|
-
|
|
125
|
+
const none = new Float64Array();
|
|
126
|
+
const [broadleaved = none, conifers = none, farBroadleaved = none, farConifers = none] = out.map((o) => Float64Array.from(o));
|
|
127
|
+
layer.setInstanceNumbers(broadleaved);
|
|
128
|
+
if (others) {
|
|
129
|
+
others.conifers.setInstanceNumbers(conifers);
|
|
130
|
+
others.farBroadleaved.setInstanceNumbers(farBroadleaved);
|
|
131
|
+
others.farConifers.setInstanceNumbers(farConifers);
|
|
132
|
+
}
|
|
49
133
|
};
|
|
50
134
|
const update = async () => {
|
|
51
135
|
if (context.destroyed())
|
|
@@ -86,8 +170,9 @@ export const trees = (context, options = {}) => {
|
|
|
86
170
|
});
|
|
87
171
|
});
|
|
88
172
|
};
|
|
89
|
-
// While the camera moves, the trees drawn follow
|
|
90
|
-
|
|
173
|
+
// While the camera moves, the trees drawn follow it (dense near it), chosen again once it has gone far enough
|
|
174
|
+
const follow = followWhenMoved(map, (zoom) => TREES_NEAR_METRES * 2 ** (16 - zoom), send);
|
|
175
|
+
context.followView(update, requests, follow);
|
|
91
176
|
return layer;
|
|
92
177
|
};
|
|
93
178
|
//# sourceMappingURL=trees.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trees.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/trees.ts"],"names":[],"mappings":"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","sourcesContent":["/** The trees of a vector basemap (`VectorTiles.trees`): 3D models scattered by the workers over its woods and grass */\n\nimport type { Layer, ModelLayer } from '../../layers/layers.ts';\nimport type { BasemapWork } from '../../workers/basemap.worker.ts';\nimport { isWoodland, TREE_NUMBERS, type TreeColors, treeModel, treeSpacing } from '../trees.ts';\nimport type { StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { TileRequests } from './requests.ts';\nimport { nearPriority, STREET_ZOOM, tileKey, tilesAround } from './tiles.ts';\n\n/** Metres around the view's center where every tree is drawn at zoom 16 (twice as far a zoom level out) */\nconst TREES_NEAR_METRES = 350;\n\n/** Metres in a degree of latitude (and of longitude at the equator), near enough for the trees' distances */\nconst METRES_PER_DEGREE = 111320;\n\n/** The options of `VectorTiles.trees` */\nexport interface TreesOptions {\n layers?: (layer: StyleLayer) => boolean;\n spacing?: number | ((layer: StyleLayer) => number);\n minZoom?: number;\n maxTiles?: number;\n maxTrees?: number;\n maxInstances?: number;\n colors?: Partial<TreeColors>;\n url?: string;\n data?: ArrayBuffer | ArrayBufferView<ArrayBuffer>;\n before?: Layer;\n}\n\nexport const trees = (context: VectorTilesContext, options: TreesOptions = {}): ModelLayer => {\n const { map } = context;\n const {\n layers = isWoodland,\n spacing = treeSpacing,\n minZoom = STREET_ZOOM,\n maxTiles = 9,\n maxTrees = 30000,\n maxInstances = 25000,\n } = options;\n const model = options.url ? { url: options.url } : { data: options.data ?? treeModel(options.colors) };\n const layer = map.addModels({\n ...model,\n instances: [],\n ...(options.before ? { before: options.before } : {}),\n });\n const renderer = context.renderer((l) => l.type === 'fill' && layers(l), []);\n\n renderer.catch(() => undefined);\n context.layers.push(layer);\n\n /** The tiles held or asked for, by key, and the trees of those that came */\n const requests = new TileRequests();\n const found = new Map<string, Float64Array>();\n /** The trees drawn to the engine (longitude, latitude, altitude, heading, pitch, roll, scale each): all of them\n * near the view's center, past `near` metres those of a rank under (near / distance)², at most `maxInstances` */\n const send = () => {\n const { center, zoom } = map.getCamera();\n const near = TREES_NEAR_METRES * 2 ** (16 - zoom);\n const cos = Math.cos((center[1] * Math.PI) / 180);\n const chosen: [score: number, tile: Float64Array, i: number][] = [];\n\n found.forEach((t) => {\n for (let i = 0; i < t.length / TREE_NUMBERS; i += 1) {\n const dx = ((t[i * TREE_NUMBERS] ?? 0) - center[0]) * METRES_PER_DEGREE * cos;\n const dy = ((t[i * TREE_NUMBERS + 1] ?? 0) - center[1]) * METRES_PER_DEGREE;\n const far = (dx * dx + dy * dy) / (near * near);\n const score = (t[i * TREE_NUMBERS + 4] ?? 0) * Math.max(1, far);\n\n if (score < 1) chosen.push([score, t, i]);\n }\n });\n if (chosen.length > maxInstances) chosen.sort((a, b) => a[0] - b[0]).splice(maxInstances);\n\n const out = new Float64Array(chosen.length * 7);\n\n chosen.forEach(([, t, i], k) => {\n const at = i * TREE_NUMBERS;\n\n out.set([t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1], k * 7);\n });\n layer.setInstanceNumbers(out);\n };\n const update = async () => {\n if (context.destroyed()) return;\n\n const { key, maxzoom, layers: list } = await renderer;\n const camera = map.getCamera();\n const z = maxzoom;\n const wanted = camera.zoom < minZoom ? [] : tilesAround(map, camera, z, maxTiles);\n const keys = new Set(wanted.map(([x, y]) => tileKey(z, x, y)));\n const metres = list.map((l) => (typeof spacing === 'number' ? spacing : spacing(l)));\n const dropped = requests.keys().filter((k) => !keys.has(k));\n\n // Out of view: dropped, or no longer asked for\n dropped.forEach((k) => {\n requests.drop(k);\n found.delete(k);\n });\n // Dense around the new center\n send();\n wanted.forEach(([x, y], index) => {\n const k = tileKey(z, x, y);\n\n if (requests.has(k)) return;\n\n const work: BasemapWork = {\n type: 'trees',\n key,\n z,\n x,\n y,\n spacing: metres,\n maxTrees,\n priority: nearPriority(index),\n };\n\n requests.ask(\n k,\n (signal) => context.request(z, x, y, work, signal),\n (r) => {\n if (!('trees' in r)) return;\n found.set(k, r.trees);\n send();\n },\n );\n });\n };\n // While the camera moves, the trees drawn follow its center (dense near it)\n context.followView(update, requests, send);\n\n return layer;\n};\n"]}
|
|
1
|
+
{"version":3,"file":"trees.js","sourceRoot":"","sources":["../../../src/basemap/vectortiles/trees.ts"],"names":[],"mappings":"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","sourcesContent":["/** The trees of a vector basemap (`VectorTiles.trees`): 3D models scattered by the workers over its woods and grass */\n\nimport type { Layer, ModelLayer } from '../../layers/layers.ts';\nimport type { GeoMap } from '../../map.ts';\nimport type { BasemapWork } from '../../workers/basemap.worker.ts';\nimport { coniferModel, isWoodland, TREE_NUMBERS, type TreeColors, treeModel, treeSpacing } from '../trees.ts';\nimport type { StyleLayer } from '../vectorstyle.ts';\nimport type { VectorTilesContext } from './context.ts';\nimport { TileRequests } from './requests.ts';\nimport { nearPriority, STREET_ZOOM, tileKey, tilesAround } from './tiles.ts';\n\n/** Metres around the view's center where every tree is drawn in full at zoom 16 (twice as far a zoom level out);\n * past them, simplified (`treeModel(…, true)`) */\nconst TREES_NEAR_METRES = 350;\n\n/** The engine's vertical field of view (radians, `camera::FOV`): where the camera stands behind the view's center */\nconst FOV = 0.6435011087932844;\n\n/** How much denser the simplified trees far away stay than the full ones would (four times fewer triangles each): a\n * tree twice as far kept as often */\nconst FAR_DENSITY = 4;\n\n/** The simplified trees drawn at most, for so many full ones (`maxInstances`) */\nconst FAR_INSTANCES = 3;\n\n/** While the camera moves, the trees chosen again once it has gone this share of the full trees' radius (or turned\n * or zoomed as much): going through the tiles' trees at every frame of a drag would hold the main thread */\nconst RESEND_SHARE = 0.05;\n\n/** Metres in a degree of latitude (and of longitude at the equator), near enough for the trees' distances */\nexport const METRES_PER_DEGREE = 111320;\n\n/** The options of `VectorTiles.trees` */\nexport interface TreesOptions {\n layers?: (layer: StyleLayer) => boolean;\n spacing?: number | ((layer: StyleLayer) => number);\n minZoom?: number;\n maxTiles?: number;\n maxTrees?: number;\n maxInstances?: number;\n colors?: Partial<TreeColors>;\n url?: string;\n data?: ArrayBuffer | ArrayBufferView<ArrayBuffer>;\n before?: Layer;\n}\n\n/** The ground under the camera: east and north metres from the view's center, and its distance from it (the camera\n * stands behind the center of a tilted view, `FOV` its field of view) */\nexport const groundUnderCamera = (map: GeoMap): [east: number, north: number, distance: number] => {\n const { pitch, bearing } = map.getCamera();\n const back =\n ((0.5 * map.getCanvas().clientHeight) / Math.tan(FOV / 2)) *\n Math.sin((pitch * Math.PI) / 180) *\n (map.metersPerPixel() ?? 0);\n\n return [-back * Math.sin((bearing * Math.PI) / 180), -back * Math.cos((bearing * Math.PI) / 180), back];\n};\n\n/** What follows the camera as it moves: `send` called again once it has gone `RESEND_SHARE` of `radius` metres (or\n * turned or zoomed as much), not at every frame of a drag */\nexport const followWhenMoved = (map: GeoMap, radius: (zoom: number) => number, send: () => void): (() => void) => {\n /** The view of the last call: center (metres), zoom, bearing, pitch */\n let sent: [number, number, number, number, number] | undefined;\n\n return () => {\n const { center, zoom, bearing, pitch } = map.getCamera();\n const [x, y] = [\n center[0] * METRES_PER_DEGREE * Math.cos((center[1] * Math.PI) / 180),\n center[1] * METRES_PER_DEGREE,\n ];\n\n if (\n sent &&\n Math.hypot(x - sent[0], y - sent[1]) < RESEND_SHARE * radius(zoom) &&\n Math.abs(zoom - sent[2]) < RESEND_SHARE &&\n Math.abs(bearing - sent[3]) < 45 * RESEND_SHARE &&\n Math.abs(pitch - sent[4]) < 45 * RESEND_SHARE\n )\n return;\n sent = [x, y, zoom, bearing, pitch];\n send();\n };\n};\n\nexport const trees = (context: VectorTilesContext, options: TreesOptions = {}): ModelLayer => {\n const { map } = context;\n const {\n layers = isWoodland,\n spacing = treeSpacing,\n minZoom = STREET_ZOOM,\n maxTiles = 9,\n maxTrees = 30000,\n maxInstances = 25000,\n } = options;\n const own = options.url !== undefined || options.data !== undefined;\n const model = options.url ? { url: options.url } : { data: options.data ?? treeModel(options.colors) };\n const before = options.before ? { before: options.before } : {};\n const layer = map.addModels({ ...model, instances: [], ...before });\n const add = (data: Uint8Array<ArrayBuffer>) => map.addModels({ data, instances: [], ...before });\n // The other kinds and the simplified trees far away on layers of their own, with it: conifers near, the broadleaved\n // and the conifers far away (a model of the page's: every tree, in full)\n const others = own\n ? undefined\n : {\n conifers: add(coniferModel(options.colors)),\n farBroadleaved: add(treeModel(options.colors, true)),\n farConifers: add(coniferModel(options.colors, true)),\n };\n\n if (others) layer.companions.push(others.conifers, others.farBroadleaved, others.farConifers);\n const renderer = context.renderer((l) => l.type === 'fill' && layers(l), []);\n\n renderer.catch(() => undefined);\n context.layers.push(layer);\n\n /** The tiles held or asked for, by key, and the trees of those that came */\n const requests = new TileRequests();\n const found = new Map<string, Float64Array>();\n /** The trees drawn to the engine (longitude, latitude, altitude, heading, pitch, roll, scale each): all of them in\n * full near the camera (as far as `TREES_NEAR_METRES` past the view's center), at most `maxInstances`; past `near`\n * metres, simplified, those of a rank under\n * `FAR_DENSITY` (near / distance)², at most `FAR_INSTANCES` times as many (a model of the page's: thinned as the\n * full ones would be, none simplified) */\n const send = () => {\n const { center, zoom } = map.getCamera();\n const cos = Math.cos((center[1] * Math.PI) / 180);\n // The trees near the ground under the camera in full, as far as some way past the center\n const [ex, ey, back] = groundUnderCamera(map);\n const near = TREES_NEAR_METRES * 2 ** (16 - zoom) + back;\n const density = others ? FAR_DENSITY : 1;\n /** Each tree of the tiles that may be drawn: in full (near, or every one with a model of the page's) or\n * simplified, with its score (the lowest kept first) */\n const visit = (each: (t: Float64Array, i: number, full: boolean, score: number) => void) => {\n found.forEach((t) => {\n for (let i = 0; i < t.length / TREE_NUMBERS; i += 1) {\n const dx = ((t[i * TREE_NUMBERS] ?? 0) - center[0]) * METRES_PER_DEGREE * cos - ex;\n const dy = ((t[i * TREE_NUMBERS + 1] ?? 0) - center[1]) * METRES_PER_DEGREE - ey;\n const distance = (dx * dx + dy * dy) / (near * near);\n const rank = t[i * TREE_NUMBERS + 4] ?? 0;\n\n if (distance <= 1) each(t, i, true, rank);\n else if (rank * (distance / density) < 1) each(t, i, !others, rank * (distance / density));\n }\n });\n };\n // How many would be drawn: past a cap, the score kept lowered in proportion (the ranks are even, no sort needed)\n let [fullCount, farCount] = [0, 0];\n\n visit((_, __, full) => {\n if (full) fullCount += 1;\n else farCount += 1;\n });\n\n const limits = [\n Math.min(1, maxInstances / Math.max(fullCount, 1)),\n Math.min(1, (maxInstances * FAR_INSTANCES) / Math.max(farCount, 1)),\n ];\n // The engine's numbers (longitude, latitude, altitude, heading, pitch, roll, scale): broadleaved and conifers in\n // full, then simplified\n const out: number[][] = [[], [], [], []];\n\n visit((t, i, full, score) => {\n if (score >= (limits[full ? 0 : 1] ?? 1)) return;\n\n const at = i * TREE_NUMBERS;\n const conifer = others && t[at + 5] === 1 ? 1 : 0;\n\n out[(full ? 0 : 2) + conifer]?.push(t[at] ?? 0, t[at + 1] ?? 0, 0, t[at + 3] ?? 0, 0, 0, t[at + 2] ?? 1);\n });\n\n const none = new Float64Array();\n const [broadleaved = none, conifers = none, farBroadleaved = none, farConifers = none] = out.map((o) =>\n Float64Array.from(o),\n );\n\n layer.setInstanceNumbers(broadleaved);\n if (others) {\n others.conifers.setInstanceNumbers(conifers);\n others.farBroadleaved.setInstanceNumbers(farBroadleaved);\n others.farConifers.setInstanceNumbers(farConifers);\n }\n };\n const update = async () => {\n if (context.destroyed()) return;\n\n const { key, maxzoom, layers: list } = await renderer;\n const camera = map.getCamera();\n const z = maxzoom;\n const wanted = camera.zoom < minZoom ? [] : tilesAround(map, camera, z, maxTiles);\n const keys = new Set(wanted.map(([x, y]) => tileKey(z, x, y)));\n const metres = list.map((l) => (typeof spacing === 'number' ? spacing : spacing(l)));\n const dropped = requests.keys().filter((k) => !keys.has(k));\n\n // Out of view: dropped, or no longer asked for\n dropped.forEach((k) => {\n requests.drop(k);\n found.delete(k);\n });\n // Dense around the new center\n send();\n wanted.forEach(([x, y], index) => {\n const k = tileKey(z, x, y);\n\n if (requests.has(k)) return;\n\n const work: BasemapWork = {\n type: 'trees',\n key,\n z,\n x,\n y,\n spacing: metres,\n maxTrees,\n priority: nearPriority(index),\n };\n\n requests.ask(\n k,\n (signal) => context.request(z, x, y, work, signal),\n (r) => {\n if (!('trees' in r)) return;\n found.set(k, r.trees);\n send();\n },\n );\n });\n };\n // While the camera moves, the trees drawn follow it (dense near it), chosen again once it has gone far enough\n const follow = followWhenMoved(map, (zoom) => TREES_NEAR_METRES * 2 ** (16 - zoom), send);\n\n context.followView(update, requests, follow);\n\n return layer;\n};\n"]}
|