leaflet-city-mapper 0.0.5 → 0.0.7

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.
Files changed (261) hide show
  1. package/README.md +10 -5
  2. package/dist/leaflet-city-mapper-src.js +6874 -6304
  3. package/dist/leaflet-city-mapper-src.js.map +4 -4
  4. package/dist/leaflet-city-mapper-worker-src.js +2766 -0
  5. package/dist/leaflet-city-mapper-worker-src.js.map +4 -4
  6. package/dist/leaflet-city-mapper-worker.js +1 -1
  7. package/dist/leaflet-city-mapper-worker.js.map +4 -4
  8. package/dist/leaflet-city-mapper.js +5 -3
  9. package/dist/leaflet-city-mapper.js.map +4 -4
  10. package/libs/leaflet-lens.js +15 -3
  11. package/libs/leaflet.js +1 -1
  12. package/package.json +1 -1
  13. package/src/camera/setBearing.js +5 -0
  14. package/src/camera/setPitch.js +5 -0
  15. package/src/cog/initCog.js +2 -2
  16. package/src/collision/collectIntersections.js +16 -0
  17. package/src/collision/collider.js +3 -2
  18. package/src/collision/countCrossings.js +15 -0
  19. package/src/collision/insideMesh.js +4 -24
  20. package/src/collision/insideWalker.js +2 -2
  21. package/src/collision/readTriangle.js +7 -4
  22. package/src/collision/setTrafficNormal.js +9 -0
  23. package/src/collision/trafficCollision.js +4 -9
  24. package/src/collision/vertexCount.js +3 -0
  25. package/src/controls/cameraControls.js +6 -0
  26. package/src/core/gridlayerGetTiledPixelBounds.js +37 -4
  27. package/src/core/markerSetPos.js +1 -1
  28. package/src/core/popupGetEvents.js +1 -1
  29. package/src/core/popupUpdatePosition.js +8 -8
  30. package/src/core/tooltipGetEvents.js +1 -1
  31. package/src/core/tooltipSetPosition.js +2 -2
  32. package/src/geometry/appendNativeTriangle.js +2 -2
  33. package/src/geometry/createModelGeometry.js +2 -9
  34. package/src/geometry/dashedSegment.js +10 -5
  35. package/src/geometry/disk.js +1 -1
  36. package/src/geometry/fillNativePolygon.js +20 -0
  37. package/src/geometry/lineJoin.js +2 -2
  38. package/src/geometry/markerQuadCorners.js +6 -0
  39. package/src/geometry/nativeGeometry.js +1 -1
  40. package/src/geometry/polygon.js +4 -10
  41. package/src/geometry/segment.js +4 -3
  42. package/src/globals/colorTexture.js +6 -0
  43. package/src/globals/depthTexture.js +1 -0
  44. package/src/globals/drawMeshEntry.js +1 -1
  45. package/src/globals/meshPipeline.js +1 -0
  46. package/src/globals/mvtTextDecoder.js +1 -0
  47. package/src/globals/nativeScalableStyleKeys.js +1 -0
  48. package/src/globals/scenePass.js +1 -0
  49. package/src/globals/vectorStyleNamedColors.js +8 -0
  50. package/src/globals/vectorTileEvents.js +1 -0
  51. package/src/globals/workerCogSource.js +1 -0
  52. package/src/gpu/mountRenderer.js +4 -11
  53. package/src/gpu/releaseRenderer.js +1 -0
  54. package/src/index.js +6 -12
  55. package/src/materials/createProgramUniforms.js +1 -0
  56. package/src/models/loadModel.js +6 -10
  57. package/src/models/loadModelResources.js +2 -8
  58. package/src/models/modelNode.js +3 -7
  59. package/src/models/prepareModel.js +19 -0
  60. package/src/models/prepareModelGeometry.js +25 -0
  61. package/src/models/prepareModelPrimitive.js +17 -0
  62. package/src/mvt/addMvtCrossings.js +17 -0
  63. package/src/mvt/appendMvtBandTriangles.js +31 -0
  64. package/src/mvt/appendMvtCoordinates.js +11 -0
  65. package/src/mvt/appendMvtPolygonTriangles.js +19 -0
  66. package/src/mvt/beginMvtPath.js +9 -0
  67. package/src/mvt/closeMvtPath.js +7 -0
  68. package/src/mvt/collectMvtEdges.js +19 -0
  69. package/src/mvt/createMvtReader.js +7 -0
  70. package/src/mvt/decodeVectorTile.js +32 -0
  71. package/src/mvt/expectMvtWire.js +3 -0
  72. package/src/mvt/finishMvtPath.js +5 -0
  73. package/src/mvt/finiteMvtCoordinate.js +7 -0
  74. package/src/mvt/groupMvtPolygons.js +25 -0
  75. package/src/mvt/isMvtFallbackError.js +6 -0
  76. package/src/mvt/mergeMvtActiveEdges.js +9 -0
  77. package/src/mvt/mvtEdgeX.js +4 -0
  78. package/src/mvt/mvtPathsVertices.js +8 -0
  79. package/src/mvt/mvtPolygonPaths.js +12 -0
  80. package/src/mvt/numericMvtValue.js +4 -0
  81. package/src/mvt/readMvtFeature.js +34 -0
  82. package/src/mvt/readMvtField.js +8 -0
  83. package/src/mvt/readMvtGeometry.js +29 -0
  84. package/src/mvt/readMvtInteger.js +12 -0
  85. package/src/mvt/readMvtKnownValue.js +21 -0
  86. package/src/mvt/readMvtLayer.js +31 -0
  87. package/src/mvt/readMvtMessage.js +10 -0
  88. package/src/mvt/readMvtNumber.js +9 -0
  89. package/src/mvt/readMvtNumbers.js +11 -0
  90. package/src/mvt/readMvtString.js +6 -0
  91. package/src/mvt/readMvtValue.js +19 -0
  92. package/src/mvt/skipMvtField.js +14 -0
  93. package/src/mvt/sortMvtActiveEdges.js +15 -0
  94. package/src/mvt/sortedMvtLevels.js +22 -0
  95. package/src/mvt/takeMvtBytes.js +8 -0
  96. package/src/mvt/tessellateVectorRings.js +19 -0
  97. package/src/mvt/triangulateVectorRings.js +19 -0
  98. package/src/native/beforeNativeRender.js +6 -0
  99. package/src/native/canScaleNativeStyle.js +17 -0
  100. package/src/native/createNativeMesh.js +31 -0
  101. package/src/native/disposeNativeLayer.js +1 -1
  102. package/src/native/getGridTerrainTile.js +34 -0
  103. package/src/native/gridTerrainElevation.js +30 -0
  104. package/src/native/loadGridTerrain.js +26 -0
  105. package/src/native/nativeLayer.js +2 -2
  106. package/src/native/nativeLayerMethod.js +5 -14
  107. package/src/native/nativeProgram.js +20 -0
  108. package/src/native/nativeVectorGeometry.js +23 -0
  109. package/src/native/orderNativeGridLayer.js +14 -0
  110. package/src/native/putNativeMesh.js +15 -21
  111. package/src/native/refreshNativeEvent.js +13 -2
  112. package/src/native/refreshNativeLayer.js +1 -0
  113. package/src/native/syncGridLayer.js +48 -3
  114. package/src/native/syncNativeStrokeAnchors.js +12 -0
  115. package/src/native/syncNativeStrokeZoom.js +29 -0
  116. package/src/native/syncVectorLayer.js +15 -13
  117. package/src/native/terrainGridMesh.js +34 -0
  118. package/src/native/updateNativeStrokeRadius.js +9 -0
  119. package/src/projections/displayContainerPoint.js +23 -3
  120. package/src/projections/groundBounds.js +2 -2
  121. package/src/projections/localPixel.js +7 -2
  122. package/src/projections/localPixelForGeometry.js +4 -2
  123. package/src/projections/projectCameraPoint.js +6 -5
  124. package/src/raster/setRasterOpacity.js +1 -1
  125. package/src/raster/setRasterZIndex.js +1 -1
  126. package/src/rendering/collectVisibleMesh.js +5 -2
  127. package/src/rendering/drawSceneMeshes.js +3 -1
  128. package/src/rendering/nativeStrokeExpansion.js +4 -0
  129. package/src/rendering/prepareMeshUniforms.js +2 -0
  130. package/src/rendering/resizeRenderer.js +9 -0
  131. package/src/scene/initializerFor.js +3 -5
  132. package/src/scene/layerInitialize.js +14 -12
  133. package/src/scene/resolveNextInitialization.js +1 -1
  134. package/src/shaders/materialShaders.js +1 -0
  135. package/src/shaders/materialVertexShader.js +7 -2
  136. package/src/shaders/nativeStrokeShader.js +6 -0
  137. package/src/sources/attachAreaMesh.js +5 -6
  138. package/src/sources/buildArea.js +7 -17
  139. package/src/sources/buildAreaFeature.js +5 -24
  140. package/src/sources/buildAreaFeatures.js +14 -0
  141. package/src/sources/initVectorTiles.js +15 -0
  142. package/src/sources/isVectorTileSource.js +4 -0
  143. package/src/sources/matchesAreaTile.js +7 -0
  144. package/src/sources/prepareAreaGeometryJob.js +2 -11
  145. package/src/sources/projectAreaPolygons.js +15 -0
  146. package/src/sources/readyVectorTiles.js +10 -0
  147. package/src/sources/sourceAreaContext.js +1 -6
  148. package/src/sunlight/createSun.js +0 -1
  149. package/src/terrain/initTerrain.js +7 -1
  150. package/src/terrain/loadTerrain.js +4 -1
  151. package/src/terrain/mapElevationOf.js +5 -1
  152. package/src/terrain/onTerrainAdd.js +11 -1
  153. package/src/terrain/onTerrainRemove.js +10 -1
  154. package/src/utils/yieldTask.js +5 -0
  155. package/src/vector-style/appendQuotedStyleCharacter.js +22 -0
  156. package/src/vector-style/arrayContainsRange.js +8 -0
  157. package/src/vector-style/evaluateBoolean.js +18 -0
  158. package/src/vector-style/evaluateCoalesceOrCase.js +21 -0
  159. package/src/vector-style/evaluateComparison.js +16 -0
  160. package/src/vector-style/evaluateIExpression.js +8 -0
  161. package/src/vector-style/evaluateInput.js +6 -0
  162. package/src/vector-style/evaluateInterpolate.js +27 -0
  163. package/src/vector-style/evaluateMatch.js +12 -0
  164. package/src/vector-style/evaluateMath.js +14 -0
  165. package/src/vector-style/evaluateMembership.js +18 -0
  166. package/src/vector-style/evaluateNegation.js +13 -0
  167. package/src/vector-style/evaluatePrimitive.js +9 -0
  168. package/src/vector-style/evaluateStep.js +11 -0
  169. package/src/vector-style/evaluateStyle.js +33 -0
  170. package/src/vector-style/evaluateToExpression.js +14 -0
  171. package/src/vector-style/fillVectorPaint.js +17 -0
  172. package/src/vector-style/lineVectorPaint.js +21 -0
  173. package/src/vector-style/parseFunctionalColor.js +14 -0
  174. package/src/vector-style/parseHexColor.js +13 -0
  175. package/src/vector-style/parseVectorStyle.js +13 -0
  176. package/src/vector-style/readPaintValue.js +6 -0
  177. package/src/vector-style/removeTrailingCommas.js +12 -0
  178. package/src/vector-style/scaleDashArray.js +13 -0
  179. package/src/vector-style/skipStyleComment.js +9 -0
  180. package/src/vector-style/stripStyleComments.js +21 -0
  181. package/src/vector-style/styleColor.js +11 -0
  182. package/src/vector-style/validateVectorLayers.js +10 -0
  183. package/src/vector-style/vectorPaint.js +8 -0
  184. package/src/vector-style/visibleStyle.js +7 -0
  185. package/src/vector-tiles/appendVectorBatch.js +22 -0
  186. package/src/vector-tiles/attachVectorTileBatch.js +17 -0
  187. package/src/vector-tiles/attachVectorTileBatches.js +15 -0
  188. package/src/vector-tiles/compareVectorLabelPriority.js +3 -0
  189. package/src/vector-tiles/compareVectorTileDistance.js +3 -0
  190. package/src/vector-tiles/configureVectorTileLayer.js +28 -0
  191. package/src/vector-tiles/forwardVectorTileError.js +5 -0
  192. package/src/vector-tiles/loadVectorSprite.js +5 -0
  193. package/src/vector-tiles/loadVectorTile.js +36 -0
  194. package/src/vector-tiles/onVectorTileAdd.js +39 -0
  195. package/src/vector-tiles/onVectorTileMessage.js +10 -0
  196. package/src/vector-tiles/onVectorTileRemove.js +20 -0
  197. package/src/vector-tiles/onVectorTileWorkerError.js +11 -0
  198. package/src/vector-tiles/paintVectorTileBatch.js +12 -0
  199. package/src/vector-tiles/prepareVectorLabel.js +43 -0
  200. package/src/vector-tiles/prepareVectorStyleLayer.js +30 -0
  201. package/src/vector-tiles/prepareVectorTile.js +16 -0
  202. package/src/vector-tiles/projectVectorPaths.js +15 -0
  203. package/src/vector-tiles/projectVectorPoint.js +6 -0
  204. package/src/vector-tiles/projectVectorTriangles.js +18 -0
  205. package/src/vector-tiles/pruneVectorTiles.js +11 -0
  206. package/src/vector-tiles/pumpVectorTiles.js +18 -0
  207. package/src/vector-tiles/readTileJSON.js +17 -0
  208. package/src/vector-tiles/readVectorStyle.js +17 -0
  209. package/src/vector-tiles/refreshVectorTiles.js +5 -0
  210. package/src/vector-tiles/reserveVectorLabelCells.js +6 -0
  211. package/src/vector-tiles/retireVectorTileGroup.js +13 -0
  212. package/src/vector-tiles/revokeVectorWorkerUrl.js +9 -0
  213. package/src/vector-tiles/rotateVectorLabel.js +12 -0
  214. package/src/vector-tiles/rotateVectorLabels.js +6 -0
  215. package/src/vector-tiles/simplifyVectorPath.js +21 -0
  216. package/src/vector-tiles/updateVectorLabelMarker.js +27 -0
  217. package/src/vector-tiles/updateVectorTileLabels.js +28 -0
  218. package/src/vector-tiles/updateVectorTilePaint.js +20 -0
  219. package/src/vector-tiles/updateVectorTiles.js +29 -0
  220. package/src/vector-tiles/validateVectorTileZooms.js +6 -0
  221. package/src/vector-tiles/vectorFeaturePaint.js +15 -0
  222. package/src/vector-tiles/vectorFeaturePaths.js +16 -0
  223. package/src/vector-tiles/vectorFeatureZoom.js +8 -0
  224. package/src/vector-tiles/vectorLabelAnchors.js +24 -0
  225. package/src/vector-tiles/vectorLabelCandidates.js +11 -0
  226. package/src/vector-tiles/vectorLabelCells.js +26 -0
  227. package/src/vector-tiles/vectorLabelIcon.js +30 -0
  228. package/src/vector-tiles/vectorLabelProperty.js +3 -0
  229. package/src/vector-tiles/vectorSpriteIcon.js +11 -0
  230. package/src/vector-tiles/vectorStraightRun.js +14 -0
  231. package/src/vector-tiles/vectorStyleDependencies.js +15 -0
  232. package/src/vector-tiles/vectorStyleValue.js +5 -0
  233. package/src/vector-tiles/vectorStyleZoom.js +6 -0
  234. package/src/vector-tiles/vectorTileAwaited.js +9 -0
  235. package/src/vector-tiles/vectorTileOverlaps.js +4 -0
  236. package/src/vector-tiles/vectorTilePaint.js +10 -0
  237. package/src/vector-tiles/vectorTileSettings.js +17 -0
  238. package/src/vector-tiles/vectorTilesIdle.js +3 -0
  239. package/src/vector-tiles/vectorTolerance.js +4 -0
  240. package/src/vector-tiles/wrapVectorLabel.js +11 -0
  241. package/src/walk/animateWalker.js +2 -13
  242. package/src/walk/updateWalkerFrame.js +19 -0
  243. package/src/weakmaps/nativeProgramsByRenderer.js +1 -0
  244. package/src/weakmaps/streamTerrainByLayer.js +1 -0
  245. package/src/weakmaps/streamTerrainByMap.js +1 -0
  246. package/src/weakmaps/vectorTileOptionsByLayer.js +1 -0
  247. package/src/weakmaps/vectorWorkerByLayer.js +1 -0
  248. package/src/weakmaps/workerMapByLayer.js +1 -0
  249. package/src/workers/acquireGeometryWorker.js +2 -5
  250. package/src/workers/buildAreaInWorker.js +3 -23
  251. package/src/workers/cogWorker.js +21 -0
  252. package/src/workers/createGeometryWorker.js +20 -0
  253. package/src/workers/geometryWorker.js +15 -0
  254. package/src/workers/getCogInWorker.js +7 -0
  255. package/src/workers/modelWorker.js +10 -0
  256. package/src/workers/openCogInWorker.js +14 -0
  257. package/src/workers/runSourceWorker.js +32 -0
  258. package/src/workers/settleGeometryWorker.js +1 -1
  259. package/src/workers/vectorTileWorker.js +10 -0
  260. package/src/geometry/buildExtrudedPolygon.js +0 -10
  261. package/src/sources/buildAreaPoint.js +0 -7
