/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ /** * Small badge in the GeoreferencingPanel header that tells the user * whether their CRS is using a precision NTv2/GeoTIFF datum-shift grid * (sub-decimeter accuracy) or the +towgs84 fallback (up to ~120 m error * for Bessel-based national grids like RD/NL, OSGB/UK, MGI/AT). * * Re-checks on a short interval so it flips from "loading" → "loaded" * after the grid finishes downloading without forcing the parent to * re-render. */ import { useEffect, useState } from 'react'; import { CheckCircle2, AlertTriangle, Loader2 } from 'lucide-react'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { PRECISION_GRIDS, hasFailedPrecisionGrid, hasLoadedPrecisionGrid, } from '@/lib/geo/precision-grids'; interface PrecisionGridBadgeProps { crsName: string | undefined; } function extractEpsgCode(crsName: string | undefined): string | null { if (!crsName) return null; const match = crsName.match(/EPSG[:\s]*(\d+)/i); return match ? match[1] : null; } type BadgeState = 'loading' | 'loaded' | 'failed'; export function PrecisionGridBadge({ crsName }: PrecisionGridBadgeProps) { const code = extractEpsgCode(crsName); const spec = code ? PRECISION_GRIDS[code] : undefined; const [state, setState] = useState(() => { if (!spec) return 'loading'; if (hasLoadedPrecisionGrid(code!)) return 'loaded'; if (hasFailedPrecisionGrid(code!)) return 'failed'; return 'loading'; }); useEffect(() => { if (!spec || state !== 'loading') return; // Poll every 250ms until the grid loader settles (success or failure). // Cheap — PRECISION_GRIDS lookup is O(1) and most CRSs never trigger // this path. Stops as soon as the grid resolves or the component // unmounts. const id = setInterval(() => { if (hasLoadedPrecisionGrid(code!)) { setState('loaded'); } else if (hasFailedPrecisionGrid(code!)) { setState('failed'); } }, 250); return () => clearInterval(id); }, [spec, state, code]); // CRS without a registered precision grid — accuracy depends entirely on // whether its +towgs84 is good (ETRS89/WGS84-aligned CRSs: yes; old // Bessel/Airy national grids: no). Don't show a badge for these. if (!spec) return null; if (state === 'loaded') { return ( grid
Precision NTv2/GeoTIFF grid loaded for {spec.region}.
Sub-decimeter datum-shift accuracy via{' '} {spec.filename}.
); } if (state === 'failed') { return ( grid failed
Precision grid fetch failed for {spec.region}.
Falling back to +towgs84 approximation. Check network access to{' '} cdn.proj.org.
); } return ( loading grid
Fetching precision grid for {spec.region}…
Until it arrives, placement uses the +towgs84 approximation (off by up to ~120 m for this CRS).
); }