# RFCP - Iteration 8.1: Clone Fix + Coverage Gaps ## Issue 1: Clone Creates New Site (Critical!) **Problem:** Clone button creates new site instead of adding sector to existing site. **Root Cause:** `cloneSector` function in sites store creates new site object. ### Solution **File:** `frontend/src/store/sites.ts` **Current (WRONG):** ```typescript const cloneSector = (siteId: string) => { const site = sites.find(s => s.id === siteId); const clone = { ...site, id: uuid(), name: `${site.name}-clone` }; setSites([...sites, clone]); // Creates NEW site ❌ }; ``` **Fixed (CORRECT):** ```typescript const cloneSector = (siteId: string) => { const site = sites.find(s => s.id === siteId); if (!site) return; // Get last sector as template const lastSector = site.sectors[site.sectors.length - 1]; // Create new sector (NOT new site!) const newSector: Sector = { ...lastSector, id: `sector-${Date.now()}`, azimuth: (lastSector.azimuth + 120) % 360, // 120° offset for tri-sector }; // Add sector to EXISTING site ✅ updateSite(siteId, { sectors: [...site.sectors, newSector] }); // Clear coverage to force recalculation useCoverageStore.getState().clearCoverage(); }; ``` ### Update Button Label **File:** `frontend/src/components/panels/SiteList.tsx` ```typescript ``` --- ## Issue 2: Coverage Gaps at 800m Wide **Problem:** At 800m heatmap radius with 300m resolution, coverage points don't overlap enough → visible dots. **Why it happens:** - Resolution: 300m (distance between coverage points) - Heatmap radius: 800m - At high zoom, 800m radius in pixels is HUGE - But point spacing (300m) stays same - Result: Gaps between points visible ### Solution A: Warn User (Quick) **File:** `frontend/src/components/panels/CoverageSettings.tsx` ```typescript {/* Warning for 800m */} {heatmapRadius === 800 && resolution > 200 && (
⚠️ Wide radius works best with fine resolution (≤200m). Current: {resolution}m. Consider reducing for smoother coverage.
)} ``` ### Solution B: Auto-adjust Resolution (Better) **File:** `frontend/src/store/coverage.ts` ```typescript const calculateCoverage = async () => { // Auto-adjust resolution based on heatmap radius // Rule: resolution should be ≤ radius/2 for smooth coverage const recommendedResolution = Math.min( resolution, Math.floor(heatmapRadius / 2) ); if (recommendedResolution < resolution) { console.log(`Auto-adjusting resolution: ${resolution}m → ${recommendedResolution}m for ${heatmapRadius}m radius`); } const effectiveResolution = recommendedResolution; // Calculate with adjusted resolution await worker.calculateCoverage({ sites, radius, resolution: effectiveResolution, rsrpThreshold }); }; ``` ### Solution C: Dynamic Point Sampling (Advanced) **File:** `frontend/src/components/map/HeatmapTileRenderer.ts` Add adaptive point sampling in renderer: ```typescript private drawPoint( intensityMap: Float32Array, point: CoveragePoint, centerX: number, centerY: number, radiusPixels: number ): void { // ... existing code // ADAPTIVE: If radius is very large, increase sampling const sampleFactor = radiusPixels > 100 ? 2 : 1; for (let y = minY; y < maxY; y += sampleFactor) { for (let x = minX; x < maxX; x += sampleFactor) { // ... draw with interpolation } } } ``` ### Solution D: Clamp Max Radius (Safest) **File:** `frontend/src/components/panels/CoverageSettings.tsx` ```typescript // Limit radius based on resolution const maxAllowedRadius = resolution * 3; // 3x resolution max ``` --- ## Issue 3: Coverage Not Cleared on Sector Delete **File:** `frontend/src/store/sites.ts` ```typescript const removeSector = (siteId: string, sectorId: string) => { const site = sites.find(s => s.id === siteId); if (!site || site.sectors.length <= 1) { toast.error('Cannot remove last sector'); return; } const updatedSectors = site.sectors.filter(s => s.id !== sectorId); updateSite(siteId, { sectors: updatedSectors }); // CRITICAL: Clear coverage! useCoverageStore.getState().clearCoverage(); toast.success('Sector removed. Recalculate coverage to update.'); }; ``` --- ## Recommended Fix Priority **Priority 1 (Critical):** - [ ] Fix cloneSector to add sector, not create site - [ ] Update button label to "+ Add Sector" - [ ] Clear coverage on sector delete **Priority 2 (Important):** - [ ] Add warning for 800m + 300m combo - [ ] OR auto-adjust resolution based on radius **Priority 3 (Nice to have):** - [ ] Clamp max radius based on resolution - [ ] Dynamic point sampling --- ## Testing ### Clone Fix: 1. Create site 2. Click "+ Add Sector" 3. Should show "Sites (1)" with 2 sectors ✅ 4. NOT "Sites (2)" ❌ ### Coverage Gaps: 1. Set resolution 300m 2. Set radius 800m 3. Calculate coverage 4. At high zoom (16+), check for dots 5. If dots visible → show warning OR auto-adjust --- ## Build & Deploy ```bash cd /opt/rfcp/frontend npm run build sudo systemctl reload caddy ``` --- ## Commit Message ``` fix(sites): clone adds sector to existing site, not new site - Fixed cloneSector to add sector to same site - Changed button label to "+ Add Sector" - Added coverage cache clear on sector delete - Sites count now accurate (counts sites, not sectors) fix(coverage): prevent gaps with 800m radius - Added warning for wide radius + coarse resolution - Auto-adjust resolution to radius/2 for smooth coverage - Clear coverage cache on sector changes ``` 🚀 Ready for 8.1!