feat: suivi par patch — décomposition MULTIPOLYGON avec distance et surface par patch
ST_Dump sur la dernière observation → 5 patches les plus proches dans 200km, exposés
dans /spots/{id}/score. SpotPanel affiche le nombre de patches et la distance+surface
de chacun sous forme de barres (échelle 0–100km).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,7 @@ class SpotScoreController extends AbstractController
|
||||
'type' => $spot->getType(),
|
||||
'region' => $spot->getRegion(),
|
||||
'score' => $current,
|
||||
'patches' => $this->loadPatches($id),
|
||||
'horizons' => $this->loadHorizonScores($id, $currentDistanceKm),
|
||||
]);
|
||||
}
|
||||
@@ -207,6 +208,45 @@ class SpotScoreController extends AbstractController
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Décompose la dernière observation en patches individuels (ST_Dump)
|
||||
* et retourne les 5 plus proches du spot dans un rayon de 200 km.
|
||||
*
|
||||
* @return array<int, array{areaKm2: float, distanceKm: float}>|null
|
||||
*/
|
||||
private function loadPatches(string $spotId): ?array
|
||||
{
|
||||
$rows = $this->connection->fetchAllAssociative(
|
||||
'SELECT
|
||||
ROUND(CAST(ST_Area(dump.geom::geography) / 1000000 AS numeric), 2) AS area_km2,
|
||||
ROUND(CAST(ST_Distance(cp.geometry::geography, dump.geom::geography) / 1000 AS numeric), 2) AS distance_km
|
||||
FROM coastal_point cp
|
||||
CROSS JOIN LATERAL (
|
||||
SELECT (ST_Dump(o.geometry)).geom AS geom
|
||||
FROM sargassum_observation o
|
||||
WHERE o.id = (
|
||||
SELECT o2.id FROM sargassum_observation o2
|
||||
INNER JOIN sargassum_forecast ff ON ff.source_observation_id = o2.id
|
||||
ORDER BY o2.detected_at DESC LIMIT 1
|
||||
)
|
||||
) dump
|
||||
WHERE cp.id = :spotId
|
||||
AND ST_Distance(cp.geometry::geography, dump.geom::geography) < 200000
|
||||
ORDER BY distance_km ASC
|
||||
LIMIT 5',
|
||||
['spotId' => $spotId]
|
||||
);
|
||||
|
||||
if (empty($rows)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array_map(
|
||||
fn(array $r) => ['areaKm2' => (float) $r['area_km2'], 'distanceKm' => (float) $r['distance_km']],
|
||||
$rows
|
||||
);
|
||||
}
|
||||
|
||||
private function scoreToLevel(int $score): string
|
||||
{
|
||||
return match (true) {
|
||||
|
||||
Reference in New Issue
Block a user