fix(rover): clip heatmap to drive-radius circle on render

This commit is contained in:
Graham McIntire 2026-04-25 17:35:43 -05:00
parent c1eabb788f
commit 083c393bc8
No known key found for this signature in database
GPG key ID: F4ABF488E6029E59

View file

@ -200,13 +200,15 @@ export const RoverMap: Partial<RoverMapHook> = {
for (const c of cells) { for (const c of cells) {
this.cellLookup.set(cellKey(c.lat, c.lon), c) 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) { if (!this.qualityLayer) {
this.qualityLayer = this.buildQualityLayer() this.qualityLayer = this.buildQualityLayer()
this.qualityLayer.addTo(this.map) this.qualityLayer.addTo(this.map)
} else { } else {
this.qualityLayer.redraw() this.qualityLayer.redraw()
} }
this.setDriveRadius(drive_radius_km)
}) })
this.handleEvent("focus_cell", ( this.handleEvent("focus_cell", (
@ -338,10 +340,26 @@ 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 img = ctx.createImageData(w, h)
const data = img.data const data = img.data
for (let i = 0; i < w * h; i++) { 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
const i = py * w + px
let bestAlpha = 0 let bestAlpha = 0
let bestRgb: [number, number, number] | null = null let bestRgb: [number, number, number] | null = null
@ -361,6 +379,7 @@ export const RoverMap: Partial<RoverMapHook> = {
data[o + 3] = Math.min(255, Math.round(bestAlpha * 0.35 * 255)) data[o + 3] = Math.min(255, Math.round(bestAlpha * 0.35 * 255))
} }
} }
}
ctx.putImageData(img, 0, 0) ctx.putImageData(img, 0, 0)
return tile return tile