@@ -1,22 +1,58 @@
1
1
  import { L } from '../globals/L.js';
2
2
  import { coreWhite } from '../globals/coreWhite.js';
3
+ import { streamTerrainByMap } from '../weakmaps/streamTerrainByMap.js';
3
4
 
4
5
  import { styleNativeMesh } from './styleNativeMesh.js';
5
6
  import { quadNativeMesh } from './quadNativeMesh.js';
6
7
  import { boundsQuad } from '../geometry/boundsQuad.js';
8
+ import { loadGridTerrain } from './loadGridTerrain.js';
9
+ import { terrainGridMesh } from './terrainGridMesh.js';
7
10
 
8
11
 
9
12
  export function syncGridLayer(state) {
10
13
  const { source, textures, meshes } = state;
11
- let key, tile, opacity, retained, mesh, nw, se;
14
+ const stream = streamTerrainByMap.get(state.map);
15
+ if (state.terrainStream !== stream) {
16
+ state.terrainStream = stream;
17
+ state.terrainRequests = stream ? /* alloc */ new Map() : null;
18
+ }
19
+ let key, tile, opacity, retained, mesh, nw, se, request, pending = false;
20
+ if (state.terrainRequests) {
21
+ for (key of state.terrainRequests.keys()) {
22
+ if (!source._tiles[key]) state.terrainRequests.delete(key);
23
+ }
24
+ }
12
25
  for (key in source._tiles) {
13
26
  if (!Object.hasOwn(source._tiles, key)) continue;
14
27
  tile = source._tiles[key];
15
- if (!tile.loaded || tile.el instanceof HTMLImageElement && !tile.el.naturalWidth) continue;
28
+ if (!tile.loaded || tile.el instanceof HTMLImageElement && !tile.el.naturalWidth) {
29
+ if (stream) pending = true;
30
+ continue;
31
+ }
16
32
  opacity = (source.options.opacity ?? 1) * (tile._gpuOpacity ?? 1);
17
33
  retained = textures.get(key);
18
34
  mesh = meshes.get(key);
19
- if (mesh && retained?.image === tile.el && retained.url === (tile.el.currentSrc || tile.el.src)) {
35
+ if (state.terrainRequests) {
36
+ request = state.terrainRequests.get(key);
37
+ if (!request || request.tile !== tile) {
38
+ request = /* alloc */ { tile, stream };
39
+ state.terrainRequests.set(key, request);
40
+ loadGridTerrain(state, key, tile, request);
41
+ }
42
+ if (!request.tiles) {
43
+ pending = true;
44
+ if (mesh && retained?.image === tile.el) {
45
+ retained.used = true;
46
+ styleNativeMesh(state, mesh, coreWhite, opacity);
47
+ }
48
+ continue;
49
+ }
50
+ if (mesh && mesh._terrainRequest === request && retained?.image === tile.el &&
51
+ retained.url === (tile.el.currentSrc || tile.el.src)) {
52
+ retained.used = true;
53
+ styleNativeMesh(state, mesh, coreWhite, opacity);
54
+ } else mesh = terrainGridMesh(state, key, tile, request, opacity);
55
+ } else if (mesh && !mesh._terrainRequest && retained?.image === tile.el && retained.url === (tile.el.currentSrc || tile.el.src)) {
20
56
  retained.used = true;
21
57
  styleNativeMesh(state, mesh, coreWhite, opacity);
22
58
  } else {
@@ -26,4 +62,13 @@ export function syncGridLayer(state) {
26
62
  }
27
63
  if (mesh) mesh.renderOrder += tile.coords.z / 100;
28
64
  }
65
+ if (stream && (pending || !Object.keys(source._tiles).length)) {
66
+ for ([key, mesh] of meshes) {
67
+ if (source._tiles[key] || !mesh._terrainRequest) continue;
68
+ retained = textures.get(key);
69
+ if (!retained) continue;
70
+ retained.used = true;
71
+ mesh._nativeUsed = true;
72
+ }
73
+ }
29
74
  }
@@ -0,0 +1,12 @@
1
+ export function syncNativeStrokeAnchors(state, stroke) {
2
+ const { source } = state;
3
+ if (state.strokeAnchors?.length === stroke.length && stroke.length) {
4
+ if (source.options.interactive === false) state.strokeCoordinates = stroke;
5
+ else {
6
+ state.strokeCoordinates = /* alloc */ new Float64Array(stroke);
7
+ state.strokeAnchors = /* alloc */ new Float64Array(state.strokeAnchors);
8
+ }
9
+ state.strokeZoom = state.map.getZoom();
10
+ state.strokeWeight = Number(source.options.weight);
11
+ } else state.strokeAnchors = null;
12
+ }
@@ -0,0 +1,29 @@
1
+ import { styleNativeMesh } from './styleNativeMesh.js';
2
+ import { parseColor } from '../colors/parseColor.js';
3
+
4
+ export function syncNativeStrokeZoom(state) {
5
+ const { source, meshes, strokeCoordinates, strokeAnchors } = state;
6
+ const mesh = meshes.get('stroke');
7
+ let i, r, g, b, fill;
8
+ if (mesh) {
9
+ const factor = 2 ** (state.strokeZoom - state.map.getZoom()) *
10
+ Number(source.options.weight) / state.strokeWeight;
11
+ const attribute = mesh.geometry.attributes.position;
12
+ if (mesh.program.uniforms.strokeScale) {
13
+ mesh.program.uniforms.strokeScale.value = factor;
14
+ } else {
15
+ for (i = 0; i < strokeCoordinates.length; i++) {
16
+ attribute.data[i] = strokeAnchors[i] + (strokeCoordinates[i] - strokeAnchors[i]) * factor;
17
+ }
18
+ attribute.needsUpdate = true;
19
+ mesh.geometry.bounds = null;
20
+ }
21
+ ({ r, g, b } = parseColor(source.options.color));
22
+ styleNativeMesh(state, mesh, /* alloc */ [r, g, b], source.options.opacity ?? 1);
23
+ }
24
+ fill = meshes.get('fill');
25
+ if (fill) {
26
+ ({ r, g, b } = parseColor(source.options.fillColor || source.options.color));
27
+ styleNativeMesh(state, fill, /* alloc */ [r, g, b], source.options.fillOpacity ?? 1);
28
+ }
29
+ }
@@ -1,22 +1,19 @@
1
- import { geometryPixelStates } from '../globals/geometryPixelStates.js';
2
-
3
-
4
- import { nativeGeometry } from '../geometry/nativeGeometry.js';
5
- import { localPixelForGeometry } from '../projections/localPixelForGeometry.js';
6
1
  import { parseColor } from '../colors/parseColor.js';
7
2
  import { putNativeMesh } from './putNativeMesh.js';
3
+ import { syncNativeStrokeZoom } from './syncNativeStrokeZoom.js';
4
+ import { nativeVectorGeometry } from './nativeVectorGeometry.js';
5
+ import { syncNativeStrokeAnchors } from './syncNativeStrokeAnchors.js';
8
6
 
9
7
  export function syncVectorLayer(state) {
10
8
  const { source } = state;
11
- geometryPixelStates.push(state);
12
- let geometry;
13
- try {
14
- geometry = nativeGeometry(source, state.map, localPixelForGeometry);
15
- } finally {
16
- geometryPixelStates.pop();
9
+ if (state.zoomOnly) {
10
+ syncNativeStrokeZoom(state);
11
+ state.zoomOnly = false;
12
+ return;
17
13
  }
18
- const { fill, stroke } = geometry;
19
- let i, key, positions, color, opacity, r, g, b;
14
+ const { fill, stroke } = nativeVectorGeometry(state);
15
+ syncNativeStrokeAnchors(state, stroke);
16
+ let i, key, positions, color, opacity, r, g, b, attributes;
20
17
  for (i = 0; i < 2; i++) {
21
18
  key = i ? 'stroke' : 'fill';
22
19
  positions = i ? stroke : fill;
@@ -25,5 +22,10 @@ export function syncVectorLayer(state) {
25
22
  if (!positions.length) continue;
26
23
  ({ r, g, b } = parseColor(color));
27
24
  putNativeMesh(state, key, positions, /* alloc */ [r, g, b], opacity ?? 1);
25
+ if (key === 'stroke' && source.options.interactive === false && state.strokeCoordinates) {
26
+ attributes = state.meshes.get(key).geometry.attributes;
27
+ state.strokeCoordinates = attributes.position.data;
28
+ state.strokeAnchors = attributes.normal.data;
29
+ }
28
30
  }
29
31
  }
@@ -0,0 +1,34 @@
1
+ import { rootByLayer } from '../weakmaps/rootByLayer.js';
2
+ import { coreWhite } from '../globals/coreWhite.js';
3
+ import { textureFor } from '../textures/nativeTextureFor.js';
4
+ import { terrainElevation } from '../terrain/terrainElevation.js';
5
+ import { localPosition } from '../projections/localPosition.js';
6
+ import { putNativeMesh } from './putNativeMesh.js';
7
+
8
+ export function terrainGridMesh(state, key, tile, request, opacity) {
9
+ const texture = textureFor(state, key, tile.el);
10
+ if (!texture) return;
11
+ const { x, y, z } = tile.coords, divisions = 32;
12
+ const northwest = localPosition(state, state.map.unproject(/* alloc */ [x * 256, y * 256], z));
13
+ const southeast = localPosition(state, state.map.unproject(/* alloc */ [(x + 1) * 256, (y + 1) * 256], z));
14
+ const vertices = /* alloc */ [], position = /* alloc */ [], uv = /* alloc */ [];
15
+ const base = rootByLayer.get(state.backend).position[1];
16
+ let row, col, u, v, elevation, a, b, c, d, index;
17
+ for (row = 0; row <= divisions; row++) for (col = 0; col <= divisions; col++) {
18
+ u = col / divisions; v = row / divisions;
19
+ elevation = terrainElevation(/* alloc */ { x: (x + u) * 256, y: (y + v) * 256 }, request.tiles);
20
+ if (!Number.isFinite(elevation)) throw /* alloc */ new Error(`Missing elevation sample in ${z}/${x}/${y}`);
21
+ vertices.push(/* alloc */ [northwest[0] + (southeast[0] - northwest[0]) * u, elevation - base,
22
+ northwest[2] + (southeast[2] - northwest[2]) * v, u, v]);
23
+ }
24
+ for (row = 0; row < divisions; row++) for (col = 0; col < divisions; col++) {
25
+ a = row * (divisions + 1) + col; b = a + 1; c = a + divisions + 1; d = c + 1;
26
+ for (index of /* alloc */ [a, c, b, b, c, d]) {
27
+ position.push(vertices[index][0], vertices[index][1], vertices[index][2]);
28
+ uv.push(vertices[index][3], vertices[index][4]);
29
+ }
30
+ }
31
+ const mesh = putNativeMesh(state, key, position, coreWhite, opacity, texture, uv, true);
32
+ mesh._terrainRequest = request;
33
+ return mesh;
34
+ }
@@ -0,0 +1,9 @@
1
+ export function updateNativeStrokeRadius(mesh) {
2
+ const attributes = mesh.geometry.attributes, positions = attributes.position.data, anchors = attributes.normal.data;
3
+ let i, radius = 0;
4
+ for (i = 0; i < positions.length; i += 3) {
5
+ radius = Math.max(radius, Math.hypot(positions[i] - anchors[i],
6
+ positions[i + 1] - anchors[i + 1], positions[i + 2] - anchors[i + 2]));
7
+ }
8
+ mesh.geometry.nativeStrokeRadius = radius;
9
+ }
@@ -1,3 +1,23 @@
1
- export function displayPoint(map, point) {
2
- return map.layerPointToContainerPoint(point).subtract(map._getMapPanePos());
3
- }
1
+ import { streamTerrainByMap } from '../weakmaps/streamTerrainByMap.js';
2
+ import { renderers } from '../weakmaps/renderers.js';
3
+ import { sceneOriginByLayer } from '../weakmaps/sceneOriginByLayer.js';
4
+ import { cameraViewByMap } from '../weakmaps/cameraViewByMap.js';
5
+ import { mapMethods } from '../globals/mapMethods.js';
6
+ import { radians } from '../globals/radians.js';
7
+ import { earthCirc } from '../globals/earthCirc.js';
8
+ import { mapElevationOf } from '../terrain/mapElevationOf.js';
9
+ import { animationPoint } from './transformZoomAnimationPoint.js';
10
+ import { project } from './projectCameraPoint.js';
11
+
12
+ export function displayPoint(map, point, location) {
13
+ const shared = renderers.get(map), origin = shared && sceneOriginByLayer.get(shared);
14
+ if (!streamTerrainByMap.get(map) || !origin) {
15
+ return map.layerPointToContainerPoint(point).subtract(map._getMapPanePos());
16
+ }
17
+ const elevation = mapElevationOf(map, location || map.layerPointToLatLng(point)) ?? 0;
18
+ const center = mapElevationOf(map, map.getCenter()) ?? 0;
19
+ const zoom = cameraViewByMap.get(map)?.zoom ?? map.getZoom();
20
+ const height = (elevation - center) * map.options.crs.scale(zoom) / (earthCirc * Math.cos(origin.lat * radians));
21
+ const raw = animationPoint(map, mapMethods.value.layerPointToContainerPoint.call(map, point));
22
+ return project(map, raw, false, false, height).subtract(map._getMapPanePos());
23
+ }
@@ -4,7 +4,7 @@ import { pointOf } from './toPoint.js';
4
4
  import { project } from './projectCameraPoint.js';
5
5
 
6
6
 
7
- export function groundBounds(map, padding = cameraZeroPadding) {
7
+ export function groundBounds(map, padding = cameraZeroPadding, height = 0) {
8
8
  const min = pointOf(padding).divideBy(2), max = map.getSize().subtract(min);
9
9
  const bounds = /* alloc */ new L.Bounds();
10
10
  const minX = min.x, minY = min.y;
@@ -12,7 +12,7 @@ export function groundBounds(map, padding = cameraZeroPadding) {
12
12
  for (i = 0; i < 4; i++) {
13
13
  min.x = i % 2 ? max.x : minX;
14
14
  min.y = i < 2 ? minY : max.y;
15
- bounds.extend(project(map, min, true, true));
15
+ bounds.extend(project(map, min, true, true, height));
16
16
  }
17
17
  return bounds;
18
18
  }
@@ -1,5 +1,10 @@
1
1
  import { localPosition } from './localPosition.js';
2
2
 
3
- export function localPixel(state, point) {
4
- return localPosition(state, state.map.unproject(point));
3
+ export function localPixel(state, point) {
4
+ if (state.pixelProjection) {
5
+ const { transformation, scale, origin, metres } = state.pixelProjection;
6
+ const projected = transformation.untransform(point, scale);
7
+ return /* alloc */ [(projected.x - origin.x) * metres, 0, -(projected.y - origin.y) * metres];
8
+ }
9
+ return localPosition(state, state.map.unproject(point));
5
10
  }
@@ -2,6 +2,8 @@ import { geometryPixelStates } from '../globals/geometryPixelStates.js';
2
2
 
3
3
  import { localPixel } from './localPixel.js';
4
4
 
5
- export function localPixelForGeometry(point) {
6
- return localPixel(geometryPixelStates[geometryPixelStates.length - 1], point);
5
+ export function localPixelForGeometry(point, anchor) {
6
+ const state = geometryPixelStates[geometryPixelStates.length - 1];
7
+ if (anchor && state.strokeAnchors) state.strokeAnchors.push(...localPixel(state, anchor));
8
+ return localPixel(state, point);
7
9
  }
@@ -3,7 +3,7 @@ import { pointOf } from './toPoint.js';
3
3
  import { angles } from './cameraAngles.js';
4
4
 
5
5
 
6
- export function project(map, point, inverse = false, limit = false) {
6
+ export function project(map, point, inverse = false, limit = false, height = 0) {
7
7
  const size = map.getSize(), halfX = size.x / 2, halfY = size.y / 2, distance = size.y * 1.5;
8
8
  const result = pointOf(point);
9
9
  if (!distance) return result;
@@ -12,16 +12,17 @@ export function project(map, point, inverse = false, limit = false) {
12
12
  if (inverse) {
13
13
  const far = size.y * map.options.pitchMaxDistance;
14
14
  const denominator = tilt * distance + rise * y;
15
- let v = denominator * tilt > 0 ? y * distance / denominator : -far;
15
+ let v = denominator * tilt > 0
16
+ ? (y * (distance - tilt * height) + distance * rise * height) / denominator : -far;
16
17
  if (limit) v = Math.max(-far, Math.min(far, v));
17
- const u = x * (distance - rise * v) / distance;
18
+ const u = x * (distance - rise * v - tilt * height) / distance;
18
19
  result.x = cos * u + sin * v + halfX;
19
20
  result.y = -sin * u + cos * v + halfY;
20
21
  return result;
21
22
  }
22
23
  const u = cos * x - sin * y, v = sin * x + cos * y;
23
- const scale = distance / (distance - rise * v);
24
+ const scale = distance / (distance - rise * v - tilt * height);
24
25
  result.x = u * scale + halfX;
25
- result.y = tilt * v * scale + halfY;
26
+ result.y = (tilt * v - rise * height) * scale + halfY;
26
27
  return result;
27
28
  }
@@ -9,7 +9,7 @@ export function setRasterOpacity(layer, opacity) {
9
9
  let tile, terrainMesh;
10
10
  for (tile of rasterTilesByLayer.get(layer).values()) {
11
11
  if (tile.mesh) tile.mesh.opacity = opacity;
12
- terrainMesh = rasterTilesByLayer.get(terrain3DByLayer.get(layer)).get(tile);
12
+ terrainMesh = rasterTilesByLayer.get(terrain3DByLayer.get(layer))?.get(tile);
13
13
  if (terrainMesh) terrainMesh.opacity = opacity;
14
14
  }
15
15
  update(layer);
@@ -9,7 +9,7 @@ export function setRasterZIndex(layer, zIndex) {
9
9
  let tile, terrainMesh;
10
10
  for (tile of rasterTilesByLayer.get(layer).values()) {
11
11
  if (tile.mesh) tile.mesh.renderOrder = zIndex;
12
- terrainMesh = rasterTilesByLayer.get(terrain3DByLayer.get(layer)).get(tile);
12
+ terrainMesh = rasterTilesByLayer.get(terrain3DByLayer.get(layer))?.get(tile);
13
13
  if (terrainMesh) terrainMesh.renderOrder = zIndex;
14
14
  }
15
15
  update(layer);
@@ -1,4 +1,5 @@
1
1
  import { computeBounds } from '../geometry/computeBounds.js';
2
+ import { nativeStrokeExpansion } from './nativeStrokeExpansion.js';
2
3
 
3
4
  export function collectVisibleMesh(mesh, projection, frustum, frustumLengths, candidates) {
4
5
  if (!mesh.geometry.bounds) computeBounds(mesh.geometry);
@@ -12,16 +13,18 @@ export function collectVisibleMesh(mesh, projection, frustum, frustumLengths, ca
12
13
  sphere.x = world[0] * center[0] + world[4] * center[1] + world[8] * center[2] + world[12];
13
14
  sphere.y = world[1] * center[0] + world[5] * center[1] + world[9] * center[2] + world[13];
14
15
  sphere.z = world[2] * center[0] + world[6] * center[1] + world[10] * center[2] + world[14];
15
- sphere.radius = bounds.radius * Math.max(
16
+ sphere.scale = Math.max(
16
17
  Math.hypot(world[0], world[1], world[2]),
17
18
  Math.hypot(world[4], world[5], world[6]),
18
19
  Math.hypot(world[8], world[9], world[10])
19
20
  );
21
+ sphere.radius = bounds.radius * sphere.scale;
20
22
  sphere.bounds = bounds;
21
23
  sphere.matrix = world;
22
24
  sphere.version = mesh._worldMatrixVersion;
23
25
  }
24
- const { x, y, z, radius } = sphere;
26
+ const { x, y, z } = sphere;
27
+ const radius = sphere.radius + nativeStrokeExpansion(mesh) * sphere.scale;
25
28
  const clipZ = projection[2] * x + projection[6] * y + projection[10] * z + projection[14];
26
29
  const clipW = projection[3] * x + projection[7] * y + projection[11] * z + projection[15];
27
30
  mesh._sortDepth = clipZ / clipW;
@@ -9,11 +9,13 @@ import { drawGeometry } from './drawGeometry.js';
9
9
  export function drawSceneMeshes(layer, encoder, meshes) {
10
10
  const renderer = rendererByLayer.get(layer);
11
11
  const pass = encoder.beginRenderPass((
12
- scenePass.colorAttachments[0].view = renderer.context.getCurrentTexture().createView(),
12
+ scenePass.colorAttachments[0].view = renderer.colorTexture.createView(),
13
+ scenePass.colorAttachments[0].resolveTarget = renderer.context.getCurrentTexture().createView(),
13
14
  scenePass.depthStencilAttachment.view = renderer.depthTexture.createView(),
14
15
  scenePass
15
16
  ));
16
17
  scenePass.colorAttachments[0].view = null;
18
+ scenePass.colorAttachments[0].resolveTarget = null;
17
19
  scenePass.depthStencilAttachment.view = null;
18
20
  pass.setViewport(0, 0, renderer.canvas.width, renderer.canvas.height, 0, 1);
19
21
  pass.setBindGroup(1, renderer.sunlight.bindGroup);
@@ -0,0 +1,4 @@
1
+ export function nativeStrokeExpansion(mesh) {
2
+ const strokeScale = mesh.program?.uniforms?.strokeScale?.value ?? 1;
3
+ return Math.max(0, strokeScale - 1) * (mesh.geometry.nativeStrokeRadius || 0);
4
+ }
@@ -20,6 +20,8 @@ export function prepareMeshUniforms(renderer, mesh) {
20
20
  data[base + 34] = mesh.program.nightSparkle ? data[55] : 0;
21
21
  data[base + 35] = mesh.ground ? 1 : mesh._appearance ?? 1;
22
22
  prepareMeshCutout(renderer, mesh, base);
23
+ data[base + 40] = uniforms.strokeScale?.value ?? 1;
24
+ data[base + 41] = data[base + 42] = data[base + 43] = 0;
23
25
  return offset;
24
26
  }
25
27
  import { prepareMeshCutout } from '../materials/prepareMeshCutout.js';
@@ -2,6 +2,7 @@ import { rendererByLayer } from '../weakmaps/rendererByLayer.js';
2
2
  import { sizeByLayer } from '../weakmaps/sizeByLayer.js';
3
3
 
4
4
  import { depthTexture as sharedDepthTexture } from '../globals/depthTexture.js';
5
+ import { colorTexture as sharedColorTexture } from '../globals/colorTexture.js';
5
6
 
6
7
 
7
8
  import { destroyTexture } from '../textures/destroyTexture.js';
@@ -15,6 +16,14 @@ export function resizeRenderer(layer, size) {
15
16
  rendererByLayer.get(layer).canvas.style.width = `${size.x}px`;
16
17
  rendererByLayer.get(layer).canvas.style.height = `${size.y}px`;
17
18
  if (rendererByLayer.get(layer).depthTexture) destroyTexture(layer, rendererByLayer.get(layer).depthTexture);
19
+ rendererByLayer.get(layer).colorTexture?.destroy();
20
+ rendererByLayer.get(layer).colorTexture = rendererByLayer.get(layer).device.createTexture((
21
+ sharedColorTexture.size[0] = rendererByLayer.get(layer).canvas.width,
22
+ sharedColorTexture.size[1] = rendererByLayer.get(layer).canvas.height,
23
+ sharedColorTexture.format = rendererByLayer.get(layer).format,
24
+ sharedColorTexture.usage = GPUTextureUsage.RENDER_ATTACHMENT,
25
+ sharedColorTexture
26
+ ));
18
27
  rendererByLayer.get(layer).depthTexture = rendererByLayer.get(layer).device.createTexture((
19
28
  sharedDepthTexture.size[0] = rendererByLayer.get(layer).canvas.width,
20
29
  sharedDepthTexture.size[1] = rendererByLayer.get(layer).canvas.height,
@@ -1,14 +1,12 @@
1
- import { initializeGeoJSON } from '../sources/initializeGeoJSON.js';
2
1
  import { initRaster } from '../raster/initRaster.js';
3
2
  import { initTerrain } from '../terrain/initTerrain.js';
4
3
  import { initTraffic } from '../traffic/initTraffic.js';
5
4
  import { initCog } from '../cog/initCog.js';
6
5
 
7
- export function initializerFor(type) {
6
+ export function initializerFor(type, options = {}) {
8
7
  switch (type) {
9
- case 'geojson': return initializeGeoJSON;
10
- case 'pmtiles': return initRaster;
11
- case 'cog': return initCog;
8
+ case 'raster': return options.asset !== undefined || /\.tiff?(?:[?#]|$)/i.test(options.url)
9
+ ? initCog : initRaster;
12
10
  case 'terrain': return initTerrain;
13
11
  case 'traffic': return initTraffic;
14
12
  default: return null;
@@ -12,6 +12,9 @@ import { loading } from '../globals/loading.js';
12
12
 
13
13
 
14
14
  import { init3D } from './init3D.js';
15
+ import { initializeGeoJSON } from '../sources/initializeGeoJSON.js';
16
+ import { isVectorTileSource } from '../sources/isVectorTileSource.js';
17
+ import { initVectorTiles } from '../sources/initVectorTiles.js';
15
18
  import { noOperation } from '../utils/noOperation.js';
16
19
  import { resolveNextInitialization } from './resolveNextInitialization.js';
17
20
  import { initializeLayer } from './initializeLayer.js';
@@ -25,21 +28,20 @@ export function layerInitialize(options = sceneEmptyOptions) {
25
28
  L.Util.setOptions(this, options);
26
29
  return;
27
30
  }
28
- const {
29
- source: {
30
- type = options.source.data?.type === 'FeatureCollection'
31
- ? 'geojson'
32
- : /\.pmtiles(?:[?#]|$)/i.test(options.source.url) ? 'pmtiles'
33
- : /\.tiff?(?:[?#]|$)/i.test(options.source.url) ? 'cog' : '3d',
34
- ...source
35
- },
36
- ...core
37
- } = options;
31
+ const { source: { type = /\.pmtiles(?:[?#]|$)|\.tiff?(?:[?#]|$)/i.test(options.source.url)
32
+ ? 'raster' : 'vector', ...source }, ...core } = options;
38
33
  const settings = /* alloc */ { ...source, ...core };
39
34
  L.Util.setOptions(this, core);
40
35
  typeByLayer.set(this, type);
41
- if (type === '3d') {
42
- init3D(this, settings);
36
+ if (type === 'vector') {
37
+ if (isVectorTileSource(settings)) {
38
+ initVectorTiles(this, settings);
39
+ } else if (settings.data !== undefined ||
40
+ settings.url && !/\.(?:pmtiles|glb|gltf)(?:[?#]|$)/i.test(settings.url)) {
41
+ initializeGeoJSON(this, settings);
42
+ } else {
43
+ init3D(this, settings);
44
+ }
43
45
  return;
44
46
  }
45
47
  kindByLayer.set(this, 'pending');
@@ -5,7 +5,7 @@ import { initializerFor } from './initializerFor.js';
5
5
 
6
6
  export function resolveNextInitialization() {
7
7
  const task = pendingInitializations.shift();
8
- task.initialize = initializerFor(task.type);
8
+ task.initialize = initializerFor(task.type, task.settings);
9
9
  if (!task.initialize) {
10
10
  task.error = /* alloc */ new Error(`Unknown layer type: ${task.type}`);
11
11
  }
@@ -30,6 +30,7 @@ export function materialShaders(material = defaultMaterial, sparkle = false, ele
30
30
  terrain: vec4<f32>,
31
31
  highlight: vec4<f32>,
32
32
  cutout: vec4<f32>,
33
+ nativeStroke: vec4<f32>,
33
34
  };
34
35
  struct Frame {
35
36
  viewMatrix: mat4x4<f32>,
@@ -1,7 +1,9 @@
1
1
  import { roofVertexShader } from './roofVertexShader.js';
2
+ import { nativeStrokeShader } from './nativeStrokeShader.js';
2
3
 
3
4
  export function materialVertexShader(material, sparkle, elevationWGSL, hasTerrain, textured, hasRoof) {
4
5
  const instanceOffset = material.instanced ? ' + input.instanceOffset.xyz' : '';
6
+ const stroke = nativeStrokeShader(material);
5
7
  return /* wgsl */ `
6
8
  struct Mesh {
7
9
  worldMatrix: mat4x4<f32>,
@@ -11,6 +13,7 @@ export function materialVertexShader(material, sparkle, elevationWGSL, hasTerrai
11
13
  terrain: vec4<f32>,
12
14
  highlight: vec4<f32>,
13
15
  cutout: vec4<f32>,
16
+ nativeStroke: vec4<f32>,
14
17
  };
15
18
  struct Frame {
16
19
  viewMatrix: mat4x4<f32>,
@@ -46,6 +49,7 @@ export function materialVertexShader(material, sparkle, elevationWGSL, hasTerrai
46
49
  @vertex fn vertexMain(input: VertexInput, @builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
47
50
  var output: VertexOutput;
48
51
  var position = input.position${instanceOffset};
52
+ ${stroke.position}
49
53
  ${hasTerrain ? 'position.y = elevation(u.terrain.xy + input.uv * u.terrain.z, u.terrain.w) - u.terrain.w;' : ''}
50
54
  let featureVertex = f32(vertexIndex)${material.instanced ? ' + input.instanceOffset.w' : ''};
51
55
  let highlighted = featureVertex >= u.highlight.x && featureVertex < u.highlight.y;
@@ -54,8 +58,9 @@ export function materialVertexShader(material, sparkle, elevationWGSL, hasTerrai
54
58
  : 'u.baseColor.rgb'};
55
59
  // Inverse-transpose from cofactors; the camera view matrix is orthonormal.
56
60
  let m = mat3x3<f32>(u.worldMatrix[0].xyz, u.worldMatrix[1].xyz, u.worldMatrix[2].xyz);
57
- let normal = (cross(m[1], m[2]) * input.normal.x + cross(m[2], m[0]) * input.normal.y +
58
- cross(m[0], m[1]) * input.normal.z) / determinant(m);
61
+ ${stroke.normal}
62
+ let normal = (cross(m[1], m[2]) * sourceNormal.x + cross(m[2], m[0]) * sourceNormal.y +
63
+ cross(m[0], m[1]) * sourceNormal.z) / determinant(m);
59
64
  output.normal = (frame.viewMatrix * vec4<f32>(normal, 0.0)).xyz;
60
65
  let world = u.worldMatrix * vec4<f32>(position, 1.0);
61
66
  output.shadowPosition = solar.matrix * world;
@@ -0,0 +1,6 @@
1
+ export function nativeStrokeShader(material) {
2
+ return /* alloc */ {
3
+ position: material.nativeStroke ? 'position = input.normal + (input.position - input.normal) * u.nativeStroke.x;' : '',
4
+ normal: material.nativeStroke ? 'let sourceNormal = vec3<f32>(0.0, 1.0, 0.0);' : 'let sourceNormal = input.normal;',
5
+ };
6
+ }
@@ -9,7 +9,6 @@ import { createProgram } from '../materials/createProgram.js';
9
9
 
10
10
  import { setParent } from '../scene/setParent.js';
11
11
  import { update } from '../scene/scheduleSceneUpdate.js';
12
- import { instanceAreaGeometry } from '../geometry/instanceAreaGeometry.js';
13
12
 
14
13
  export function attachAreaMesh(context) {
15
14
  const { backend: layer, area } = context;
@@ -18,15 +17,15 @@ export function attachAreaMesh(context) {
18
17
  return;
19
18
  }
20
19
  const device = rendererByLayer.get(layer).device;
21
- const data = context.preparedGeometry || instanceAreaGeometry(context);
20
+ const data = context.preparedGeometry;
22
21
  const attributes = /* alloc */ {
23
- position: /* alloc */ { size: 3, data: data.positions instanceof Float32Array ? data.positions : /* alloc */ new Float32Array(data.positions) },
24
- normal: /* alloc */ { size: 3, data: data.normals instanceof Float32Array ? data.normals : /* alloc */ new Float32Array(data.normals) },
25
- color: /* alloc */ { size: 3, data: data.colors instanceof Float32Array ? data.colors : /* alloc */ new Float32Array(data.colors) },
22
+ position: /* alloc */ { size: 3, data: data.positions },
23
+ normal: /* alloc */ { size: 3, data: data.normals },
24
+ color: /* alloc */ { size: 3, data: data.colors },
26
25
  };
27
26
  if (data.instanceOffsets) attributes.instanceOffset = /* alloc */ { size: 4, data: data.instanceOffsets };
28
27
  if (layer.options.nightLight) attributes.uv = /* alloc */ {
29
- size: 2, data: context.uvs instanceof Float32Array ? context.uvs : /* alloc */ new Float32Array(context.uvs),
28
+ size: 2, data: data.uvs,
30
29
  };
31
30
  let name, attribute;
32
31
  for (name in attributes) {
@@ -3,15 +3,14 @@ import { inflightByLayer } from '../weakmaps/inflightByLayer.js';
3
3
  import { cameraViewByMap } from '../weakmaps/cameraViewByMap.js';
4
4
 
5
5
 
6
- import { buildAreaFeature } from './buildAreaFeature.js';
7
6
  import { attachAreaMesh } from './attachAreaMesh.js';
8
7
  import { loadSource } from '../archives/loadSource.js';
9
8
  import { sourceAreaContext } from './sourceAreaContext.js';
10
9
  import { pump } from './pumpSourceAreas.js';
11
10
  import { buildAreaInWorker } from '../workers/buildAreaInWorker.js';
11
+ import { buildAreaFeatures } from './buildAreaFeatures.js';
12
12
 
13
13
  export async function buildArea(layer, area, map) {
14
- let feature;
15
14
  try {
16
15
  await /* alloc */ new Promise(requestAnimationFrame);
17
16
  await cameraViewByMap.get(map);
@@ -24,22 +23,13 @@ export async function buildArea(layer, area, map) {
24
23
  if (geojsonByLayer.get(layer) && typeof layer.options.style !== 'function') {
25
24
  throw /* alloc */ new Error('style must be a function');
26
25
  }
27
- const context = sourceAreaContext(layer, area, map);
28
- // ponytail: feature-count cutoff avoids startup overhead; count vertices if giant single polygons matter.
29
- if (layer.options.worker !== false && typeof Worker !== 'undefined' && data.features.length >= 64) {
30
- context.jobs = /* alloc */ [];
31
- }
32
- let deadline = performance.now() + 4;
33
- for (feature of data.features) {
34
- if (area.request.signal.aborted) return;
35
- if (performance.now() >= deadline) {
36
- await /* alloc */ new Promise(requestAnimationFrame);
37
- if (area.request.signal.aborted) return;
38
- deadline = performance.now() + 4;
39
- }
40
- buildAreaFeature(context, feature);
26
+ if (layer.options.worker === false) {
27
+ throw /* alloc */ new Error('worker: false is no longer supported; GeoJSON geometry requires Web Workers');
41
28
  }
42
- if (context.jobs) await buildAreaInWorker(context, area.request.signal);
29
+ const context = sourceAreaContext(layer, area, map);
30
+ await buildAreaFeatures(context, area, data.features);
31
+ if (area.request.signal.aborted) return;
32
+ await buildAreaInWorker(context, area.request.signal);
43
33
  if (area.request.signal.aborted) return;
44
34
  attachAreaMesh(context);
45
35
  } catch (error) {