leaflet-city-mapper 0.0.7 → 0.0.8
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/README.md +2 -2
- package/cucumber.mjs +1 -3
- package/dist/leaflet-city-mapper-src.js +403 -201
- package/dist/leaflet-city-mapper-src.js.map +4 -4
- package/dist/leaflet-city-mapper-worker-src.js +69 -59
- package/dist/leaflet-city-mapper-worker-src.js.map +3 -3
- package/dist/leaflet-city-mapper-worker.js +1 -1
- package/dist/leaflet-city-mapper-worker.js.map +4 -4
- package/dist/leaflet-city-mapper.js +5 -5
- package/dist/leaflet-city-mapper.js.map +4 -4
- package/libs/leaflet-lens.js +44 -27
- package/libs/leaflet.js +4 -4
- package/libs/openlayers-bindings.js +2 -1
- package/libs/openlayers-bindings.min.js +1 -1
- package/libs/openlayers-bindings.min.js.map +3 -3
- package/package.json +2 -2
- package/src/camera/mapCamera.js +7 -7
- package/src/camera/mapTryAnimatedPan.js +4 -4
- package/src/camera/updateMapCamera.js +8 -6
- package/src/controls/cameraControls.js +27 -22
- package/src/core/cameraCircleBounds.js +2 -1
- package/src/core/closestCameraLayerPoint.js +2 -1
- package/src/core/constructLayer.js +9 -0
- package/src/core/extendLeafletClass.js +5 -0
- package/src/core/extendTerrainPixelBounds.js +31 -0
- package/src/core/gridlayerGetTiledPixelBounds.js +2 -27
- package/src/core/layerAddInitHook.js +7 -0
- package/src/core/layerCallInitHooks.js +13 -13
- package/src/core/layerMergeOptions.js +7 -0
- package/src/core/projectNativePath.js +23 -0
- package/src/geometry/circleGeometry.js +4 -3
- package/src/globals/layerControlAddItem.js +3 -0
- package/src/globals/leafletLayer.js +3 -0
- package/src/globals/workerCogSource.js +1 -1
- package/src/gpu/initializeRendererResources.js +10 -12
- package/src/index.js +26 -11
- package/src/layer-controls/layerControlInputId.js +11 -0
- package/src/layer-controls/placeEntry.js +2 -0
- package/src/materials/createProgram.js +7 -6
- package/src/native/gridTerrainElevation.js +7 -11
- package/src/native/nativeTerrainElevation.js +16 -0
- package/src/native/prepareGridTerrainRequests.js +16 -0
- package/src/native/retainGridTerrain.js +10 -0
- package/src/native/syncGridLayer.js +12 -59
- package/src/native/syncGridTile.js +18 -0
- package/src/native/syncTerrainGridTile.js +28 -0
- package/src/rendering/drawGeometry.js +11 -11
- package/src/rendering/resizeRenderer.js +16 -15
- package/src/scene/initializerFor.js +2 -1
- package/src/scene/layerInitialize.js +1 -1
- package/src/shadows/drawShadowMeshes.js +6 -5
- package/src/sources/pumpSourceAreas.js +1 -1
- package/src/sunlight/initSunlight.js +19 -8
- package/src/textures/nativeTextureFor.js +2 -3
- package/src/textures/uploadCanvasTexture.js +11 -2
- package/src/vector-tiles/createVectorLabel.js +22 -0
- package/src/vector-tiles/prepareVectorLabel.js +17 -35
- package/src/vector-tiles/updateVectorLabelStyle.js +8 -0
- package/src/vector-tiles/vectorLabelCells.js +2 -5
- package/src/vector-tiles/vectorLabelIcon.js +1 -1
- package/src/vector-tiles/vectorLabelText.js +10 -0
- package/src/walk/initWalk.js +19 -6
- package/src/weakmaps/pathProjectionByMap.js +1 -0
- package/src/workers/cogWorker.js +4 -5
- package/src/globals/layerCallInitHooks.js +0 -1
|
@@ -33,17 +33,19 @@ export function updateMapCamera(layer, size) {
|
|
|
33
33
|
const targetZ = (size.y / 2 - origin.y) / pixelsPerMeter;
|
|
34
34
|
const pitch = mapGetPitch(map) * radians;
|
|
35
35
|
const bearing = mapGetBearing(map) * radians;
|
|
36
|
+
const sinPitch = Math.sin(pitch), cosPitch = Math.cos(pitch);
|
|
37
|
+
const sinBearing = Math.sin(bearing), cosBearing = Math.cos(bearing);
|
|
36
38
|
const camera = cameraByLayer.get(layer);
|
|
37
39
|
camera.fov = cameraFov;
|
|
38
40
|
camera.aspect = size.x / size.y;
|
|
39
41
|
camera.near = Math.max(0.1, distance / 10000);
|
|
40
42
|
camera.far = Math.max(10000, distance * 10);
|
|
41
|
-
camera.position[0] = targetX +
|
|
42
|
-
camera.position[1] = targetY +
|
|
43
|
-
camera.position[2] = targetZ +
|
|
44
|
-
camera.up[0] = -
|
|
45
|
-
camera.up[1] =
|
|
46
|
-
camera.up[2] = -
|
|
43
|
+
camera.position[0] = targetX + sinBearing * sinPitch * distance;
|
|
44
|
+
camera.position[1] = targetY + cosPitch * distance;
|
|
45
|
+
camera.position[2] = targetZ + cosBearing * sinPitch * distance;
|
|
46
|
+
camera.up[0] = -sinBearing * cosPitch;
|
|
47
|
+
camera.up[1] = sinPitch;
|
|
48
|
+
camera.up[2] = -cosBearing * cosPitch;
|
|
47
49
|
camera.target[0] = targetX; camera.target[1] = targetY; camera.target[2] = targetZ;
|
|
48
50
|
// Refresh the camera view, projection and combined projection-view matrices.
|
|
49
51
|
updateCamera(camera);
|
|
@@ -36,37 +36,42 @@ import { changeCameraTouch } from './changeCameraTouch.js';
|
|
|
36
36
|
import { cleanupCameraTouch } from './cleanupCameraTouch.js';
|
|
37
37
|
import { endAllCameraTouches } from './endAllCameraTouches.js';
|
|
38
38
|
import { addCameraHandler } from './addCameraHandler.js';
|
|
39
|
+
import { extendLeafletClass } from '../core/extendLeafletClass.js';
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
41
|
+
class CompassHandler extends extendLeafletClass(L.Handler) {}
|
|
42
|
+
Object.assign(CompassHandler.prototype, { addHooks: compassAddHooks, removeHooks: compassRemoveHooks });
|
|
43
|
+
Compass.value = CompassHandler;
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
removeHooks: containerResizeRemoveHooks,
|
|
45
|
+
class ContainerResizeHandler extends extendLeafletClass(L.Handler) {}
|
|
46
|
+
Object.assign(ContainerResizeHandler.prototype, {
|
|
47
|
+
addHooks: containerResizeAddHooks, removeHooks: containerResizeRemoveHooks,
|
|
48
48
|
});
|
|
49
|
+
ContainerResize.value = ContainerResizeHandler;
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
});
|
|
51
|
+
class PitchDragHandler extends extendLeafletClass(L.Handler) {}
|
|
52
|
+
Object.assign(PitchDragHandler.prototype, { addHooks: pitchDragAddHooks, removeHooks: pitchDragRemoveHooks });
|
|
53
|
+
PitchDrag.value = PitchDragHandler;
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
removeHooks: shiftRotateRemoveHooks,
|
|
55
|
+
class ShiftRotateHandler extends extendLeafletClass(L.Handler) {}
|
|
56
|
+
Object.assign(ShiftRotateHandler.prototype, {
|
|
57
|
+
addHooks: shiftRotateAddHooks, removeHooks: shiftRotateRemoveHooks,
|
|
58
58
|
});
|
|
59
|
+
ShiftRotate.value = ShiftRotateHandler;
|
|
59
60
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
removeHooks: notifyCameraTouchChange,
|
|
61
|
+
class TouchModeHandler extends extendLeafletClass(L.Handler) {}
|
|
62
|
+
Object.assign(TouchModeHandler.prototype, {
|
|
63
|
+
addHooks: notifyCameraTouchChange, removeHooks: notifyCameraTouchChange,
|
|
63
64
|
});
|
|
65
|
+
TouchMode.value = TouchModeHandler;
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
class RotateControl extends extendLeafletClass(L.Control) {
|
|
68
|
+
static defaultOptions = { position: 'topleft', closeOnZeroBearing: true, visualizePitch: true };
|
|
69
|
+
}
|
|
70
|
+
Object.assign(RotateControl.prototype, { onAdd: rotateOnAdd, onRemove: rotateOnRemove });
|
|
71
|
+
if (L.version.startsWith('1.')) {
|
|
72
|
+
RotateControl.prototype.options = Object.assign(Object.create(L.Control.prototype.options), RotateControl.defaultOptions);
|
|
73
|
+
}
|
|
74
|
+
L.Control.Rotate = RotateControl;
|
|
70
75
|
|
|
71
76
|
if (L.control) L.control.rotate = rotateControl;
|
|
72
77
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { boundsMethods } from '../weakmaps/boundsMethods.js';
|
|
2
|
+
import { projectNativePath } from './projectNativePath.js';
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
export function cameraCircleBounds() {
|
|
5
|
-
this.
|
|
6
|
+
if (this._map) projectNativePath(this);
|
|
6
7
|
return boundsMethods.get(this).call(this);
|
|
7
8
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { closestMethods } from '../weakmaps/closestMethods.js';
|
|
2
|
+
import { projectNativePath } from './projectNativePath.js';
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
export function closestCameraLayerPoint(point) {
|
|
5
|
-
this
|
|
6
|
+
projectNativePath(this);
|
|
6
7
|
this._parts = this._rings;
|
|
7
8
|
return closestMethods.get(this).call(this, point);
|
|
8
9
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { leafletLayer } from '../globals/leafletLayer.js';
|
|
2
|
+
import { layerInitialize } from '../scene/layerInitialize.js';
|
|
3
|
+
|
|
4
|
+
export function constructLayer(options) {
|
|
5
|
+
const layer = Reflect.construct(leafletLayer, /* alloc */ [], new.target);
|
|
6
|
+
layerInitialize.call(layer, options);
|
|
7
|
+
layer.callInitHooks();
|
|
8
|
+
return layer;
|
|
9
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { cameraViewByMap } from '../weakmaps/cameraViewByMap.js';
|
|
2
|
+
import { mapMethods } from '../globals/mapMethods.js';
|
|
3
|
+
import { radians } from '../globals/radians.js';
|
|
4
|
+
import { earthCirc } from '../globals/earthCirc.js';
|
|
5
|
+
import { mapElevationOf } from '../terrain/mapElevationOf.js';
|
|
6
|
+
import { groundBounds } from '../projections/groundBounds.js';
|
|
7
|
+
import { animationPoint } from '../projections/transformZoomAnimationPoint.js';
|
|
8
|
+
|
|
9
|
+
export function extendTerrainPixelBounds(layer, result, stream, origin) {
|
|
10
|
+
const map = layer._map;
|
|
11
|
+
let minimum = Infinity, maximum = -Infinity, key, entry;
|
|
12
|
+
for ([key, entry] of stream.terrainCache) {
|
|
13
|
+
if (!key.startsWith(`${layer._tileZoom}/`) || !entry.range) continue;
|
|
14
|
+
minimum = Math.min(minimum, entry.range[0]);
|
|
15
|
+
maximum = Math.max(maximum, entry.range[1]);
|
|
16
|
+
}
|
|
17
|
+
if (!Number.isFinite(minimum) || !Number.isFinite(maximum)) return result;
|
|
18
|
+
const zoom = cameraViewByMap.get(map)?.zoom ?? map.getZoom();
|
|
19
|
+
const scale = map.options.crs.scale(zoom) / (earthCirc * Math.cos(origin.lat * radians));
|
|
20
|
+
const target = mapElevationOf(map, map.getCenter()) ?? 0;
|
|
21
|
+
let i, j, footprint, point, raw;
|
|
22
|
+
for (i = 0; i < 2; i++) {
|
|
23
|
+
footprint = groundBounds(map, undefined, ((i ? maximum : minimum) - target) * scale);
|
|
24
|
+
for (j = 0; j < 2; j++) {
|
|
25
|
+
point = j ? footprint.max : footprint.min;
|
|
26
|
+
raw = mapMethods.value.containerPointToLayerPoint.call(map, animationPoint(map, point, true));
|
|
27
|
+
result.extend(map.project(map.layerPointToLatLng(raw), layer._tileZoom));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
@@ -6,13 +6,7 @@ import { mapGetPitch } from '../camera/mapGetPitch.js';
|
|
|
6
6
|
import { streamTerrainByMap } from '../weakmaps/streamTerrainByMap.js';
|
|
7
7
|
import { renderers } from '../weakmaps/renderers.js';
|
|
8
8
|
import { sceneOriginByLayer } from '../weakmaps/sceneOriginByLayer.js';
|
|
9
|
-
import {
|
|
10
|
-
import { mapMethods } from '../globals/mapMethods.js';
|
|
11
|
-
import { radians } from '../globals/radians.js';
|
|
12
|
-
import { earthCirc } from '../globals/earthCirc.js';
|
|
13
|
-
import { mapElevationOf } from '../terrain/mapElevationOf.js';
|
|
14
|
-
import { groundBounds } from '../projections/groundBounds.js';
|
|
15
|
-
import { animationPoint } from '../projections/transformZoomAnimationPoint.js';
|
|
9
|
+
import { extendTerrainPixelBounds } from './extendTerrainPixelBounds.js';
|
|
16
10
|
|
|
17
11
|
export function gridlayerGetTiledPixelBounds(center) {
|
|
18
12
|
const map = this._map, stream = streamTerrainByMap.get(map);
|
|
@@ -22,24 +16,5 @@ export function gridlayerGetTiledPixelBounds(center) {
|
|
|
22
16
|
map.project(bounds.getSouthEast(), this._tileZoom));
|
|
23
17
|
const shared = renderers.get(map), origin = shared && sceneOriginByLayer.get(shared);
|
|
24
18
|
if (!stream || !origin) return result;
|
|
25
|
-
|
|
26
|
-
for ([key, entry] of stream.terrainCache) {
|
|
27
|
-
if (!key.startsWith(`${this._tileZoom}/`) || !entry.range) continue;
|
|
28
|
-
minimum = Math.min(minimum, entry.range[0]);
|
|
29
|
-
maximum = Math.max(maximum, entry.range[1]);
|
|
30
|
-
}
|
|
31
|
-
if (!Number.isFinite(minimum) || !Number.isFinite(maximum)) return result;
|
|
32
|
-
const zoom = cameraViewByMap.get(map)?.zoom ?? map.getZoom();
|
|
33
|
-
const scale = map.options.crs.scale(zoom) / (earthCirc * Math.cos(origin.lat * radians));
|
|
34
|
-
const target = mapElevationOf(map, map.getCenter()) ?? 0;
|
|
35
|
-
let i, j, footprint, point, raw;
|
|
36
|
-
for (i = 0; i < 2; i++) {
|
|
37
|
-
footprint = groundBounds(map, undefined, ((i ? maximum : minimum) - target) * scale);
|
|
38
|
-
for (j = 0; j < 2; j++) {
|
|
39
|
-
point = j ? footprint.max : footprint.min;
|
|
40
|
-
raw = mapMethods.value.containerPointToLayerPoint.call(map, animationPoint(map, point, true));
|
|
41
|
-
result.extend(map.project(map.layerPointToLatLng(raw), this._tileZoom));
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return result;
|
|
19
|
+
return extendTerrainPixelBounds(this, result, stream, origin);
|
|
45
20
|
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { sceneLayers } from '../weakmaps/sceneLayers.js';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { initializeNativeLayer } from './initializeNativeLayer.js';
|
|
7
|
-
|
|
8
|
-
export function layerCallInitHooks() {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
3
|
+
import { L } from '../globals/L.js';
|
|
4
|
+
import { layerProto } from '../globals/layerProto.js';
|
|
5
|
+
|
|
6
|
+
import { initializeNativeLayer } from './initializeNativeLayer.js';
|
|
7
|
+
|
|
8
|
+
export function layerCallInitHooks() {
|
|
9
|
+
const initialized = this._initHooksCalled;
|
|
10
|
+
if (!L.version.startsWith('2.')) layerProto.value.callInitHooks.call(this);
|
|
11
|
+
if (L.version.startsWith('2.') || !initialized) {
|
|
12
|
+
sceneLayers.add(this);
|
|
13
|
+
initializeNativeLayer.call(this);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { L } from '../globals/L.js';
|
|
2
|
+
import { pathProjectionByMap } from '../weakmaps/pathProjectionByMap.js';
|
|
3
|
+
|
|
4
|
+
export function projectNativePath(source) {
|
|
5
|
+
if (!L.version.startsWith('2.')) return source._project();
|
|
6
|
+
const map = source._map, renderer = source._renderer;
|
|
7
|
+
let projection = pathProjectionByMap.get(map);
|
|
8
|
+
if (!projection) {
|
|
9
|
+
// Leaflet 2 projects against a renderer view, even when no DOM renderer is mounted.
|
|
10
|
+
projection = Object.create(L.Renderer.prototype);
|
|
11
|
+
projection._map = map;
|
|
12
|
+
pathProjectionByMap.set(map, projection);
|
|
13
|
+
}
|
|
14
|
+
projection._pathZoom = map.getZoom();
|
|
15
|
+
projection._pathOrigin = map.getPixelOrigin();
|
|
16
|
+
source._renderer = projection;
|
|
17
|
+
try {
|
|
18
|
+
source._project();
|
|
19
|
+
} finally {
|
|
20
|
+
if (renderer) source._renderer = renderer;
|
|
21
|
+
else delete source._renderer;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -3,18 +3,19 @@ import { disk } from './disk.js';
|
|
|
3
3
|
import { circleAt } from './circleAt.js';
|
|
4
4
|
import { line } from './line.js';
|
|
5
5
|
import { triangle } from './appendNativeTriangle.js';
|
|
6
|
+
import { projectNativePath } from '../core/projectNativePath.js';
|
|
6
7
|
|
|
7
8
|
export function circleGeometry(source, context) {
|
|
8
9
|
const { map, point, fill, stroke, options, dash, width } = context;
|
|
9
10
|
const center = map.project(source.getLatLng());
|
|
10
11
|
let radius = source.getRadius(), radiusY = radius, index, i;
|
|
11
12
|
if (source instanceof L.Circle) {
|
|
12
|
-
source
|
|
13
|
+
projectNativePath(source);
|
|
13
14
|
const projected = source._point.add(map.getPixelOrigin());
|
|
14
15
|
center.x = projected.x;
|
|
15
16
|
center.y = projected.y;
|
|
16
|
-
radius = source._radius;
|
|
17
|
-
radiusY = source._radiusY
|
|
17
|
+
radius = source._pxRadius ?? source._radius;
|
|
18
|
+
radiusY = source._pxRadiusY ?? source._radiusY ?? radius;
|
|
18
19
|
}
|
|
19
20
|
if (options.fill) disk(point, center, radius, fill, radiusY);
|
|
20
21
|
const count = Math.max(12, Math.min(128, Math.ceil(Math.PI * Math.sqrt(Math.max(radius, radiusY)))));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const workerCogSource =
|
|
1
|
+
export const workerCogSource = new Map();
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { rendererByLayer } from '../weakmaps/rendererByLayer.js';
|
|
2
|
-
|
|
1
|
+
import { rendererByLayer } from '../weakmaps/rendererByLayer.js';
|
|
2
|
+
|
|
3
3
|
import { sceneSunlightUniforms } from '../globals/sceneSunlightUniforms.js';
|
|
4
4
|
import { resizeSunlight } from '../shadows/resizeSunlight.js';
|
|
5
5
|
|
|
6
6
|
export function initializeRendererResources(layer, device) {
|
|
7
|
+
const renderer = rendererByLayer.get(layer);
|
|
7
8
|
const layout = device.createBindGroupLayout(/* alloc */ {
|
|
8
9
|
entries: /* alloc */ [
|
|
9
10
|
/* alloc */ { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: /* alloc */ { type: 'uniform' } },
|
|
@@ -12,16 +13,13 @@ export function initializeRendererResources(layer, device) {
|
|
|
12
13
|
/* alloc */ { binding: 3, visibility: GPUShaderStage.FRAGMENT, buffer: /* alloc */ { type: 'read-only-storage' } },
|
|
13
14
|
]
|
|
14
15
|
});
|
|
15
|
-
const buffer =
|
|
16
|
-
const sampler =
|
|
17
|
-
const lights =
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
const buffer = device.createBuffer(/* alloc */ { size: 80, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
17
|
+
const sampler = device.createSampler(/* alloc */ { compare: 'less-equal', minFilter: 'linear', magFilter: 'linear' });
|
|
18
|
+
const lights = device.createBuffer(/* alloc */ { size: 32, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST });
|
|
19
|
+
renderer.sunlight = /* alloc */ { layout, buffer, sampler, lights, size: 0 };
|
|
20
|
+
device.queue.writeBuffer(buffer, 0, sceneSunlightUniforms);
|
|
20
21
|
resizeSunlight(layer, 1);
|
|
21
|
-
|
|
22
|
-
emptyImage.width = 1;
|
|
23
|
-
emptyImage.height = 1;
|
|
24
|
-
rendererByLayer.get(layer).roofFallbackTexture = /* alloc */ {
|
|
22
|
+
renderer.roofFallbackTexture = /* alloc */ {
|
|
25
23
|
device,
|
|
26
24
|
texture: device.createTexture(/* alloc */ {
|
|
27
25
|
size: /* alloc */ [1, 1],
|
|
@@ -31,6 +29,6 @@ export function initializeRendererResources(layer, device) {
|
|
|
31
29
|
sampler: device.createSampler(/* alloc */ {
|
|
32
30
|
addressModeU: 'clamp-to-edge', addressModeV: 'clamp-to-edge',
|
|
33
31
|
}),
|
|
34
|
-
image:
|
|
32
|
+
image: null, format: 'rgba8unorm', srgb: false, uploaded: null,
|
|
35
33
|
};
|
|
36
34
|
}
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { L } from './globals/L.js';
|
|
2
2
|
import { layerProto } from './globals/layerProto.js';
|
|
3
|
-
import { layerCallInitHooks as sharedLayerCallInitHooks } from './globals/layerCallInitHooks.js';
|
|
4
3
|
import { removeLayer as sharedRemoveLayer } from './globals/removeLayer.js';
|
|
5
4
|
|
|
6
5
|
import './camera/mapCamera.js';
|
|
@@ -16,6 +15,10 @@ import { setPitch } from './camera/setPitch.js';
|
|
|
16
15
|
import { setBearing } from './camera/setBearing.js';
|
|
17
16
|
import { setRotation } from './core/setRotation.js';
|
|
18
17
|
import { layerCallInitHooks } from './core/layerCallInitHooks.js';
|
|
18
|
+
import { leafletLayer } from './globals/leafletLayer.js';
|
|
19
|
+
import { constructLayer } from './core/constructLayer.js';
|
|
20
|
+
import { layerAddInitHook } from './core/layerAddInitHook.js';
|
|
21
|
+
import { layerMergeOptions } from './core/layerMergeOptions.js';
|
|
19
22
|
|
|
20
23
|
/**
|
|
21
24
|
* `new L.Layer({ source: { type, url, ...settings }, pane, attribution })`: layers with a `source`
|
|
@@ -37,8 +40,26 @@ import { layerCallInitHooks } from './core/layerCallInitHooks.js';
|
|
|
37
40
|
* When `type` is omitted, *.pmtiles and *.tif/*.tiff URLs use 'raster'; other sources use 'vector'.
|
|
38
41
|
*/
|
|
39
42
|
|
|
40
|
-
layerProto.value = Object.defineProperties({}, Object.getOwnPropertyDescriptors(
|
|
41
|
-
|
|
43
|
+
layerProto.value = Object.defineProperties({}, Object.getOwnPropertyDescriptors(leafletLayer.prototype));
|
|
44
|
+
layerProto.value._layerAdd = leafletLayer.prototype._layerAdd;
|
|
45
|
+
layerProto.value.callInitHooks = leafletLayer.prototype.callInitHooks;
|
|
46
|
+
|
|
47
|
+
if (L.version.startsWith('2.')) {
|
|
48
|
+
// Keep the native prototype and instanceof contract, but finish options before init hooks.
|
|
49
|
+
Object.setPrototypeOf(constructLayer, leafletLayer);
|
|
50
|
+
constructLayer.prototype = leafletLayer.prototype;
|
|
51
|
+
constructLayer.initHooks = true;
|
|
52
|
+
constructLayer.addInitHook = layerAddInitHook;
|
|
53
|
+
constructLayer.mergeOptions = layerMergeOptions;
|
|
54
|
+
L.Layer = constructLayer;
|
|
55
|
+
leafletLayer.prototype.constructor = L.Layer;
|
|
56
|
+
leafletLayer.addInitHook(layerCallInitHooks);
|
|
57
|
+
} else {
|
|
58
|
+
leafletLayer.prototype.initialize = layerInitialize;
|
|
59
|
+
leafletLayer.prototype.callInitHooks = layerCallInitHooks;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
Object.assign(leafletLayer.prototype, { _layerAdd: layerLayerAdd });
|
|
42
63
|
|
|
43
64
|
/**
|
|
44
65
|
* The 'vector' layer type: native WebGPU scene synchronized with the map camera.
|
|
@@ -95,12 +116,6 @@ sharedLayerCallInitHooks.value = L.Layer.prototype.callInitHooks;
|
|
|
95
116
|
* @param {Layer3DOptions} [options] World origin comes from center or the first map centre.
|
|
96
117
|
*/
|
|
97
118
|
|
|
98
|
-
L.Layer.include({
|
|
99
|
-
initialize: layerInitialize,
|
|
100
|
-
_layerAdd: layerLayerAdd,
|
|
101
|
-
callInitHooks: layerCallInitHooks,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
119
|
sharedRemoveLayer.value = L.Map.prototype.removeLayer;
|
|
105
|
-
L.Map.
|
|
106
|
-
L.Marker.
|
|
120
|
+
Object.assign(L.Map.prototype, { removeLayer, getPitch, getBearing, setPitch, setBearing });
|
|
121
|
+
Object.assign(L.Marker.prototype, { setRotation });
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { L } from '../globals/L.js';
|
|
2
|
+
import { layerControlAddItem } from '../globals/layerControlAddItem.js';
|
|
3
|
+
|
|
4
|
+
// Leaflet 2 stores layer associations on its control, not on the input.
|
|
5
|
+
if (layerControlAddItem && !L.Control.Layers) L.LayersControl.prototype._addItem = addLayerControlInputId;
|
|
6
|
+
|
|
7
|
+
export function addLayerControlInputId(entry) {
|
|
8
|
+
const label = layerControlAddItem.call(this, entry);
|
|
9
|
+
label.querySelector('.leaflet-control-layers-selector').layerId = L.Util.stamp(entry.layer);
|
|
10
|
+
return label;
|
|
11
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { L } from '../globals/L.js';
|
|
2
2
|
import { placeEntryElement } from './placeEntryElement.js';
|
|
3
|
+
import './layerControlInputId.js';
|
|
4
|
+
|
|
3
5
|
export function placeEntry(map, layer, element) {
|
|
4
6
|
let input, entry;
|
|
5
7
|
for (input of map.getContainer().querySelectorAll('.leaflet-control-layers-selector')) {
|
|
@@ -19,17 +19,18 @@ import { materialShaders } from '../shaders/materialShaders.js';
|
|
|
19
19
|
import { reportCompilation } from '../gpu/reportShaderCompilation.js';
|
|
20
20
|
|
|
21
21
|
export function createProgram(layer, material = defaultMaterial) {
|
|
22
|
+
const renderer = rendererByLayer.get(layer), { device } = renderer;
|
|
22
23
|
const shaders = materialShaders(
|
|
23
24
|
material,
|
|
24
25
|
!!layer.options.nightSparkle,
|
|
25
26
|
material.terrain ? elevationWGSL : ''
|
|
26
27
|
);
|
|
27
|
-
const vertex =
|
|
28
|
+
const vertex = device.createShaderModule((
|
|
28
29
|
vertexShader.code = shaders.vertex,
|
|
29
30
|
vertexShader
|
|
30
31
|
));
|
|
31
32
|
vertexShader.code = null;
|
|
32
|
-
const fragment =
|
|
33
|
+
const fragment = device.createShaderModule((
|
|
33
34
|
fragmentShader.code = shaders.fragment,
|
|
34
35
|
fragmentShader
|
|
35
36
|
));
|
|
@@ -45,17 +46,17 @@ export function createProgram(layer, material = defaultMaterial) {
|
|
|
45
46
|
shaders.textured ? uVLayout : null,
|
|
46
47
|
];
|
|
47
48
|
if (material.instanced) vertexBuffers.push(instanceLayout);
|
|
48
|
-
const bindGroupLayout = createProgramLayout(
|
|
49
|
-
const pipelineLayout =
|
|
49
|
+
const bindGroupLayout = createProgramLayout(device, shaders);
|
|
50
|
+
const pipelineLayout = device.createPipelineLayout((
|
|
50
51
|
sharedPipelineLayout.bindGroupLayouts[0] = bindGroupLayout,
|
|
51
|
-
sharedPipelineLayout.bindGroupLayouts[1] =
|
|
52
|
+
sharedPipelineLayout.bindGroupLayouts[1] = renderer.sunlight.layout,
|
|
52
53
|
sharedPipelineLayout
|
|
53
54
|
));
|
|
54
55
|
sharedPipelineLayout.bindGroupLayouts[0] = null;
|
|
55
56
|
sharedPipelineLayout.bindGroupLayouts[1] = null;
|
|
56
57
|
const uniforms = createProgramUniforms(material);
|
|
57
58
|
return /* alloc */ {
|
|
58
|
-
device
|
|
59
|
+
device,
|
|
59
60
|
vertex,
|
|
60
61
|
fragment,
|
|
61
62
|
bindings: shaders.bindings,
|
|
@@ -1,23 +1,19 @@
|
|
|
1
1
|
import { terrainElevation } from '../terrain/terrainElevation.js';
|
|
2
|
-
import {
|
|
2
|
+
import { nativeTerrainElevation } from './nativeTerrainElevation.js';
|
|
3
3
|
|
|
4
4
|
export function gridTerrainElevation(state, location) {
|
|
5
5
|
let z = Math.max(0, Math.min(24, Math.round(state.map.getZoom())));
|
|
6
6
|
const tiles = /* alloc */ new Map();
|
|
7
|
-
let point, limit, x, y, dx, dy, tx, ty, entry, elevation
|
|
7
|
+
let point, limit, x, y, index, dx, dy, tx, ty, entry, elevation;
|
|
8
8
|
for (; z >= 0; z--) {
|
|
9
9
|
point = state.map.project(location, z), limit = 2 ** z;
|
|
10
10
|
x = Math.floor(point.x / 256), y = Math.floor(point.y / 256);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (native?.disposed || native?.terrainStream !== state) continue;
|
|
14
|
-
request = native.terrainRequests?.get(`${x}:${y}:${z}`);
|
|
15
|
-
if (!request?.tiles || layer._tiles[`${x}:${y}:${z}`] !== request.tile) continue;
|
|
16
|
-
elevation = terrainElevation(point, request.tiles);
|
|
17
|
-
if (Number.isFinite(elevation)) return elevation;
|
|
18
|
-
}
|
|
11
|
+
elevation = nativeTerrainElevation(state, point, x, y, z);
|
|
12
|
+
if (Number.isFinite(elevation)) return elevation;
|
|
19
13
|
tiles.clear();
|
|
20
|
-
for (
|
|
14
|
+
for (index = 0; index < 9; index++) {
|
|
15
|
+
dx = index % 3 - 1;
|
|
16
|
+
dy = Math.floor(index / 3) - 1;
|
|
21
17
|
tx = ((x + dx) % limit + limit) % limit;
|
|
22
18
|
ty = Math.max(0, Math.min(limit - 1, y + dy));
|
|
23
19
|
entry = state.terrainCache.get(`${z}/${tx}/${ty}`);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { terrainElevation } from '../terrain/terrainElevation.js';
|
|
2
|
+
import { nativeGPUByLayer } from '../weakmaps/nativeGPUByLayer.js';
|
|
3
|
+
|
|
4
|
+
export function nativeTerrainElevation(state, point, x, y, z) {
|
|
5
|
+
let layer, native, request, elevation;
|
|
6
|
+
const key = `${x}:${y}:${z}`;
|
|
7
|
+
for (layer of Object.values(state.map._layers)) {
|
|
8
|
+
native = nativeGPUByLayer.get(layer);
|
|
9
|
+
if (native?.disposed || native?.terrainStream !== state) continue;
|
|
10
|
+
request = native.terrainRequests?.get(key);
|
|
11
|
+
if (!request?.tiles || layer._tiles[key] !== request.tile) continue;
|
|
12
|
+
elevation = terrainElevation(point, request.tiles);
|
|
13
|
+
if (Number.isFinite(elevation)) return elevation;
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { streamTerrainByMap } from '../weakmaps/streamTerrainByMap.js';
|
|
2
|
+
|
|
3
|
+
export function prepareGridTerrainRequests(state) {
|
|
4
|
+
const stream = streamTerrainByMap.get(state.map);
|
|
5
|
+
if (state.terrainStream !== stream) {
|
|
6
|
+
state.terrainStream = stream;
|
|
7
|
+
state.terrainRequests = stream ? /* alloc */ new Map() : null;
|
|
8
|
+
}
|
|
9
|
+
if (state.terrainRequests) {
|
|
10
|
+
let key;
|
|
11
|
+
for (key of state.terrainRequests.keys()) {
|
|
12
|
+
if (!state.source._tiles[key]) state.terrainRequests.delete(key);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return stream;
|
|
16
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function retainGridTerrain(state) {
|
|
2
|
+
let key, mesh, retained;
|
|
3
|
+
for ([key, mesh] of state.meshes) {
|
|
4
|
+
if (state.source._tiles[key] || !mesh._terrainRequest) continue;
|
|
5
|
+
retained = state.textures.get(key);
|
|
6
|
+
if (!retained) continue;
|
|
7
|
+
retained.used = true;
|
|
8
|
+
mesh._nativeUsed = true;
|
|
9
|
+
}
|
|
10
|
+
}
|