@mytec: iter10.3.1 ready for testing

This commit is contained in:
2026-01-30 18:24:45 +02:00
parent 12b5c89355
commit 176df9ddaf
3 changed files with 24 additions and 5 deletions

View File

@@ -380,6 +380,7 @@ export default function App() {
visible={heatmapVisible} visible={heatmapVisible}
opacity={settings.heatmapOpacity} opacity={settings.heatmapOpacity}
radiusMeters={settings.heatmapRadius} radiusMeters={settings.heatmapRadius}
rsrpThreshold={settings.rsrpThreshold}
/> />
<CoverageBoundary <CoverageBoundary
points={coverageResult.points} points={coverageResult.points}

View File

@@ -24,6 +24,7 @@ interface GeographicHeatmapProps {
visible: boolean; visible: boolean;
opacity?: number; opacity?: number;
radiusMeters?: number; radiusMeters?: number;
rsrpThreshold?: number;
} }
export default function GeographicHeatmap({ export default function GeographicHeatmap({
@@ -31,6 +32,7 @@ export default function GeographicHeatmap({
visible, visible,
opacity = 0.7, opacity = 0.7,
radiusMeters = 400, radiusMeters = 400,
rsrpThreshold = -100,
}: GeographicHeatmapProps) { }: GeographicHeatmapProps) {
const map = useMap(); const map = useMap();
const layerRef = useRef<L.GridLayer | null>(null); const layerRef = useRef<L.GridLayer | null>(null);
@@ -53,7 +55,12 @@ export default function GeographicHeatmap({
rendererRef.current.setRadiusMeters(radiusMeters); rendererRef.current.setRadiusMeters(radiusMeters);
}, [radiusMeters]); }, [radiusMeters]);
// Invalidate cache when points change (use length + first/last coords as fingerprint) // Update renderer threshold when prop changes
useEffect(() => {
rendererRef.current.setRsrpThreshold(rsrpThreshold);
}, [rsrpThreshold]);
// Invalidate cache when points or threshold change
useEffect(() => { useEffect(() => {
if (points.length === 0) { if (points.length === 0) {
rendererRef.current.setPointsHash('empty'); rendererRef.current.setPointsHash('empty');
@@ -61,9 +68,9 @@ export default function GeographicHeatmap({
} }
const first = points[0]; const first = points[0];
const last = points[points.length - 1]; const last = points[points.length - 1];
const hash = `${points.length}:${first.lat.toFixed(4)},${first.lon.toFixed(4)}:${last.rsrp}`; const hash = `${points.length}:${first.lat.toFixed(4)},${first.lon.toFixed(4)}:${last.rsrp}:t${rsrpThreshold}`;
rendererRef.current.setPointsHash(hash); rendererRef.current.setPointsHash(hash);
}, [points]); }, [points, rsrpThreshold]);
// Create / destroy GridLayer // Create / destroy GridLayer
const createLayer = useCallback(() => { const createLayer = useCallback(() => {

View File

@@ -34,6 +34,7 @@ export interface HeatmapPoint {
export class HeatmapTileRenderer { export class HeatmapTileRenderer {
private tileSize = 256; private tileSize = 256;
private radiusMeters: number; private radiusMeters: number;
private rsrpThreshold: number;
// LRU cache: key → canvas // LRU cache: key → canvas
private cache = new Map<string, ImageData>(); private cache = new Map<string, ImageData>();
@@ -42,9 +43,10 @@ export class HeatmapTileRenderer {
// Points fingerprint for cache invalidation // Points fingerprint for cache invalidation
private pointsHash = ''; private pointsHash = '';
constructor(radiusMeters = 400, maxCacheSize = 150) { constructor(radiusMeters = 400, maxCacheSize = 150, rsrpThreshold = -100) {
this.radiusMeters = radiusMeters; this.radiusMeters = radiusMeters;
this.maxCacheSize = maxCacheSize; this.maxCacheSize = maxCacheSize;
this.rsrpThreshold = rsrpThreshold;
} }
/** Update the geographic radius of each coverage point. */ /** Update the geographic radius of each coverage point. */
@@ -55,6 +57,14 @@ export class HeatmapTileRenderer {
} }
} }
/** Update the RSRP threshold — points below this are not rendered. */
setRsrpThreshold(threshold: number): void {
if (threshold !== this.rsrpThreshold) {
this.rsrpThreshold = threshold;
this.clearCache();
}
}
/** Call when points change to invalidate cache. */ /** Call when points change to invalidate cache. */
setPointsHash(hash: string): void { setPointsHash(hash: string): void {
if (hash !== this.pointsHash) { if (hash !== this.pointsHash) {
@@ -105,9 +115,10 @@ export class HeatmapTileRenderer {
// still contribute their gaussian tail inside the tile // still contribute their gaussian tail inside the tile
const bufferDeg = (this.radiusMeters / 111_000) * 2; const bufferDeg = (this.radiusMeters / 111_000) * 2;
// Filter relevant points // Filter relevant points — geographic bounds AND RSRP threshold
const relevant = points.filter( const relevant = points.filter(
(p) => (p) =>
p.rsrp >= this.rsrpThreshold &&
p.lat >= latMin - bufferDeg && p.lat >= latMin - bufferDeg &&
p.lat <= latMax + bufferDeg && p.lat <= latMax + bufferDeg &&
p.lon >= lonMin - bufferDeg && p.lon >= lonMin - bufferDeg &&