@mytec: iter10.3.1 ready for testing
This commit is contained in:
@@ -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}
|
||||||
|
|||||||
@@ -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(() => {
|
||||||
|
|||||||
@@ -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 &&
|
||||||
|
|||||||
Reference in New Issue
Block a user