fix(rover): clip heatmap to drive-radius circle on render
This commit is contained in:
parent
c1eabb788f
commit
083c393bc8
1 changed files with 35 additions and 16 deletions
|
|
@ -200,13 +200,15 @@ export const RoverMap: Partial<RoverMapHook> = {
|
|||
for (const c of cells) {
|
||||
this.cellLookup.set(cellKey(c.lat, c.lon), c)
|
||||
}
|
||||
// Update radius before (re)drawing so the per-pixel clip uses the
|
||||
// new value, otherwise the first paint can leak past the circle.
|
||||
this.setDriveRadius(drive_radius_km)
|
||||
if (!this.qualityLayer) {
|
||||
this.qualityLayer = this.buildQualityLayer()
|
||||
this.qualityLayer.addTo(this.map)
|
||||
} else {
|
||||
this.qualityLayer.redraw()
|
||||
}
|
||||
this.setDriveRadius(drive_radius_km)
|
||||
})
|
||||
|
||||
this.handleEvent("focus_cell", (
|
||||
|
|
@ -338,27 +340,44 @@ export const RoverMap: Partial<RoverMapHook> = {
|
|||
}
|
||||
}
|
||||
|
||||
// Clip the heatmap to the drive-radius circle: pixels farther
|
||||
// than driveRadiusKm from home stay transparent so the overlay
|
||||
// never extends past the dashed circle.
|
||||
const cosLat = Math.cos(self.homeLat * Math.PI / 180)
|
||||
const kmPerPxX = lonPerPx * 111.0 * Math.max(cosLat, 0.1)
|
||||
const kmPerPxY = latPerPx * 111.0
|
||||
const homePxX = (self.homeLon - nw.lng) / lonPerPx
|
||||
const homePxY = (nw.lat - self.homeLat) / latPerPx
|
||||
const radiusKmSq = self.driveRadiusKm * self.driveRadiusKm
|
||||
|
||||
const img = ctx.createImageData(w, h)
|
||||
const data = img.data
|
||||
|
||||
for (let i = 0; i < w * h; i++) {
|
||||
let bestAlpha = 0
|
||||
let bestRgb: [number, number, number] | null = null
|
||||
for (let py = 0; py < h; py++) {
|
||||
const dyKm = (py - homePxY) * kmPerPxY
|
||||
for (let px = 0; px < w; px++) {
|
||||
const dxKm = (px - homePxX) * kmPerPxX
|
||||
if (dxKm * dxKm + dyKm * dyKm > radiusKmSq) continue
|
||||
|
||||
for (const tierColor of TIER_ORDER) {
|
||||
const a = tierBuffers[tierColor][i]
|
||||
if (a > 0.05 && a > bestAlpha) {
|
||||
bestAlpha = a
|
||||
bestRgb = TIER_RGB[tierColor]
|
||||
const i = py * w + px
|
||||
let bestAlpha = 0
|
||||
let bestRgb: [number, number, number] | null = null
|
||||
|
||||
for (const tierColor of TIER_ORDER) {
|
||||
const a = tierBuffers[tierColor][i]
|
||||
if (a > 0.05 && a > bestAlpha) {
|
||||
bestAlpha = a
|
||||
bestRgb = TIER_RGB[tierColor]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestRgb && bestAlpha > 0) {
|
||||
const o = i * 4
|
||||
data[o] = bestRgb[0]
|
||||
data[o + 1] = bestRgb[1]
|
||||
data[o + 2] = bestRgb[2]
|
||||
data[o + 3] = Math.min(255, Math.round(bestAlpha * 0.35 * 255))
|
||||
if (bestRgb && bestAlpha > 0) {
|
||||
const o = i * 4
|
||||
data[o] = bestRgb[0]
|
||||
data[o + 1] = bestRgb[1]
|
||||
data[o + 2] = bestRgb[2]
|
||||
data[o + 3] = Math.min(255, Math.round(bestAlpha * 0.35 * 255))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue