leaflet-city-mapper 0.0.1 → 0.0.3
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 +61 -13
- package/cucumber.mjs +4 -0
- package/dist/leaflet-city-mapper.js +3 -1
- package/dist/leaflet-city-mapper.js.map +4 -4
- package/package.json +3 -4
- package/src/archives/decodeDirectory.js +32 -0
- package/src/archives/decodeHeader.js +19 -0
- package/src/archives/decompress.js +5 -0
- package/src/archives/getHeader.js +9 -0
- package/src/archives/getZxy.js +75 -0
- package/src/archives/loadDirectory.js +7 -0
- package/src/archives/loadSource.js +17 -0
- package/src/archives/read.js +29 -0
- package/src/archives/tileId.js +19 -0
- package/src/archives/varint.js +15 -0
- package/src/camera/angles.js +6 -0
- package/src/camera/animationPoint.js +8 -0
- package/src/camera/cameraMapReady.js +8 -0
- package/src/camera/cancelCameraAnimation.js +11 -0
- package/src/camera/cleanupCameraMap.js +11 -0
- package/src/camera/constrainCameraToBounds.js +3 -0
- package/src/camera/displayPoint.js +3 -0
- package/src/camera/fitCameraBounds.js +48 -0
- package/src/camera/groundBounds.js +11 -0
- package/src/camera/initializeCameraMap.js +25 -0
- package/src/camera/mapAnimateCamera.js +17 -0
- package/src/camera/mapCamera.js +123 -0
- package/src/camera/mapContainerPointToLayerPoint.js +7 -0
- package/src/camera/mapGetBearing.js +1 -0
- package/src/camera/mapGetBounds.js +14 -0
- package/src/camera/mapGetBoundsCenterZoom.js +7 -0
- package/src/camera/mapGetBoundsZoom.js +14 -0
- package/src/camera/mapGetCenterLayerPoint.js +5 -0
- package/src/camera/mapGetPitch.js +1 -0
- package/src/camera/mapLayerPointToContainerPoint.js +7 -0
- package/src/camera/mapLimitCenter.js +12 -0
- package/src/camera/mapLimitOffset.js +10 -0
- package/src/camera/mapPanBy.js +9 -0
- package/src/camera/mapPanInside.js +14 -0
- package/src/camera/mapResetNorth.js +1 -0
- package/src/camera/mapResetNorthPitch.js +1 -0
- package/src/camera/mapSetBearing.js +1 -0
- package/src/camera/mapSetPitch.js +1 -0
- package/src/camera/mapSetPitchAndBearing.js +14 -0
- package/src/camera/mapSetZoomAround.js +11 -0
- package/src/camera/mapStopPitchBearingAnimation.js +6 -0
- package/src/camera/mapTryAnimatedPan.js +9 -0
- package/src/camera/mapUpdateCameraOverlays.js +7 -0
- package/src/camera/pointOf.js +3 -0
- package/src/camera/project.js +20 -0
- package/src/camera/runCameraAnimations.js +28 -0
- package/src/camera/scheduleCameraAnimation.js +8 -0
- package/src/camera/updateSky.js +16 -0
- package/src/camera/verticalGroundY.js +4 -0
- package/src/collision/collectMeshes.js +5 -0
- package/src/collision/collider.js +63 -0
- package/src/collision/horizontalRay.js +12 -0
- package/src/collision/intersectMeshes.js +133 -0
- package/src/collision/sortHits.js +23 -0
- package/src/constants/CELL.js +4 -0
- package/src/constants/Compass.js +7 -0
- package/src/constants/ContainerResize.js +7 -0
- package/src/constants/HEIGHT.js +1 -0
- package/src/constants/PitchDrag.js +7 -0
- package/src/constants/ShiftRotate.js +7 -0
- package/src/constants/TILE_RADIUS.js +1 -0
- package/src/constants/TILE_SIZE.js +1 -0
- package/src/constants/TouchMode.js +6 -0
- package/src/constants/accessorSizes.js +1 -0
- package/src/constants/accessorTypes.js +8 -0
- package/src/constants/attachState.js +1 -0
- package/src/constants/cameraControlsState.js +1 -0
- package/src/constants/cityMapper.js +6 -0
- package/src/constants/colliders.js +2 -0
- package/src/constants/dark.js +1 -0
- package/src/constants/elevationWGSL.js +27 -0
- package/src/constants/glass.js +1 -0
- package/src/constants/headlight.js +1 -0
- package/src/constants/hull.js +1 -0
- package/src/constants/indexState.js +1 -0
- package/src/constants/limbs.js +9 -0
- package/src/constants/mapCameraState.js +1 -0
- package/src/constants/moves.js +11 -0
- package/src/constants/nativeEventMaps.js +1 -0
- package/src/constants/nativeLayerState.js +1 -0
- package/src/constants/nativeMethodHandlers.js +31 -0
- package/src/constants/onMapChangeState.js +1 -0
- package/src/constants/onZoomAnimState.js +1 -0
- package/src/constants/paints.js +10 -0
- package/src/constants/parts.js +19 -0
- package/src/constants/pendingUpdates.js +1 -0
- package/src/constants/pumpState.js +1 -0
- package/src/constants/renderers.js +2 -0
- package/src/constants/ringDirections.js +10 -0
- package/src/constants/roundProfile.js +1 -0
- package/src/constants/shirt.js +1 -0
- package/src/constants/skin.js +2 -0
- package/src/constants/speed.js +3 -0
- package/src/constants/taillight.js +1 -0
- package/src/constants/trafficShader.js +49 -0
- package/src/constants/trousers.js +1 -0
- package/src/constants/tyre.js +1 -0
- package/src/constants/underEntryState.js +1 -0
- package/src/constants/vehicles.js +40 -0
- package/src/constants/white.js +1 -0
- package/src/controls/acceptPitchDrag.js +4 -0
- package/src/controls/acceptRotateDrag.js +3 -0
- package/src/controls/adjustCameraDrag.js +10 -0
- package/src/controls/cameraControls.js +60 -0
- package/src/controls/cameraDragClick.js +9 -0
- package/src/controls/cameraDragContextMenu.js +8 -0
- package/src/controls/cameraDragDown.js +20 -0
- package/src/controls/cameraDragEnd.js +6 -0
- package/src/controls/cameraDragMove.js +23 -0
- package/src/controls/changeCameraTouch.js +14 -0
- package/src/controls/cleanupCameraTouch.js +24 -0
- package/src/controls/compassAddHooks.js +15 -0
- package/src/controls/compassOrientation.js +6 -0
- package/src/controls/compassRemoveHooks.js +5 -0
- package/src/controls/containerResizeAddHooks.js +8 -0
- package/src/controls/containerResizeRemoveHooks.js +5 -0
- package/src/controls/dragCamera.js +22 -0
- package/src/controls/editable.js +3 -0
- package/src/controls/endAllCameraDrags.js +7 -0
- package/src/controls/endAllCameraTouches.js +7 -0
- package/src/controls/endCameraTouch.js +11 -0
- package/src/controls/endCameraTouchEvent.js +5 -0
- package/src/controls/finishCameraDrag.js +9 -0
- package/src/controls/finishCompassPermission.js +16 -0
- package/src/controls/loadCameraControls.js +9 -0
- package/src/controls/moveCameraTouch.js +22 -0
- package/src/controls/notifyCameraTouchChange.js +1 -0
- package/src/controls/pitchDragAddHooks.js +6 -0
- package/src/controls/pitchDragRemoveHooks.js +5 -0
- package/src/controls/refreshRotateControl.js +7 -0
- package/src/controls/refreshRotateFocus.js +5 -0
- package/src/controls/removeCameraDrag.js +23 -0
- package/src/controls/resizeMap.js +3 -0
- package/src/controls/rotateButtonClick.js +7 -0
- package/src/controls/rotateButtonKeydown.js +11 -0
- package/src/controls/rotateControl.js +3 -0
- package/src/controls/rotateOnAdd.js +38 -0
- package/src/controls/rotateOnRemove.js +6 -0
- package/src/controls/shiftRotateAddHooks.js +8 -0
- package/src/controls/shiftRotateRemoveHooks.js +5 -0
- package/src/controls/shiftRotateWheel.js +9 -0
- package/src/controls/startCameraTouch.js +23 -0
- package/src/core/addImageState.js +7 -0
- package/src/core/addRasterImage.js +10 -0
- package/src/core/adjustCameraMarkerPan.js +22 -0
- package/src/core/beforeNativeRender.js +10 -0
- package/src/core/boundsQuad.js +11 -0
- package/src/core/bringNativeLayerToBack.js +3 -0
- package/src/core/bringNativeLayerToFront.js +3 -0
- package/src/core/cameraCircleBounds.js +6 -0
- package/src/core/cameraMarkerDrag.js +18 -0
- package/src/core/cameraMarkerOnDrag.js +8 -0
- package/src/core/cancelGridFade.js +10 -0
- package/src/core/closestCameraLayerPoint.js +7 -0
- package/src/core/compareNativeHits.js +3 -0
- package/src/core/current.js +3 -0
- package/src/core/disposeNativeLayer.js +35 -0
- package/src/core/fireRasterLoad.js +5 -0
- package/src/core/forwardNativeError.js +3 -0
- package/src/core/gridlayerGetEvents.js +7 -0
- package/src/core/gridlayerGetTiledPixelBounds.js +8 -0
- package/src/core/handleNativeMapEvent.js +47 -0
- package/src/core/hideTargets.js +16 -0
- package/src/core/initNativeGPU.js +21 -0
- package/src/core/initializeGridContainer.js +6 -0
- package/src/core/initializeNativeLayer.js +42 -0
- package/src/core/localPixel.js +5 -0
- package/src/core/localPixelForGeometry.js +6 -0
- package/src/core/localPosition.js +6 -0
- package/src/core/markerCameraIconPoint.js +9 -0
- package/src/core/markerGetEvents.js +5 -0
- package/src/core/markerInitInteraction.js +8 -0
- package/src/core/markerQuadCorners.js +31 -0
- package/src/core/markerSetIcon.js +9 -0
- package/src/core/markerSetPos.js +14 -0
- package/src/core/markerSetRotation.js +7 -0
- package/src/core/markerUpdateZIndex.js +8 -0
- package/src/core/nativeAddLatLng.js +3 -0
- package/src/core/nativeBringToBack.js +3 -0
- package/src/core/nativeBringToFront.js +3 -0
- package/src/core/nativeEvents.js +26 -0
- package/src/core/nativeImageError.js +8 -0
- package/src/core/nativeImageRefresh.js +7 -0
- package/src/core/nativeLayer.js +97 -0
- package/src/core/nativeLayerMethod.js +21 -0
- package/src/core/nativeRedraw.js +3 -0
- package/src/core/nativeSetBounds.js +3 -0
- package/src/core/nativeSetIcon.js +3 -0
- package/src/core/nativeSetLatLng.js +3 -0
- package/src/core/nativeSetLatLngs.js +3 -0
- package/src/core/nativeSetOpacity.js +3 -0
- package/src/core/nativeSetRadius.js +3 -0
- package/src/core/nativeSetStyle.js +3 -0
- package/src/core/nativeSetUrl.js +3 -0
- package/src/core/nativeSetZIndex.js +3 -0
- package/src/core/nativeSetZIndexOffset.js +3 -0
- package/src/core/popupAdjustPan.js +23 -0
- package/src/core/popupGetEvents.js +5 -0
- package/src/core/popupUpdatePosition.js +14 -0
- package/src/core/putNativeMesh.js +33 -0
- package/src/core/quadNativeMesh.js +15 -0
- package/src/core/readyNativeGPU.js +6 -0
- package/src/core/refreshNativeEvent.js +5 -0
- package/src/core/refreshNativeLayer.js +29 -0
- package/src/core/refreshNativeLayerContract.js +3 -0
- package/src/core/rejectNativeReady.js +3 -0
- package/src/core/removeImageState.js +8 -0
- package/src/core/removeNativeEvents.js +16 -0
- package/src/core/removeTargets.js +8 -0
- package/src/core/reorderNativeLayer.js +6 -0
- package/src/core/resolveNativeReady.js +3 -0
- package/src/core/restoreNativeEvents.js +6 -0
- package/src/core/runGridFades.js +14 -0
- package/src/core/runMarkerPanFrame.js +12 -0
- package/src/core/scheduleGridFade.js +9 -0
- package/src/core/scheduleMarkerPan.js +8 -0
- package/src/core/styleNativeMesh.js +10 -0
- package/src/core/syncGridLayer.js +22 -0
- package/src/core/syncImageOverlay.js +9 -0
- package/src/core/syncMarker.js +12 -0
- package/src/core/syncVectorLayer.js +26 -0
- package/src/core/synchronizeNativeLayer.js +35 -0
- package/src/core/textureFor.js +48 -0
- package/src/core/tooltipGetEvents.js +5 -0
- package/src/core/tooltipSetPosition.js +8 -0
- package/src/core/updateGridOpacity.js +23 -0
- package/src/core/updateNativeLayerView.js +6 -0
- package/src/core/uploadCanvasTexture.js +19 -0
- package/src/geometry/addBridges.js +88 -0
- package/src/geometry/below.js +3 -0
- package/src/geometry/box.js +3 -0
- package/src/geometry/bridgeElevation.js +19 -0
- package/src/geometry/bridgeLocal.js +4 -0
- package/src/geometry/build.js +19 -0
- package/src/geometry/circleAt.js +5 -0
- package/src/geometry/clipLine.js +23 -0
- package/src/geometry/clipSegment.js +19 -0
- package/src/geometry/computeBounds.js +33 -0
- package/src/geometry/conformModelToTerrain.js +67 -0
- package/src/geometry/cross.js +3 -0
- package/src/geometry/disk.js +11 -0
- package/src/geometry/diskAt.js +4 -0
- package/src/geometry/dot.js +6 -0
- package/src/geometry/emitter.js +8 -0
- package/src/geometry/lampPostGeometry.js +24 -0
- package/src/geometry/lampRing.js +11 -0
- package/src/geometry/lightGeometry.js +15 -0
- package/src/geometry/line.js +54 -0
- package/src/geometry/nativeGeometry.js +55 -0
- package/src/geometry/nativeTriangle.js +3 -0
- package/src/geometry/polygon.js +22 -0
- package/src/geometry/push.js +3 -0
- package/src/geometry/quad.js +4 -0
- package/src/geometry/roofCoverage.js +52 -0
- package/src/geometry/samePoint.js +3 -0
- package/src/geometry/segment.js +21 -0
- package/src/geometry/setVertexColor.js +15 -0
- package/src/geometry/sub.js +6 -0
- package/src/geometry/surface.js +17 -0
- package/src/geometry/treeGeometry.js +31 -0
- package/src/geometry/treeRing.js +14 -0
- package/src/geometry/triangle.js +12 -0
- package/src/geometry/vertexNormals.js +32 -0
- package/src/geometry/visit.js +9 -0
- package/src/index.js +98 -65
- package/src/lighting/cacheLightGrid.js +23 -0
- package/src/lighting/collectLightMeshes.js +6 -0
- package/src/lighting/lightGrid.js +42 -0
- package/src/lighting/updatePointLights.js +34 -0
- package/src/lighting/visitCells.js +15 -0
- package/src/lighting/worldLights.js +27 -0
- package/src/models/decodeModel.js +45 -0
- package/src/models/hasUnsupportedPrimitives.js +10 -0
- package/src/models/loadBuffer.js +6 -0
- package/src/models/loadImage.js +15 -0
- package/src/models/loadModel.js +69 -0
- package/src/models/materialFor.js +21 -0
- package/src/models/modelNode.js +93 -0
- package/src/models/nodeMatrix.js +22 -0
- package/src/models/readAccessor.js +53 -0
- package/src/models/readAccessorValues.js +16 -0
- package/src/models/textureFor.js +35 -0
- package/src/models/textureSampler.js +10 -0
- package/src/picking/collectVisibleMesh.js +4 -0
- package/src/picking/findFeature.js +49 -0
- package/src/picking/hit.js +23 -0
- package/src/picking/hitMesh.js +30 -0
- package/src/picking/onClick.js +13 -0
- package/src/picking/onPointerLeave.js +11 -0
- package/src/picking/onPointerMove.js +15 -0
- package/src/picking/pointerClick.js +5 -0
- package/src/picking/pointerLeave.js +5 -0
- package/src/picking/pointerMove.js +5 -0
- package/src/picking/raycast.js +59 -0
- package/src/picking/setHighlight.js +13 -0
- package/src/picking/shouldSkipOther.js +3 -0
- package/src/picking/showFeature.js +34 -0
- package/src/raster/addRasterTile.js +114 -0
- package/src/raster/comparePendingTiles.js +5 -0
- package/src/raster/createGeometry.js +22 -0
- package/src/raster/createRasterMesh.js +47 -0
- package/src/raster/finishAttachment.js +11 -0
- package/src/raster/finishRasterTile.js +47 -0
- package/src/raster/getRasterEvents.js +6 -0
- package/src/raster/getRasterTileSize.js +5 -0
- package/src/raster/initRaster.js +38 -0
- package/src/raster/isLoading.js +5 -0
- package/src/raster/loadRasterTile.js +10 -0
- package/src/raster/onPMTileAdd.js +10 -0
- package/src/raster/onPMTileRemove.js +8 -0
- package/src/raster/pruneRasterTiles.js +37 -0
- package/src/raster/pumpRasterTiles.js +22 -0
- package/src/raster/readyRaster.js +13 -0
- package/src/raster/registerTerrainTile.js +12 -0
- package/src/raster/releaseRasterTile.js +18 -0
- package/src/raster/releaseRasterTiles.js +15 -0
- package/src/raster/removeRasterTile.js +13 -0
- package/src/raster/reportError.js +6 -0
- package/src/raster/setPMTileOpacity.js +7 -0
- package/src/raster/setPMTileZIndex.js +7 -0
- package/src/raster/setRasterOpacity.js +11 -0
- package/src/raster/setRasterTerrain.js +21 -0
- package/src/raster/setRasterZIndex.js +11 -0
- package/src/raster/updateAttachedTiles.js +10 -0
- package/src/raster/updateRasterTiles.js +59 -0
- package/src/rendering/collectFrameMeshes.js +31 -0
- package/src/rendering/collectMeshes.js +36 -0
- package/src/rendering/compareMeshes.js +10 -0
- package/src/rendering/compareRoofTiles.js +4 -0
- package/src/rendering/composeRoofAtlas.js +52 -0
- package/src/rendering/createMesh.js +33 -0
- package/src/rendering/createProgram.js +92 -0
- package/src/rendering/destroyAfterSubmission.js +8 -0
- package/src/rendering/destroyTexture.js +6 -0
- package/src/rendering/disposeMesh.js +14 -0
- package/src/rendering/drawGeometry.js +129 -0
- package/src/rendering/drawSceneMeshes.js +51 -0
- package/src/rendering/ensureRoofBlit.js +40 -0
- package/src/rendering/prepareFrameMeshes.js +42 -0
- package/src/rendering/prepareFrameUniforms.js +49 -0
- package/src/rendering/rebuildRoofAtlas.js +67 -0
- package/src/rendering/render.js +57 -0
- package/src/rendering/reportCompilation.js +17 -0
- package/src/rendering/resizeRenderer.js +19 -0
- package/src/rendering/sortMeshes.js +6 -0
- package/src/rendering/synchronizeZoomView.js +34 -0
- package/src/rendering/textureBinding.js +7 -0
- package/src/rendering/updateMapCamera.js +32 -0
- package/src/rendering/updateRoofRaster.js +32 -0
- package/src/scene/attach.js +161 -0
- package/src/scene/attachLayer.js +10 -0
- package/src/scene/cancelUpdate.js +10 -0
- package/src/scene/emptyEvents.js +3 -0
- package/src/scene/emptyNode.js +11 -0
- package/src/scene/endZoom.js +16 -0
- package/src/scene/failAttachment.js +9 -0
- package/src/scene/get3DEvents.js +13 -0
- package/src/scene/init3D.js +30 -0
- package/src/scene/initializeLayer.js +16 -0
- package/src/scene/initializerFor.js +14 -0
- package/src/scene/layerInitialize.js +38 -0
- package/src/scene/layerLayerAdd.js +21 -0
- package/src/scene/onAdd3DLayer.js +35 -0
- package/src/scene/onMapChange.js +16 -0
- package/src/scene/onRemove3DLayer.js +69 -0
- package/src/scene/onZoomAnim.js +16 -0
- package/src/scene/placeEntry.js +11 -0
- package/src/scene/placeUnderEntry.js +8 -0
- package/src/scene/ready3D.js +25 -0
- package/src/scene/releaseRenderer.js +14 -0
- package/src/scene/removeEntry.js +6 -0
- package/src/scene/renderPendingMapChange.js +11 -0
- package/src/scene/renderPendingUpdates.js +19 -0
- package/src/scene/renderPendingZoomAnimation.js +7 -0
- package/src/scene/rendererDeviceError.js +10 -0
- package/src/scene/rendererDeviceLost.js +11 -0
- package/src/scene/replaceEntry.js +7 -0
- package/src/scene/reportError.js +3 -0
- package/src/scene/requestAdapter.js +12 -0
- package/src/scene/requestDevice.js +9 -0
- package/src/scene/resolveNextInitialization.js +12 -0
- package/src/scene/restoreObject.js +71 -0
- package/src/scene/runPlacements.js +7 -0
- package/src/scene/setParent.js +7 -0
- package/src/scene/showWebGPUWarning.js +16 -0
- package/src/scene/startZoom.js +5 -0
- package/src/scene/traverse.js +7 -0
- package/src/scene/underEntry.js +17 -0
- package/src/scene/update.js +19 -0
- package/src/scene/updateCamera.js +34 -0
- package/src/scene/updateWorldMatrix.js +48 -0
- package/src/{utils/shaders.js → shaders/materialShaders.js} +246 -237
- package/src/shadows/bindSunlight.js +12 -0
- package/src/shadows/drawShadowMeshes.js +48 -0
- package/src/shadows/ensureShadowPipeline.js +53 -0
- package/src/shadows/renderSunlight.js +46 -0
- package/src/shadows/resizeSunlight.js +15 -0
- package/src/shadows/shadowBounds.js +32 -0
- package/src/shadows/shadowCacheMatches.js +23 -0
- package/src/shadows/shadowMatrix.js +39 -0
- package/src/sources/addGeneratedTriangle.js +6 -0
- package/src/sources/addTriangle.js +17 -0
- package/src/sources/attachAreaMesh.js +58 -0
- package/src/sources/buildArea.js +42 -0
- package/src/sources/buildAreaFeature.js +41 -0
- package/src/sources/buildAreaPoint.js +25 -0
- package/src/sources/buildAreaPolygon.js +29 -0
- package/src/sources/compareAreaDistance.js +4 -0
- package/src/sources/generateTreeGeometry.js +11 -0
- package/src/sources/groundOffset.js +3 -0
- package/src/sources/initializeGeoJSON.js +8 -0
- package/src/sources/instanceAreaGeometry.js +29 -0
- package/src/sources/projectRing.js +20 -0
- package/src/sources/projectedTree.js +13 -0
- package/src/sources/pump.js +54 -0
- package/src/sources/releaseArea.js +22 -0
- package/src/sources/setGeoJSONData.js +12 -0
- package/src/sources/setGeoJSONLayerData.js +5 -0
- package/src/sources/sourceAreaContext.js +9 -0
- package/src/sources/updateArea.js +45 -0
- package/src/sources/updateStatus.js +12 -0
- package/src/sunlight/addTimeLayer.js +3 -0
- package/src/sunlight/addTo.js +10 -0
- package/src/sunlight/atmosphere.js +28 -0
- package/src/sunlight/horizontalPosition.js +16 -0
- package/src/sunlight/initSunlight.js +14 -0
- package/src/sunlight/initialize.js +11 -0
- package/src/sunlight/mix.js +6 -0
- package/src/sunlight/moonPosition.js +17 -0
- package/src/sunlight/onAdd.js +5 -0
- package/src/sunlight/onAddSun.js +66 -0
- package/src/sunlight/projectCelestialBody.js +13 -0
- package/src/sunlight/remove.js +7 -0
- package/src/sunlight/removeSun.js +15 -0
- package/src/sunlight/removeTimeLayer.js +3 -0
- package/src/sunlight/render.js +7 -0
- package/src/sunlight/rgb.js +6 -0
- package/src/sunlight/solarPosition.js +17 -0
- package/src/sunlight/styleTimeControl.js +7 -0
- package/src/sunlight/tickSun.js +5 -0
- package/src/sunlight/updateSky.js +20 -0
- package/src/sunlight/updateSun.js +34 -0
- package/src/sunlight/useLiveTime.js +6 -0
- package/src/sunlight/useSelectedTime.js +20 -0
- package/src/terrain/clearLayerTerrain.js +5 -0
- package/src/terrain/getElevation.js +10 -0
- package/src/terrain/initTerrain.js +20 -0
- package/src/terrain/loadReadyTerrain.js +5 -0
- package/src/terrain/loadTerrain.js +63 -0
- package/src/terrain/loadTerrainTiles.js +13 -0
- package/src/terrain/onTerrainAdd.js +21 -0
- package/src/terrain/onTerrainChange.js +14 -0
- package/src/terrain/onTerrainRemove.js +41 -0
- package/src/terrain/readBridges.js +4 -0
- package/src/terrain/sample.js +7 -0
- package/src/terrain/setLayerTerrain.js +5 -0
- package/src/terrain/setTerrainHeight.js +10 -0
- package/src/terrain/terrainAtlas.js +23 -0
- package/src/terrain/terrainElevation.js +20 -0
- package/src/terrain/terrainGrid.js +24 -0
- package/src/traffic/addTraffic.js +7 -0
- package/src/traffic/along.js +14 -0
- package/src/traffic/clockMinutes.js +6 -0
- package/src/traffic/compareDepartures.js +5 -0
- package/src/traffic/createTrafficMesh.js +7 -0
- package/src/traffic/destroyTrafficGpu.js +5 -0
- package/src/traffic/disposeTrafficObject.js +13 -0
- package/src/traffic/drawTrafficRoute.js +6 -0
- package/src/traffic/failTraffic.js +6 -0
- package/src/traffic/failedTrafficLoad.js +5 -0
- package/src/traffic/fetchTrafficLanes.js +10 -0
- package/src/traffic/groundTraffic.js +15 -0
- package/src/traffic/initTraffic.js +54 -0
- package/src/traffic/loadTraffic.js +15 -0
- package/src/traffic/loadedTrafficLanes.js +16 -0
- package/src/traffic/locateTraffic.js +9 -0
- package/src/traffic/moveTraffic.js +15 -0
- package/src/traffic/placeTraffic.js +21 -0
- package/src/traffic/prepareTraffic.js +25 -0
- package/src/traffic/readyTraffic.js +6 -0
- package/src/traffic/rebaseTraffic.js +58 -0
- package/src/traffic/rebuildTrafficMesh.js +28 -0
- package/src/traffic/removeTraffic.js +17 -0
- package/src/traffic/routeColor.js +6 -0
- package/src/traffic/routeGeometry.js +31 -0
- package/src/traffic/scheduledTrips.js +40 -0
- package/src/traffic/startTraffic.js +8 -0
- package/src/traffic/tickTraffic.js +57 -0
- package/src/traffic/toLanes.js +16 -0
- package/src/traffic/tooltip.js +11 -0
- package/src/traffic/trafficBounds.js +17 -0
- package/src/traffic/trafficNow.js +4 -0
- package/src/traffic/trafficStorage.js +5 -0
- package/src/traffic/tripsAt.js +27 -0
- package/src/traffic/updateTraffic.js +8 -0
- package/src/traffic/updateTrafficTerrain.js +12 -0
- package/src/traffic/vehicleOffsets.js +11 -0
- package/src/triangulation/area.js +9 -0
- package/src/triangulation/clean.js +18 -0
- package/src/triangulation/containsVertex.js +11 -0
- package/src/triangulation/cross.js +3 -0
- package/src/triangulation/crossesBoundary.js +8 -0
- package/src/triangulation/crossesRing.js +9 -0
- package/src/triangulation/equal.js +3 -0
- package/src/triangulation/inside.js +10 -0
- package/src/triangulation/insideHole.js +7 -0
- package/src/triangulation/intersects.js +11 -0
- package/src/triangulation/isClockWise.js +13 -0
- package/src/triangulation/minimumX.js +6 -0
- package/src/triangulation/on.js +4 -0
- package/src/triangulation/sortHoles.js +26 -0
- package/src/triangulation/triangulate.js +86 -0
- package/src/utils/channel.js +4 -0
- package/src/utils/compareDistance.js +3 -0
- package/src/utils/noOperation.js +1 -0
- package/src/utils/parseColor.js +42 -0
- package/src/utils/toSRGB.js +3 -0
- package/src/utils/wrap.js +3 -0
- package/src/vehicles/bicycleModel.js +23 -0
- package/src/vehicles/boatBenches.js +8 -0
- package/src/vehicles/boatModel.js +27 -0
- package/src/vehicles/busModel.js +6 -0
- package/src/vehicles/carModel.js +22 -0
- package/src/vehicles/carriage.js +19 -0
- package/src/vehicles/metroModel.js +9 -0
- package/src/vehicles/mirror.js +8 -0
- package/src/vehicles/pedestrianModel.js +17 -0
- package/src/vehicles/tramModel.js +9 -0
- package/src/walk/blocked.js +6 -0
- package/src/walk/createWalk.js +60 -0
- package/src/walk/initWalk.js +18 -0
- package/src/walk/initialize.js +6 -0
- package/src/walk/local.js +10 -0
- package/src/walk/onAdd.js +4 -0
- package/src/walk/onBlur.js +3 -0
- package/src/walk/onKey.js +12 -0
- package/src/walk/onPointer.js +13 -0
- package/src/walk/onRemove.js +4 -0
- package/src/walk/onTerrain.js +5 -0
- package/src/walk/place.js +18 -0
- package/src/walk/start.js +37 -0
- package/src/walk/step.js +53 -0
- package/src/walk/stop.js +27 -0
- package/src/walk/toggle.js +6 -0
- package/dist/scene/gpu.js +0 -3
- package/dist/scene/gpu.js.map +0 -7
- package/dist/scene/lighting.js +0 -9
- package/dist/scene/lighting.js.map +0 -7
- package/dist/scene/model.js +0 -2
- package/dist/scene/model.js.map +0 -7
- package/dist/scene/picking.js +0 -2
- package/dist/scene/picking.js.map +0 -7
- package/dist/scene/pmtiles.js +0 -2
- package/dist/scene/pmtiles.js.map +0 -7
- package/dist/scene/render.js +0 -15
- package/dist/scene/render.js.map +0 -7
- package/dist/scene/sources.js +0 -2
- package/dist/scene/sources.js.map +0 -7
- package/dist/types/3d.js +0 -2
- package/dist/types/3d.js.map +0 -7
- package/dist/types/geojson.js +0 -2
- package/dist/types/geojson.js.map +0 -7
- package/dist/types/pmtiles.js +0 -2
- package/dist/types/pmtiles.js.map +0 -7
- package/dist/types/sunlight.js +0 -2
- package/dist/types/sunlight.js.map +0 -7
- package/dist/types/terrain.js +0 -24
- package/dist/types/terrain.js.map +0 -7
- package/dist/types/traffic.js +0 -41
- package/dist/types/traffic.js.map +0 -7
- package/dist/types/walk.js +0 -2
- package/dist/types/walk.js.map +0 -7
- package/dist/utils/control.js +0 -2
- package/dist/utils/control.js.map +0 -7
- package/dist/utils/geometry.js +0 -2
- package/dist/utils/geometry.js.map +0 -7
- package/dist/utils/lighting.js +0 -2
- package/dist/utils/lighting.js.map +0 -7
- package/dist/utils/model.js +0 -2
- package/dist/utils/model.js.map +0 -7
- package/dist/utils/picking.js +0 -2
- package/dist/utils/picking.js.map +0 -7
- package/dist/utils/pmtiles.js +0 -2
- package/dist/utils/pmtiles.js.map +0 -7
- package/dist/utils/scene.js +0 -2
- package/dist/utils/scene.js.map +0 -7
- package/dist/utils/shaders.js +0 -203
- package/dist/utils/shaders.js.map +0 -7
- package/dist/utils/sun.js +0 -2
- package/dist/utils/sun.js.map +0 -7
- package/dist/utils/terrain.js +0 -2
- package/dist/utils/terrain.js.map +0 -7
- package/dist/utils/traffic.js +0 -2
- package/dist/utils/traffic.js.map +0 -7
- package/dist/utils/vehicles.js +0 -2
- package/dist/utils/vehicles.js.map +0 -7
- package/dist/utils/walk.js +0 -2
- package/dist/utils/walk.js.map +0 -7
- package/src/scene/gpu.js +0 -438
- package/src/scene/lighting.js +0 -193
- package/src/scene/model.js +0 -204
- package/src/scene/picking.js +0 -150
- package/src/scene/pmtiles.js +0 -94
- package/src/scene/render.js +0 -467
- package/src/scene/sources.js +0 -265
- package/src/types/3d.js +0 -337
- package/src/types/geojson.js +0 -42
- package/src/types/pmtiles.js +0 -143
- package/src/types/sunlight.js +0 -142
- package/src/types/terrain.js +0 -331
- package/src/types/traffic.js +0 -356
- package/src/types/walk.js +0 -219
- package/src/utils/control.js +0 -18
- package/src/utils/geometry.js +0 -256
- package/src/utils/lighting.js +0 -51
- package/src/utils/model.js +0 -178
- package/src/utils/picking.js +0 -119
- package/src/utils/pmtiles.js +0 -79
- package/src/utils/scene.js +0 -102
- package/src/utils/sun.js +0 -71
- package/src/utils/terrain.js +0 -78
- package/src/utils/traffic.js +0 -90
- package/src/utils/vehicles.js +0 -69
- package/src/utils/walk.js +0 -72
package/src/utils/geometry.js
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HSL inputs are linear-space to preserve the original building styling.
|
|
3
|
-
* Numeric/CSS/RGB inputs are already sRGB; CSS alpha is not used for extrusion.
|
|
4
|
-
* @param {number|string|Object} value 0xRRGGBB, CSS color, {r,g,b}, or {h,s,l} in 0..1.
|
|
5
|
-
* @returns {Object} sRGB {r,g,b} components in 0..1.
|
|
6
|
-
*/
|
|
7
|
-
export function parseColor(value) {
|
|
8
|
-
if (value && typeof value === 'object' && 'h' in value) {
|
|
9
|
-
const { h, s, l } = value;
|
|
10
|
-
const a = s * Math.min(l, 1 - l);
|
|
11
|
-
const channel = n => {
|
|
12
|
-
const k = (n + h * 12) % 12;
|
|
13
|
-
return l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1));
|
|
14
|
-
};
|
|
15
|
-
const toSRGB = value => value <= 0.0031308 ? value * 12.92 : 1.055 * value ** (1 / 2.4) - 0.055;
|
|
16
|
-
return { r: toSRGB(channel(0)), g: toSRGB(channel(8)), b: toSRGB(channel(4)) };
|
|
17
|
-
}
|
|
18
|
-
if (value && typeof value === 'object' && 'r' in value) return value;
|
|
19
|
-
if (typeof value === 'number') return {
|
|
20
|
-
r: (value >> 16 & 255) / 255, g: (value >> 8 & 255) / 255, b: (value & 255) / 255,
|
|
21
|
-
};
|
|
22
|
-
if (typeof value !== 'string' || !CSS.supports('color', value)) throw new Error('Invalid 3D color');
|
|
23
|
-
const context = document.createElement('canvas').getContext('2d');
|
|
24
|
-
context.fillStyle = value;
|
|
25
|
-
context.fillRect(0, 0, 1, 1);
|
|
26
|
-
const [r, g, b] = context.getImageData(0, 0, 1, 1).data;
|
|
27
|
-
return { r: r / 255, g: g / 255, b: b / 255 };
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Paints the vertices `[start, end)` of a mesh and marks its color buffer dirty.
|
|
32
|
-
* @param {Object} mesh Layer-created mesh with a color attribute.
|
|
33
|
-
* @param {number} start Inclusive vertex index, not an offset into the RGB array.
|
|
34
|
-
* @param {number} end Exclusive vertex index.
|
|
35
|
-
* @param {Object} color sRGB {r,g,b}, typically from parseColor().
|
|
36
|
-
*/
|
|
37
|
-
export function setVertexColor(mesh, start, end, color) {
|
|
38
|
-
for (let i = start; i < end; i++) {
|
|
39
|
-
mesh.geometry.attributes.color.data.set([color.r, color.g, color.b], i * 3);
|
|
40
|
-
}
|
|
41
|
-
mesh.geometry.attributes.color.needsUpdate = true;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Triangulates a polygon given as `{x, y}` points.
|
|
46
|
-
* Rings omit the repeated closing point; winding is normalized internally.
|
|
47
|
-
* Vertex indices remain relative to the original inputs after duplicate/collinear
|
|
48
|
-
* cleanup. Hole bridges duplicate endpoints, not source vertices.
|
|
49
|
-
* @param {Object[]} contour Outer boundary.
|
|
50
|
-
* @param {Object[][]} [holes] Interior boundaries.
|
|
51
|
-
*
|
|
52
|
-
* @returns {number[][]} Triangles as indices in `[...contour, ...holes.flat()]`.
|
|
53
|
-
*/
|
|
54
|
-
export function triangulate(contour, holes = []) {
|
|
55
|
-
const points = [contour, ...holes].flat();
|
|
56
|
-
if (points.some(p => !Number.isFinite(p.x) || !Number.isFinite(p.y))) throw new Error('Invalid polygon coordinates');
|
|
57
|
-
// Translate near the origin to avoid cancellation with geographic coordinates.
|
|
58
|
-
const vertices = points.map((p, index) => ({ x: p.x - contour[0].x, y: p.y - contour[0].y, index }));
|
|
59
|
-
const cross = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
|
60
|
-
const equal = (a, b) => a.x === b.x && a.y === b.y;
|
|
61
|
-
// Remove zero-area corners before connecting holes; keep original vertex indices.
|
|
62
|
-
const clean = ring => {
|
|
63
|
-
let changed = true;
|
|
64
|
-
while (changed && ring.length > 3) {
|
|
65
|
-
changed = false;
|
|
66
|
-
for (let i = 0; i < ring.length; i++) {
|
|
67
|
-
const a = ring[(i + ring.length - 1) % ring.length], b = ring[i], c = ring[(i + 1) % ring.length];
|
|
68
|
-
if (equal(a, b) || Math.abs(cross(a, b, c)) < 1e-10) {
|
|
69
|
-
ring.splice(i, 1); changed = true; break;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (ring.length < 3) throw new Error('Degenerate polygon ring');
|
|
74
|
-
return ring;
|
|
75
|
-
};
|
|
76
|
-
let offset = 0;
|
|
77
|
-
const rings = [contour, ...holes].map((path, index) => {
|
|
78
|
-
const ring = clean(vertices.slice(offset, offset += path.length));
|
|
79
|
-
if (isClockWise(ring) !== Boolean(index)) ring.reverse();
|
|
80
|
-
return ring;
|
|
81
|
-
});
|
|
82
|
-
const inside = (point, ring) => {
|
|
83
|
-
let result = false;
|
|
84
|
-
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
|
|
85
|
-
const a = ring[i], b = ring[j];
|
|
86
|
-
if ((a.y > point.y) !== (b.y > point.y) &&
|
|
87
|
-
point.x < (b.x - a.x) * (point.y - a.y) / (b.y - a.y) + a.x) result = !result;
|
|
88
|
-
}
|
|
89
|
-
return result;
|
|
90
|
-
};
|
|
91
|
-
const intersects = (a, b, c, d) => {
|
|
92
|
-
if (equal(a, c) || equal(a, d) || equal(b, c) || equal(b, d)) return false;
|
|
93
|
-
const abC = cross(a, b, c), abD = cross(a, b, d), cdA = cross(c, d, a), cdB = cross(c, d, b);
|
|
94
|
-
const on = (p, q, r) => Math.min(p.x, q.x) <= r.x && r.x <= Math.max(p.x, q.x) &&
|
|
95
|
-
Math.min(p.y, q.y) <= r.y && r.y <= Math.max(p.y, q.y);
|
|
96
|
-
return abC * abD < 0 && cdA * cdB < 0 ||
|
|
97
|
-
abC === 0 && on(a, b, c) || abD === 0 && on(a, b, d) ||
|
|
98
|
-
cdA === 0 && on(c, d, a) || cdB === 0 && on(c, d, b);
|
|
99
|
-
};
|
|
100
|
-
let polygon = rings[0].slice();
|
|
101
|
-
// A bridge must stay inside the outer boundary, outside every hole, and cross no edge.
|
|
102
|
-
// ponytail: quadratic ear clipping for building footprints; use spatial indexing for large rings.
|
|
103
|
-
for (const hole of rings.slice(1).sort((a, b) => Math.min(...a.map(p => p.x)) - Math.min(...b.map(p => p.x)))) {
|
|
104
|
-
let bridge, distance = Infinity;
|
|
105
|
-
for (let h = 0; h < hole.length; h++) for (let p = 0; p < polygon.length; p++) {
|
|
106
|
-
const a = hole[h], b = polygon[p], d = (a.x - b.x) ** 2 + (a.y - b.y) ** 2;
|
|
107
|
-
if (d >= distance) continue;
|
|
108
|
-
const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
|
|
109
|
-
if (!inside(mid, rings[0]) || rings.slice(1).some(r => inside(mid, r))) continue;
|
|
110
|
-
if ([polygon, ...rings.slice(1)].some(r => r.some((c, i) => intersects(a, b, c, r[(i + 1) % r.length])))) continue;
|
|
111
|
-
bridge = [h, p]; distance = d;
|
|
112
|
-
}
|
|
113
|
-
if (!bridge) throw new Error('Unable to connect polygon hole');
|
|
114
|
-
const [h, p] = bridge;
|
|
115
|
-
polygon = [...polygon.slice(0, p + 1), ...hole.slice(h), ...hole.slice(0, h + 1),
|
|
116
|
-
polygon[p], ...polygon.slice(p + 1)];
|
|
117
|
-
}
|
|
118
|
-
// Clip a convex corner only when no other vertex is inside/on its triangle.
|
|
119
|
-
const result = [];
|
|
120
|
-
while (polygon.length > 3) {
|
|
121
|
-
let clipped = false;
|
|
122
|
-
for (let i = 0; i < polygon.length; i++) {
|
|
123
|
-
const a = polygon[(i + polygon.length - 1) % polygon.length], b = polygon[i], c = polygon[(i + 1) % polygon.length];
|
|
124
|
-
if (cross(a, b, c) <= 1e-10) continue;
|
|
125
|
-
if (polygon.some(p => !equal(p, a) && !equal(p, b) && !equal(p, c) &&
|
|
126
|
-
cross(a, b, p) >= 0 && cross(b, c, p) >= 0 && cross(c, a, p) >= 0)) continue;
|
|
127
|
-
result.push([a.index, b.index, c.index]); polygon.splice(i, 1); clipped = true; break;
|
|
128
|
-
}
|
|
129
|
-
if (!clipped) throw new Error('Unable to triangulate polygon: invalid or self-intersecting rings');
|
|
130
|
-
}
|
|
131
|
-
if (cross(...polygon) > 1e-10) result.push(polygon.map(p => p.index));
|
|
132
|
-
const area = ring => Math.abs(ring.reduce((sum, p, i) => {
|
|
133
|
-
const q = ring[(i + 1) % ring.length]; return sum + p.x * q.y - q.x * p.y;
|
|
134
|
-
}, 0)) / 2;
|
|
135
|
-
// Reject incomplete coverage instead of silently emitting a partial roof.
|
|
136
|
-
const expected = area(rings[0]) - rings.slice(1).reduce((sum, ring) => sum + area(ring), 0);
|
|
137
|
-
const actual = result.reduce((sum, triangle) => sum + cross(...triangle.map(i => vertices[i])) / 2, 0);
|
|
138
|
-
if (expected <= 0 || Math.abs(actual - expected) > Math.max(1e-7, expected * 1e-8)) throw new Error('Polygon triangulation area mismatch');
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* @returns {boolean} Whether the `{x, y}` points are in clockwise order.
|
|
144
|
-
*/
|
|
145
|
-
export function isClockWise(points) {
|
|
146
|
-
let area = 0;
|
|
147
|
-
for (let i = 0; i < points.length; i++) {
|
|
148
|
-
const a = points[i], b = points[(i + 1) % points.length];
|
|
149
|
-
area += a.x * b.y - b.x * a.y;
|
|
150
|
-
}
|
|
151
|
-
return area < 0;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/** Low-poly tree, sharing the source block's buffers, picking and terrain offset. */
|
|
155
|
-
export function treeGeometry(point, style, addTriangle) {
|
|
156
|
-
const { top, bottom = 0, trunkRadius, crownRadius, crownBottom, crownShape = 'round' } = style;
|
|
157
|
-
if (![trunkRadius, crownRadius, crownBottom].every(Number.isFinite) ||
|
|
158
|
-
trunkRadius <= 0 || crownRadius < trunkRadius || crownBottom <= bottom || crownBottom >= top ||
|
|
159
|
-
!['round', 'cone'].includes(crownShape)) {
|
|
160
|
-
throw new Error('Invalid tree dimensions or crown shape');
|
|
161
|
-
}
|
|
162
|
-
const trunk = parseColor(style.trunkColor ?? 0x72513a);
|
|
163
|
-
const crown = parseColor(style.color ?? 0x4f823b);
|
|
164
|
-
const ring = radius => Array.from({ length: 8 }, (_, i) => ({
|
|
165
|
-
x: point.x + Math.cos(i * Math.PI / 4) * radius,
|
|
166
|
-
y: point.y + Math.sin(i * Math.PI / 4) * radius,
|
|
167
|
-
ground: point.ground,
|
|
168
|
-
}));
|
|
169
|
-
const surface = (lowRadius, low, highRadius, high, color) => {
|
|
170
|
-
const lower = ring(lowRadius), upper = ring(highRadius);
|
|
171
|
-
for (let i = 0; i < 8; i++) {
|
|
172
|
-
const next = (i + 1) % 8;
|
|
173
|
-
const angle = (i + 0.5) * Math.PI / 4;
|
|
174
|
-
const slope = (lowRadius - highRadius) / (high - low);
|
|
175
|
-
const length = Math.hypot(1, slope);
|
|
176
|
-
const nx = Math.cos(angle) / length, ny = slope / length, nz = -Math.sin(angle) / length;
|
|
177
|
-
if (lowRadius) addTriangle(lower[i], low, lower[next], low, upper[next], high, nx, ny, nz, color);
|
|
178
|
-
if (highRadius) addTriangle(lower[i], low, upper[next], high, upper[i], high, nx, ny, nz, color);
|
|
179
|
-
}
|
|
180
|
-
};
|
|
181
|
-
surface(trunkRadius, bottom, trunkRadius, crownBottom + (top - crownBottom) * 0.25, trunk);
|
|
182
|
-
if (crownShape === 'cone') {
|
|
183
|
-
const base = ring(crownRadius);
|
|
184
|
-
for (let i = 0; i < 8; i++) addTriangle(point, crownBottom, base[i], crownBottom,
|
|
185
|
-
base[(i + 1) % 8], crownBottom, 0, -1, 0, crown);
|
|
186
|
-
surface(crownRadius, crownBottom, 0, top, crown);
|
|
187
|
-
} else {
|
|
188
|
-
const profile = [[0, 0], [0.35, 0.8], [0.6, 1], [0.85, 0.7], [1, 0]];
|
|
189
|
-
for (let i = 1; i < profile.length; i++) {
|
|
190
|
-
const [low, lr] = profile[i - 1], [high, hr] = profile[i];
|
|
191
|
-
surface(lr * crownRadius, crownBottom + low * (top - crownBottom),
|
|
192
|
-
hr * crownRadius, crownBottom + high * (top - crownBottom), crown);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/** Three crossed emitter discs; illumination itself is evaluated on receiving surfaces. */
|
|
198
|
-
export function lightGeometry(point, style, addTriangle) {
|
|
199
|
-
if (!Number.isFinite(style.lightRadius) || style.lightRadius <= 0) throw new Error('Invalid light radius');
|
|
200
|
-
const color = parseColor(style.color);
|
|
201
|
-
const quad = (a, b, c, d, height, normal) => {
|
|
202
|
-
addTriangle(a, height, b, height, c, height, ...normal, color);
|
|
203
|
-
addTriangle(a, height, c, height, d, height, ...normal, color);
|
|
204
|
-
};
|
|
205
|
-
const r = 0.65;
|
|
206
|
-
const emitter = (u, v, axis) => ({
|
|
207
|
-
x: point.x + (axis === 2 ? 0 : u * r),
|
|
208
|
-
y: point.y + (axis === 1 ? 0 : axis === 2 ? u * r : v * r),
|
|
209
|
-
ground: point.ground + (axis === 0 ? 0 : v * r), uv: [u, v],
|
|
210
|
-
});
|
|
211
|
-
for (let axis = 0; axis < 3; axis++) {
|
|
212
|
-
quad(emitter(-1, -1, axis), emitter(1, -1, axis), emitter(1, 1, axis), emitter(-1, 1, axis),
|
|
213
|
-
style.top, axis === 0 ? [0, 1, 0] : axis === 1 ? [0, 0, 1] : [1, 0, 0]);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/** Schematic support and lamp head; wall-mounted fixtures do not get an invented pole. */
|
|
218
|
-
export function lampPostGeometry(point, style, addTriangle) {
|
|
219
|
-
const color = parseColor(0x50565a), radius = style.poleRadius;
|
|
220
|
-
if (!Number.isFinite(radius) || radius <= 0) throw new Error('Invalid lamp pole radius');
|
|
221
|
-
const ring = r => Array.from({ length: 6 }, (_, i) => ({
|
|
222
|
-
x: point.x + Math.cos(i * Math.PI / 3) * r,
|
|
223
|
-
y: point.y + Math.sin(i * Math.PI / 3) * r, ground: point.ground, uv: [3, 3],
|
|
224
|
-
}));
|
|
225
|
-
const center = { ...point, uv: [3, 3] };
|
|
226
|
-
for (const [r, low, high] of [[radius, 0, style.top], [radius * 2.5, style.top - 0.25, style.top + 0.15]]) {
|
|
227
|
-
const points = ring(r);
|
|
228
|
-
for (let i = 0; i < 6; i++) {
|
|
229
|
-
const a = points[i], b = points[(i + 1) % 6], angle = (i + 0.5) * Math.PI / 3;
|
|
230
|
-
const nx = Math.cos(angle), nz = -Math.sin(angle);
|
|
231
|
-
addTriangle(a, low, b, low, b, high, nx, 0, nz, color);
|
|
232
|
-
addTriangle(a, low, b, high, a, high, nx, 0, nz, color);
|
|
233
|
-
addTriangle(center, high, a, high, b, high, 0, 1, 0, color);
|
|
234
|
-
addTriangle(center, low, b, low, a, low, 0, -1, 0, color);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/** Cache local AABB and center for ray picking and transparent mesh sorting. */
|
|
240
|
-
export function computeBounds(geometry) {
|
|
241
|
-
const min = [Infinity, Infinity, Infinity],
|
|
242
|
-
max = [-Infinity, -Infinity, -Infinity],
|
|
243
|
-
data = geometry.attributes.position.data;
|
|
244
|
-
for (let i = 0; i < data.length; i++) {
|
|
245
|
-
min[i % 3] = Math.min(min[i % 3], data[i]);
|
|
246
|
-
max[i % 3] = Math.max(max[i % 3], data[i]);
|
|
247
|
-
}
|
|
248
|
-
const center = min.map((v, i) => (v + max[i]) / 2);
|
|
249
|
-
let radius = 0;
|
|
250
|
-
for (let i = 0; i < data.length; i += 3) {
|
|
251
|
-
radius = Math.max(radius, Math.hypot(
|
|
252
|
-
data[i] - center[0], data[i + 1] - center[1], data[i + 2] - center[2]
|
|
253
|
-
));
|
|
254
|
-
}
|
|
255
|
-
geometry.bounds = { min, max, center, radius };
|
|
256
|
-
}
|
package/src/utils/lighting.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/** Pack world-space point lights into the shader's spatial grid. */
|
|
2
|
-
export function lightGrid(packed, maxBytes) {
|
|
3
|
-
const count = packed.reduce((sum, values) => sum + values.length / 8, 0), cellSize = 32;
|
|
4
|
-
let data = new Float32Array(8);
|
|
5
|
-
if (count) {
|
|
6
|
-
let minX = Infinity, minZ = Infinity, maxX = -Infinity, maxZ = -Infinity;
|
|
7
|
-
for (const values of packed) for (let i = 0; i < values.length; i += 8) {
|
|
8
|
-
minX = Math.min(minX, values[i] - values[i + 3]); maxX = Math.max(maxX, values[i] + values[i + 3]);
|
|
9
|
-
minZ = Math.min(minZ, values[i + 2] - values[i + 3]); maxZ = Math.max(maxZ, values[i + 2] + values[i + 3]);
|
|
10
|
-
}
|
|
11
|
-
const columns = Math.ceil((maxX - minX) / cellSize) + 1, rows = Math.ceil((maxZ - minZ) / cellSize) + 1;
|
|
12
|
-
const each = callback => {
|
|
13
|
-
for (const values of packed) for (let i = 0; i < values.length; i += 8) {
|
|
14
|
-
const radius = values[i + 3], x = values[i] - minX, z = values[i + 2] - minZ;
|
|
15
|
-
for (let y = Math.floor((z - radius) / cellSize); y <= Math.floor((z + radius) / cellSize); y++) {
|
|
16
|
-
for (let c = Math.floor((x - radius) / cellSize); c <= Math.floor((x + radius) / cellSize); c++) callback(y * columns + c, values, i);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
// Counting sort: count the lights of each cell, then fill each cell's slice.
|
|
21
|
-
const counts = new Uint32Array(columns * rows), next = new Uint32Array(columns * rows);
|
|
22
|
-
each(key => counts[key]++);
|
|
23
|
-
const entries = counts.reduce((sum, value) => sum + value, 0);
|
|
24
|
-
const length = (2 + columns * rows + entries * 2) * 4;
|
|
25
|
-
if (length * 4 > maxBytes) throw new Error('Streetlight grid exceeds GPU storage limit');
|
|
26
|
-
data = new Float32Array(length);
|
|
27
|
-
data.set([minX, minZ, cellSize, columns, rows, count, 0, 0]);
|
|
28
|
-
let offset = 2 + columns * rows;
|
|
29
|
-
for (let key = 0; key < counts.length; key++) if (counts[key]) {
|
|
30
|
-
data[(2 + key) * 4] = next[key] = offset;
|
|
31
|
-
data[(2 + key) * 4 + 1] = counts[key];
|
|
32
|
-
offset += counts[key] * 2;
|
|
33
|
-
}
|
|
34
|
-
each((key, values, i) => {
|
|
35
|
-
for (let j = 0, o = next[key] * 4; j < 8; j++) data[o + j] = values[i + j];
|
|
36
|
-
next[key] += 2;
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
return { data, count };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/** World-space [x, y, z, radius, r, g, b, intensity] for one mesh's point lights. */
|
|
43
|
-
export function worldLights(lights, m) {
|
|
44
|
-
const values = new Float32Array(lights.length * 8);
|
|
45
|
-
lights.forEach(({ position: [x, y, z], radius, color, flux }, i) => {
|
|
46
|
-
const w = m[3] * x + m[7] * y + m[11] * z + m[15];
|
|
47
|
-
values.set([(m[0] * x + m[4] * y + m[8] * z + m[12]) / w, (m[1] * x + m[5] * y + m[9] * z + m[13]) / w,
|
|
48
|
-
(m[2] * x + m[6] * y + m[10] * z + m[14]) / w, radius, ...color, flux / (4 * Math.PI) * 0.03], i * 8);
|
|
49
|
-
});
|
|
50
|
-
return values;
|
|
51
|
-
}
|
package/src/utils/model.js
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
const types = {
|
|
2
|
-
5120: Int8Array,
|
|
3
|
-
5121: Uint8Array,
|
|
4
|
-
5122: Int16Array,
|
|
5
|
-
5123: Uint16Array,
|
|
6
|
-
5125: Uint32Array,
|
|
7
|
-
5126: Float32Array,
|
|
8
|
-
};
|
|
9
|
-
const sizes = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4 };
|
|
10
|
-
|
|
11
|
-
/** Decode a static glTF JSON document or GLB v2 container. */
|
|
12
|
-
export function decodeModel(data) {
|
|
13
|
-
const view = new DataView(data),
|
|
14
|
-
decoder = new TextDecoder();
|
|
15
|
-
let description;
|
|
16
|
-
if (view.getUint32(0, true) === 0x46546c67) {
|
|
17
|
-
// Decode GLB v2 chunks; unknown types are skipped.
|
|
18
|
-
if (view.getUint32(4, true) !== 2 || view.getUint32(8, true) !== data.byteLength) {
|
|
19
|
-
throw new Error('Invalid GLB header');
|
|
20
|
-
}
|
|
21
|
-
let binary;
|
|
22
|
-
for (let offset = 12; offset < data.byteLength;) {
|
|
23
|
-
if (offset + 8 > data.byteLength) {
|
|
24
|
-
throw new Error('Truncated GLB chunk');
|
|
25
|
-
}
|
|
26
|
-
const length = view.getUint32(offset, true), type = view.getUint32(offset + 4, true);
|
|
27
|
-
offset += 8;
|
|
28
|
-
if (offset + length > data.byteLength) {
|
|
29
|
-
throw new Error('Truncated GLB data');
|
|
30
|
-
}
|
|
31
|
-
const chunk = data.slice(offset, offset + length);
|
|
32
|
-
if (type === 0x4e4f534a) {
|
|
33
|
-
description = JSON.parse(decoder.decode(chunk));
|
|
34
|
-
}
|
|
35
|
-
if (type === 0x004e4942) {
|
|
36
|
-
binary = chunk;
|
|
37
|
-
}
|
|
38
|
-
offset += length;
|
|
39
|
-
}
|
|
40
|
-
if (!description) {
|
|
41
|
-
throw new Error('Missing GLB JSON');
|
|
42
|
-
}
|
|
43
|
-
if (binary) {
|
|
44
|
-
description.buffers[0].binary = binary;
|
|
45
|
-
}
|
|
46
|
-
} else {
|
|
47
|
-
description = JSON.parse(decoder.decode(data));
|
|
48
|
-
}
|
|
49
|
-
if (description.skins?.length || description.animations?.length || description.extensionsRequired?.length || description.meshes?.some(mesh => mesh.primitives.some(primitive => primitive.targets || (primitive.mode !== undefined && primitive.mode !== 4)))) {
|
|
50
|
-
throw new Error('Layer3D supports static triangle glTF models without required extensions');
|
|
51
|
-
}
|
|
52
|
-
return description;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** Decode packed, interleaved, normalized or sparse glTF accessor data. */
|
|
56
|
-
export function readAccessor(description, index) {
|
|
57
|
-
const spec = description.accessors[index],
|
|
58
|
-
Type = types[spec.componentType],
|
|
59
|
-
size = sizes[spec.type];
|
|
60
|
-
if (!Type || !size || !Number.isInteger(spec.count) || spec.count < 0) {
|
|
61
|
-
throw new Error('Invalid glTF accessor');
|
|
62
|
-
}
|
|
63
|
-
const data = new Type(spec.count * size);
|
|
64
|
-
// The destination callback is sequential for base data and sparse-indexed for overrides.
|
|
65
|
-
const read = (viewIndex, offset, count, stride, output) => {
|
|
66
|
-
const view = description.bufferViews[viewIndex], bytes = Type.BYTES_PER_ELEMENT;
|
|
67
|
-
const buffer = description.buffers[view.buffer].binary;
|
|
68
|
-
stride ||= size * bytes;
|
|
69
|
-
if (!buffer || stride < size * bytes || offset < 0 ||
|
|
70
|
-
(view.byteOffset || 0) + view.byteLength > buffer.byteLength ||
|
|
71
|
-
(count - 1) * stride + size * bytes + offset > view.byteLength) throw new Error('glTF accessor outside buffer view');
|
|
72
|
-
for (let i = 0; i < count; i++) {
|
|
73
|
-
const values = new Type(buffer.slice((view.byteOffset || 0) + offset + i * stride,
|
|
74
|
-
(view.byteOffset || 0) + offset + i * stride + size * bytes));
|
|
75
|
-
data.set(values, output(i) * size);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
if (spec.bufferView !== undefined) {
|
|
79
|
-
read(
|
|
80
|
-
spec.bufferView,
|
|
81
|
-
spec.byteOffset || 0,
|
|
82
|
-
spec.count,
|
|
83
|
-
description.bufferViews[spec.bufferView].byteStride,
|
|
84
|
-
i => i
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
if (spec.sparse) {
|
|
88
|
-
const sparse = spec.sparse, Index = types[sparse.indices.componentType];
|
|
89
|
-
if (![Uint8Array, Uint16Array, Uint32Array].includes(Index)) {
|
|
90
|
-
throw new Error('Invalid sparse glTF indices');
|
|
91
|
-
}
|
|
92
|
-
const view = description.bufferViews[sparse.indices.bufferView];
|
|
93
|
-
const offset = (view.byteOffset || 0) + (sparse.indices.byteOffset || 0);
|
|
94
|
-
if (sparse.count > spec.count || (sparse.indices.byteOffset || 0) + sparse.count * Index.BYTES_PER_ELEMENT > view.byteLength) {
|
|
95
|
-
throw new Error('Invalid sparse glTF indices');
|
|
96
|
-
}
|
|
97
|
-
const indices = new Index(description.buffers[view.buffer].binary.slice(offset, offset + sparse.count * Index.BYTES_PER_ELEMENT));
|
|
98
|
-
read(
|
|
99
|
-
sparse.values.bufferView,
|
|
100
|
-
sparse.values.byteOffset || 0,
|
|
101
|
-
sparse.count,
|
|
102
|
-
0,
|
|
103
|
-
i => {
|
|
104
|
-
if (indices[i] >= spec.count) throw new Error('Invalid sparse glTF index');
|
|
105
|
-
return indices[i];
|
|
106
|
-
}
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
if (spec.componentType === 5126) {
|
|
110
|
-
return { data, size };
|
|
111
|
-
}
|
|
112
|
-
const normalized = new Float32Array(data.length);
|
|
113
|
-
// Normalization is a glTF accessor rule, not sRGB conversion; indices stay integers.
|
|
114
|
-
for (let i = 0; i < data.length; i++) {
|
|
115
|
-
normalized[i] = spec.normalized
|
|
116
|
-
? Math.max(-1, data[i] / (Type === Int8Array ? 127 : Type === Int16Array ? 32767 : Type === Uint8Array ? 255 : Type === Uint32Array ? 4294967295 : 65535))
|
|
117
|
-
: data[i];
|
|
118
|
-
}
|
|
119
|
-
return { data: normalized, size, indices: data };
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** glTF quaternion/translation/scale to a column-major matrix. */
|
|
123
|
-
export function nodeMatrix(spec) {
|
|
124
|
-
if (spec.matrix) return Array.from(spec.matrix);
|
|
125
|
-
// glTF stores quaternions [x,y,z,w]; convert directly to a scaled column-major matrix.
|
|
126
|
-
const [x, y, z, w] = spec.rotation || [0, 0, 0, 1],
|
|
127
|
-
[sx, sy, sz] = spec.scale || [1, 1, 1];
|
|
128
|
-
return [
|
|
129
|
-
(1 - 2 * (y * y + z * z)) * sx,
|
|
130
|
-
2 * (x * y + z * w) * sx,
|
|
131
|
-
2 * (x * z - y * w) * sx,
|
|
132
|
-
0,
|
|
133
|
-
2 * (x * y - z * w) * sy,
|
|
134
|
-
(1 - 2 * (x * x + z * z)) * sy,
|
|
135
|
-
2 * (y * z + x * w) * sy, 0,
|
|
136
|
-
2 * (x * z + y * w) * sz,
|
|
137
|
-
2 * (y * z - x * w) * sz,
|
|
138
|
-
(1 - 2 * (x * x + y * y)) * sz,
|
|
139
|
-
0,
|
|
140
|
-
...(spec.translation || [0, 0, 0]),
|
|
141
|
-
1,
|
|
142
|
-
];
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/** Area-weighted vertex normals, for indexed or non-indexed triangles. */
|
|
146
|
-
export function vertexNormals(p, indices) {
|
|
147
|
-
// Accumulate area-weighted face normals for shared vertices, then normalize.
|
|
148
|
-
const normals = new Float32Array(p.length);
|
|
149
|
-
for (let i = 0; i < (indices?.length || p.length / 3); i += 3) {
|
|
150
|
-
const a = indices ? indices[i] : i,
|
|
151
|
-
b = indices ? indices[i + 1] : i + 1,
|
|
152
|
-
c = indices ? indices[i + 2] : i + 2;
|
|
153
|
-
const u = [0, 1, 2].map(j => p[b * 3 + j] - p[a * 3 + j]), v = [0, 1, 2].map(j => p[c * 3 + j] - p[a * 3 + j]);
|
|
154
|
-
const n = [u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0]];
|
|
155
|
-
for (const index of [a, b, c]) {
|
|
156
|
-
for (let j = 0; j < 3; j++) {
|
|
157
|
-
normals[index * 3 + j] += n[j];
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
for (let i = 0; i < normals.length; i += 3) {
|
|
162
|
-
const length = Math.hypot(...normals.subarray(i, i + 3)) || 1;
|
|
163
|
-
for (let j = 0; j < 3; j++) {
|
|
164
|
-
normals[i + j] /= length;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return normals;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/** Translate glTF sampler constants into WebGPU sampler options. */
|
|
171
|
-
export function textureSampler(sampler) {
|
|
172
|
-
return {
|
|
173
|
-
addressModeU: sampler.wrapS === 33071 ? 'clamp-to-edge' : sampler.wrapS === 33648 ? 'mirror-repeat' : 'repeat',
|
|
174
|
-
addressModeV: sampler.wrapT === 33071 ? 'clamp-to-edge' : sampler.wrapT === 33648 ? 'mirror-repeat' : 'repeat',
|
|
175
|
-
magFilter: sampler.magFilter === 9728 ? 'nearest' : 'linear',
|
|
176
|
-
minFilter: sampler.minFilter === 9728 || sampler.minFilter === 9984 || sampler.minFilter === 9986 ? 'nearest' : 'linear',
|
|
177
|
-
};
|
|
178
|
-
}
|
package/src/utils/picking.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { computeBounds } from './geometry.js';
|
|
2
|
-
|
|
3
|
-
/** Nearest triangle hit per mesh, sorted by world-space distance. */
|
|
4
|
-
export function intersectMeshes(ray, meshes, night = 0) {
|
|
5
|
-
const hits = [],
|
|
6
|
-
a = [0, 0, 0],
|
|
7
|
-
b = [0, 0, 0],
|
|
8
|
-
c = [0, 0, 0],
|
|
9
|
-
sub = (a, b) => a.map((v, i) => v - b[i]),
|
|
10
|
-
cross = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]],
|
|
11
|
-
dot = (a, b) => a.reduce((sum, v, i) => sum + v * b[i], 0);
|
|
12
|
-
for (const mesh of meshes) {
|
|
13
|
-
// Test in mesh-local space; compare distances only after returning to shared world space.
|
|
14
|
-
const inverse = new DOMMatrix(mesh.worldMatrix).inverse();
|
|
15
|
-
const inverseValues = inverse.toFloat64Array();
|
|
16
|
-
if (![...inverseValues].every(Number.isFinite)) {
|
|
17
|
-
throw new Error('Singular 3D transform');
|
|
18
|
-
}
|
|
19
|
-
const localOrigin = new DOMPoint(...ray.origin, 1).matrixTransform(inverse);
|
|
20
|
-
const origin = [
|
|
21
|
-
localOrigin.x / localOrigin.w,
|
|
22
|
-
localOrigin.y / localOrigin.w,
|
|
23
|
-
localOrigin.z / localOrigin.w
|
|
24
|
-
];
|
|
25
|
-
const localDirection = new DOMPoint(...ray.direction, 0).matrixTransform(inverse);
|
|
26
|
-
const direction = [
|
|
27
|
-
localDirection.x,
|
|
28
|
-
localDirection.y,
|
|
29
|
-
localDirection.z
|
|
30
|
-
];
|
|
31
|
-
const directionLength = Math.hypot(...direction) || 1;
|
|
32
|
-
direction[0] /= directionLength; direction[1] /= directionLength; direction[2] /= directionLength;
|
|
33
|
-
// AABB slab test reuses the same local ray as the triangle test.
|
|
34
|
-
if (!mesh.geometry.bounds) {
|
|
35
|
-
computeBounds(mesh.geometry);
|
|
36
|
-
}
|
|
37
|
-
let near = 0, far = Infinity;
|
|
38
|
-
for (let i = 0; i < 3; i++) {
|
|
39
|
-
if (Math.abs(direction[i]) < 1e-12) {
|
|
40
|
-
if (origin[i] < mesh.geometry.bounds.min[i] || origin[i] > mesh.geometry.bounds.max[i]) {
|
|
41
|
-
far = -Infinity;
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
} else {
|
|
45
|
-
const a = (mesh.geometry.bounds.min[i] - origin[i]) / direction[i],
|
|
46
|
-
b = (mesh.geometry.bounds.max[i] - origin[i]) / direction[i];
|
|
47
|
-
near = Math.max(near, Math.min(a, b));
|
|
48
|
-
far = Math.min(far, Math.max(a, b));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
if (far < near) {
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
const { position, index } = mesh.geometry.attributes;
|
|
55
|
-
let closest = Infinity, faceIndex;
|
|
56
|
-
for (let i = 0; i < (index?.count || position.count); i += 3) {
|
|
57
|
-
const ai = (index ? index.data[i] : i) * position.size;
|
|
58
|
-
const bi = (index ? index.data[i + 1] : i + 1) * position.size;
|
|
59
|
-
const ci = (index ? index.data[i + 2] : i + 2) * position.size;
|
|
60
|
-
a[0] = position.data[ai];
|
|
61
|
-
a[1] = position.data[ai + 1];
|
|
62
|
-
a[2] = position.data[ai + 2];
|
|
63
|
-
b[0] = position.data[bi];
|
|
64
|
-
b[1] = position.data[bi + 1];
|
|
65
|
-
b[2] = position.data[bi + 2];
|
|
66
|
-
c[0] = position.data[ci];
|
|
67
|
-
c[1] = position.data[ci + 1];
|
|
68
|
-
c[2] = position.data[ci + 2];
|
|
69
|
-
// Moller-Trumbore: barycentric triangle coordinates and local ray distance.
|
|
70
|
-
const e = sub(b, a),
|
|
71
|
-
f = sub(c, a),
|
|
72
|
-
p = cross(direction, f),
|
|
73
|
-
det = dot(e, p);
|
|
74
|
-
if (mesh.program.cullFace !== null ? det < 1e-9 : Math.abs(det) < 1e-9) {
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
const t = sub(origin, a),
|
|
78
|
-
u = dot(t, p) / det;
|
|
79
|
-
if (u < 0 || u > 1) {
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
const q = cross(t, e),
|
|
83
|
-
v = dot(direction, q) / det;
|
|
84
|
-
if (v < 0 || u + v > 1) {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (mesh.program.nightLight) {
|
|
88
|
-
const uv = mesh.geometry.attributes.uv.data;
|
|
89
|
-
const ids = index ? [index.data[i], index.data[i + 1], index.data[i + 2]] : [i, i + 1, i + 2];
|
|
90
|
-
const x = uv[ids[0] * 2] * (1 - u - v) + uv[ids[1] * 2] * u + uv[ids[2] * 2] * v;
|
|
91
|
-
const y = uv[ids[0] * 2 + 1] * (1 - u - v) + uv[ids[1] * 2 + 1] * u + uv[ids[2] * 2 + 1] * v;
|
|
92
|
-
if (x <= 2 && (!night || x * x + y * y > 0.9)) continue;
|
|
93
|
-
}
|
|
94
|
-
const distance = dot(f, q) / det;
|
|
95
|
-
if (distance > 0 && distance < closest) {
|
|
96
|
-
closest = distance; faceIndex = i / 3;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
if (faceIndex === undefined) continue;
|
|
100
|
-
const point = new DOMPoint(
|
|
101
|
-
direction[0] * closest + origin[0],
|
|
102
|
-
direction[1] * closest + origin[1],
|
|
103
|
-
direction[2] * closest + origin[2],
|
|
104
|
-
1
|
|
105
|
-
).matrixTransform(new DOMMatrix(mesh.worldMatrix));
|
|
106
|
-
const worldPoint = [point.x / point.w, point.y / point.w, point.z / point.w];
|
|
107
|
-
hits.push({
|
|
108
|
-
faceIndex,
|
|
109
|
-
object: mesh,
|
|
110
|
-
point: worldPoint,
|
|
111
|
-
distance: Math.hypot(
|
|
112
|
-
worldPoint[0] - ray.origin[0],
|
|
113
|
-
worldPoint[1] - ray.origin[1],
|
|
114
|
-
worldPoint[2] - ray.origin[2]
|
|
115
|
-
)
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
return hits.sort((a, b) => a.distance - b.distance);
|
|
119
|
-
}
|
package/src/utils/pmtiles.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
export async function decompress(data, compression) {
|
|
2
|
-
if (compression === 1) return data;
|
|
3
|
-
if (compression !== 2) throw new Error(`Unsupported PMTiles compression: ${compression}`);
|
|
4
|
-
return new Response(new Blob([data]).stream().pipeThrough(new DecompressionStream('gzip'))).arrayBuffer();
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/** Decode the PMTiles v3 header. */
|
|
8
|
-
export function decodeHeader(data) {
|
|
9
|
-
if (data.byteLength < 127 || new TextDecoder().decode(new Uint8Array(data, 0, 7)) !== 'PMTiles' ||
|
|
10
|
-
new Uint8Array(data)[7] !== 3) throw new Error('Expected a PMTiles v3 archive');
|
|
11
|
-
const view = new DataView(data);
|
|
12
|
-
const header = {};
|
|
13
|
-
['rootDirectoryOffset', 'rootDirectoryLength', 'jsonMetadataOffset', 'jsonMetadataLength', 'leafDirectoryOffset', 'leafDirectoryLength', 'tileDataOffset', 'tileDataLength', 'numAddressedTiles', 'numTileEntries', 'numTileContents'].forEach((name, i) => { header[name] = Number(view.getBigUint64(8 + i * 8, true)); });
|
|
14
|
-
['clustered', 'internalCompression', 'tileCompression', 'tileType', 'minZoom', 'maxZoom'].forEach((name, i) => { header[name] = view.getUint8(96 + i); });
|
|
15
|
-
['minLon', 'minLat', 'maxLon', 'maxLat'].forEach((name, i) => { header[name] = view.getInt32(102 + i * 4, true) / 1e7; });
|
|
16
|
-
header.centerZoom = view.getUint8(118);
|
|
17
|
-
header.centerLon = view.getInt32(119, true) / 1e7;
|
|
18
|
-
header.centerLat = view.getInt32(123, true) / 1e7;
|
|
19
|
-
return header;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Cumulative Hilbert ID for an archive tile. */
|
|
23
|
-
export function tileId(z, x, y) {
|
|
24
|
-
if (![z, x, y].every(Number.isInteger) || z < 0 || z > 26 ||
|
|
25
|
-
x < 0 || y < 0 || x >= 2 ** z || y >= 2 ** z) throw new Error('Invalid PMTiles tile coordinates');
|
|
26
|
-
let id = (4 ** z - 1) / 3;
|
|
27
|
-
const n = 2 ** z;
|
|
28
|
-
// Same cumulative Hilbert ordering used by build/pmtiles.js.
|
|
29
|
-
for (let s = n / 2; s >= 1; s /= 2) {
|
|
30
|
-
const rx = (x & s) ? 1 : 0,
|
|
31
|
-
ry = (y & s) ? 1 : 0;
|
|
32
|
-
id += s * s * ((3 * rx) ^ ry);
|
|
33
|
-
if (!ry) {
|
|
34
|
-
if (rx) { x = n - 1 - x; y = n - 1 - y; }
|
|
35
|
-
[x, y] = [y, x];
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return id;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** Decode delta/varint directory columns, rejecting malformed entries. */
|
|
42
|
-
export function decodeDirectory(data) {
|
|
43
|
-
const bytes = new Uint8Array(data);
|
|
44
|
-
let cursor = 0;
|
|
45
|
-
const varint = () => {
|
|
46
|
-
let value = 0;
|
|
47
|
-
for (let factor = 1; factor <= 2 ** 49; factor *= 128) {
|
|
48
|
-
if (cursor >= bytes.length) throw new Error('Truncated PMTiles directory');
|
|
49
|
-
const byte = bytes[cursor++];
|
|
50
|
-
value += (byte & 127) * factor;
|
|
51
|
-
if (!Number.isSafeInteger(value)) throw new Error('Invalid PMTiles directory integer');
|
|
52
|
-
if (byte < 128) return value;
|
|
53
|
-
}
|
|
54
|
-
throw new Error('Invalid PMTiles directory integer');
|
|
55
|
-
};
|
|
56
|
-
const count = varint();
|
|
57
|
-
if (count > (bytes.length - cursor) / 4) throw new Error('Invalid PMTiles directory count');
|
|
58
|
-
const entries = [];
|
|
59
|
-
let tileId = 0;
|
|
60
|
-
for (let i = 0; i < count; i++) {
|
|
61
|
-
tileId += varint();
|
|
62
|
-
if (!Number.isSafeInteger(tileId) || (i && tileId <= entries[i - 1].tileId)) {
|
|
63
|
-
throw new Error('Invalid PMTiles directory tile IDs');
|
|
64
|
-
}
|
|
65
|
-
entries.push({ tileId });
|
|
66
|
-
}
|
|
67
|
-
for (const entry of entries) entry.runLength = varint();
|
|
68
|
-
for (const entry of entries) {
|
|
69
|
-
entry.length = varint();
|
|
70
|
-
if (!entry.length) throw new Error('Invalid PMTiles directory length');
|
|
71
|
-
}
|
|
72
|
-
entries.forEach((entry, i) => {
|
|
73
|
-
const value = varint();
|
|
74
|
-
if (!value && !i) throw new Error('Invalid PMTiles directory offset');
|
|
75
|
-
entry.offset = value ? value - 1 : entries[i - 1].offset + entries[i - 1].length;
|
|
76
|
-
});
|
|
77
|
-
if (cursor !== bytes.length) throw new Error('Trailing PMTiles directory data');
|
|
78
|
-
return entries;
|
|
79
|
-
}
|