feat: fix gps map projection and update map config
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
import { type CameraState } from '../camera/camera'
|
||||
import { type TileStoreStats } from '../tile/tileStore'
|
||||
import { type LonLatPoint } from '../../utils/projection'
|
||||
import { type LonLatPoint, type MapCalibration } from '../../utils/projection'
|
||||
import { type TileZoomBounds } from '../../utils/remoteMapConfig'
|
||||
|
||||
export interface MapScene {
|
||||
tileSource: string
|
||||
osmTileSource: string
|
||||
zoom: number
|
||||
centerTileX: number
|
||||
centerTileY: number
|
||||
exactCenterWorldX: number
|
||||
exactCenterWorldY: number
|
||||
tileBoundsByZoom: Record<number, TileZoomBounds> | null
|
||||
viewportWidth: number
|
||||
viewportHeight: number
|
||||
@@ -21,6 +24,10 @@ export interface MapScene {
|
||||
previewOriginY: number
|
||||
track: LonLatPoint[]
|
||||
gpsPoint: LonLatPoint
|
||||
gpsCalibration: MapCalibration
|
||||
gpsCalibrationOrigin: LonLatPoint
|
||||
osmReferenceEnabled: boolean
|
||||
overlayOpacity: number
|
||||
}
|
||||
|
||||
export type MapRendererStats = TileStoreStats
|
||||
@@ -34,8 +41,8 @@ export interface MapRenderer {
|
||||
|
||||
export function buildCamera(scene: MapScene): CameraState {
|
||||
return {
|
||||
centerWorldX: scene.centerTileX,
|
||||
centerWorldY: scene.centerTileY,
|
||||
centerWorldX: scene.centerTileX + 0.5,
|
||||
centerWorldY: scene.centerTileY + 0.5,
|
||||
viewportWidth: scene.viewportWidth,
|
||||
viewportHeight: scene.viewportHeight,
|
||||
visibleColumns: scene.visibleColumns,
|
||||
@@ -44,5 +51,3 @@ export function buildCamera(scene: MapScene): CameraState {
|
||||
rotationRad: scene.rotationRad,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ const ANIMATION_FRAME_MS = 33
|
||||
|
||||
export class WebGLMapRenderer implements MapRenderer {
|
||||
tileStore: TileStore
|
||||
osmTileStore: TileStore
|
||||
tileLayer: TileLayer
|
||||
osmTileLayer: TileLayer
|
||||
trackLayer: TrackLayer
|
||||
gpsLayer: GpsLayer
|
||||
tileRenderer: WebGLTileRenderer
|
||||
@@ -40,10 +42,19 @@ export class WebGLMapRenderer implements MapRenderer {
|
||||
this.scheduleRender()
|
||||
},
|
||||
} satisfies TileStoreCallbacks)
|
||||
this.osmTileStore = new TileStore({
|
||||
onTileReady: () => {
|
||||
this.scheduleRender()
|
||||
},
|
||||
onTileError: () => {
|
||||
this.scheduleRender()
|
||||
},
|
||||
} satisfies TileStoreCallbacks)
|
||||
this.tileLayer = new TileLayer()
|
||||
this.osmTileLayer = new TileLayer()
|
||||
this.trackLayer = new TrackLayer()
|
||||
this.gpsLayer = new GpsLayer()
|
||||
this.tileRenderer = new WebGLTileRenderer(this.tileLayer, this.tileStore)
|
||||
this.tileRenderer = new WebGLTileRenderer(this.tileLayer, this.tileStore, this.osmTileLayer, this.osmTileStore)
|
||||
this.vectorRenderer = new WebGLVectorRenderer(this.trackLayer, this.gpsLayer)
|
||||
this.scene = null
|
||||
this.renderTimer = 0
|
||||
@@ -94,6 +105,7 @@ export class WebGLMapRenderer implements MapRenderer {
|
||||
this.vectorRenderer.destroy()
|
||||
this.tileRenderer.destroy()
|
||||
this.tileStore.destroy()
|
||||
this.osmTileStore.destroy()
|
||||
this.scene = null
|
||||
}
|
||||
|
||||
|
||||
@@ -53,25 +53,31 @@ export class WebGLTileRenderer {
|
||||
gl: any
|
||||
tileLayer: TileLayer
|
||||
tileStore: TileStore
|
||||
osmTileLayer: TileLayer
|
||||
osmTileStore: TileStore
|
||||
dpr: number
|
||||
program: any
|
||||
positionBuffer: any
|
||||
texCoordBuffer: any
|
||||
positionLocation: number
|
||||
texCoordLocation: number
|
||||
opacityLocation: any
|
||||
textureCache: Map<string, TextureRecord>
|
||||
|
||||
constructor(tileLayer: TileLayer, tileStore: TileStore) {
|
||||
constructor(tileLayer: TileLayer, tileStore: TileStore, osmTileLayer: TileLayer, osmTileStore: TileStore) {
|
||||
this.canvas = null
|
||||
this.gl = null
|
||||
this.tileLayer = tileLayer
|
||||
this.tileStore = tileStore
|
||||
this.osmTileLayer = osmTileLayer
|
||||
this.osmTileStore = osmTileStore
|
||||
this.dpr = 1
|
||||
this.program = null
|
||||
this.positionBuffer = null
|
||||
this.texCoordBuffer = null
|
||||
this.positionLocation = -1
|
||||
this.texCoordLocation = -1
|
||||
this.opacityLocation = null
|
||||
this.textureCache = new Map<string, TextureRecord>()
|
||||
}
|
||||
|
||||
@@ -90,12 +96,13 @@ export class WebGLTileRenderer {
|
||||
this.program = createProgram(
|
||||
gl,
|
||||
'attribute vec2 a_position; attribute vec2 a_texCoord; varying vec2 v_texCoord; void main() { gl_Position = vec4(a_position, 0.0, 1.0); v_texCoord = a_texCoord; }',
|
||||
'precision mediump float; varying vec2 v_texCoord; uniform sampler2D u_texture; void main() { gl_FragColor = texture2D(u_texture, v_texCoord); }',
|
||||
'precision mediump float; varying vec2 v_texCoord; uniform sampler2D u_texture; uniform float u_opacity; void main() { vec4 color = texture2D(u_texture, v_texCoord); gl_FragColor = vec4(color.rgb, color.a * u_opacity); }',
|
||||
)
|
||||
this.positionBuffer = gl.createBuffer()
|
||||
this.texCoordBuffer = gl.createBuffer()
|
||||
this.positionLocation = gl.getAttribLocation(this.program, 'a_position')
|
||||
this.texCoordLocation = gl.getAttribLocation(this.program, 'a_texCoord')
|
||||
this.opacityLocation = gl.getUniformLocation(this.program, 'u_opacity')
|
||||
|
||||
gl.viewport(0, 0, canvasNode.width, canvasNode.height)
|
||||
gl.disable(gl.DEPTH_TEST)
|
||||
@@ -103,6 +110,7 @@ export class WebGLTileRenderer {
|
||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
this.tileStore.attachCanvas(canvasNode)
|
||||
this.osmTileStore.attachCanvas(canvasNode)
|
||||
}
|
||||
|
||||
destroy(): void {
|
||||
@@ -135,24 +143,46 @@ export class WebGLTileRenderer {
|
||||
}
|
||||
|
||||
const gl = this.gl
|
||||
const camera = buildCamera(scene)
|
||||
const tiles = this.tileLayer.prepareTiles(scene, camera, this.tileStore)
|
||||
|
||||
gl.viewport(0, 0, this.canvas.width, this.canvas.height)
|
||||
gl.clearColor(0.8588, 0.9333, 0.8314, 1)
|
||||
gl.clear(gl.COLOR_BUFFER_BIT)
|
||||
gl.useProgram(this.program)
|
||||
|
||||
if (scene.osmReferenceEnabled) {
|
||||
this.renderTilePass(
|
||||
{
|
||||
...scene,
|
||||
tileSource: scene.osmTileSource,
|
||||
tileBoundsByZoom: null,
|
||||
},
|
||||
1,
|
||||
this.osmTileLayer,
|
||||
this.osmTileStore,
|
||||
)
|
||||
}
|
||||
|
||||
this.renderTilePass(
|
||||
scene,
|
||||
scene.osmReferenceEnabled ? scene.overlayOpacity : 1,
|
||||
this.tileLayer,
|
||||
this.tileStore,
|
||||
)
|
||||
}
|
||||
|
||||
renderTilePass(scene: MapScene, opacity: number, tileLayer: TileLayer, tileStore: TileStore): void {
|
||||
const camera = buildCamera(scene)
|
||||
const tiles = tileLayer.prepareTiles(scene, camera, tileStore)
|
||||
|
||||
for (const tile of tiles) {
|
||||
const readyEntry = this.tileStore.getEntry(tile.url)
|
||||
const readyEntry = tileStore.getEntry(tile.url)
|
||||
|
||||
if (readyEntry && readyEntry.status === 'ready' && readyEntry.image) {
|
||||
this.drawEntry(readyEntry, tile.url, 0, 0, readyEntry.image.width || 256, readyEntry.image.height || 256, tile.leftPx, tile.topPx, tile.sizePx, tile.sizePx, scene)
|
||||
this.tileLayer.lastReadyTileCount += 1
|
||||
this.drawEntry(readyEntry, tile.url, 0, 0, readyEntry.image.width || 256, readyEntry.image.height || 256, tile.leftPx, tile.topPx, tile.sizePx, tile.sizePx, scene, opacity)
|
||||
tileLayer.lastReadyTileCount += 1
|
||||
continue
|
||||
}
|
||||
|
||||
const parentFallback = this.tileStore.getParentFallbackSlice(tile, scene)
|
||||
const parentFallback = tileStore.getParentFallbackSlice(tile, scene)
|
||||
if (parentFallback) {
|
||||
this.drawEntry(
|
||||
parentFallback.entry,
|
||||
@@ -166,10 +196,11 @@ export class WebGLTileRenderer {
|
||||
tile.sizePx,
|
||||
tile.sizePx,
|
||||
scene,
|
||||
opacity,
|
||||
)
|
||||
}
|
||||
|
||||
const childFallback = this.tileStore.getChildFallback(tile, scene)
|
||||
const childFallback = tileStore.getChildFallback(tile, scene)
|
||||
if (!childFallback) {
|
||||
continue
|
||||
}
|
||||
@@ -189,6 +220,7 @@ export class WebGLTileRenderer {
|
||||
cellWidth,
|
||||
cellHeight,
|
||||
scene,
|
||||
opacity,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -206,6 +238,7 @@ export class WebGLTileRenderer {
|
||||
drawWidth: number,
|
||||
drawHeight: number,
|
||||
scene: MapScene,
|
||||
opacity: number,
|
||||
): void {
|
||||
if (!this.gl || !entry.image) {
|
||||
return
|
||||
@@ -246,6 +279,7 @@ export class WebGLTileRenderer {
|
||||
texRight, texBottom,
|
||||
])
|
||||
|
||||
gl.uniform1f(this.opacityLocation, opacity)
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture.texture)
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer)
|
||||
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STREAM_DRAW)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { buildCamera, type MapScene } from './mapRenderer'
|
||||
import { type MapScene } from './mapRenderer'
|
||||
import { TrackLayer } from '../layer/trackLayer'
|
||||
import { GpsLayer } from '../layer/gpsLayer'
|
||||
|
||||
@@ -123,9 +123,8 @@ export class WebGLVectorRenderer {
|
||||
}
|
||||
|
||||
const gl = this.gl
|
||||
const camera = buildCamera(scene)
|
||||
const trackPoints = this.trackLayer.projectPoints(scene, camera)
|
||||
const gpsPoint = this.gpsLayer.projectPoint(scene, camera)
|
||||
const trackPoints = this.trackLayer.projectPoints(scene)
|
||||
const gpsPoint = this.gpsLayer.projectPoint(scene)
|
||||
const positions: number[] = []
|
||||
const colors: number[] = []
|
||||
|
||||
@@ -232,3 +231,4 @@ export class WebGLVectorRenderer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user