Merge pull request 'release: 어구 거리제한' (#139) from develop into main
All checks were successful
Deploy KCG / deploy (push) Successful in 1m58s

This commit is contained in:
htlee 2026-03-20 18:54:18 +09:00
커밋 db352946ae

파일 보기

@ -127,8 +127,8 @@ export function FleetClusterLayer({ ships, analysisMap, clusters, onShipSelect,
// 비허가 어구 클러스터: parentName → { parent: Ship | null, gears: Ship[] } // 비허가 어구 클러스터: parentName → { parent: Ship | null, gears: Ship[] }
const gearGroupMap = useMemo(() => { const gearGroupMap = useMemo(() => {
const gearPattern = /^(.+?)_\d+_\d+_?$/; const gearPattern = /^(.+?)_\d+_\d+_?$/;
const MAX_DIST_DEG = 0.15; // ~10NM — 모선과 어구 간 최대 거리 const MAX_DIST_DEG = 0.15; // ~10NM
const STALE_MS = 60 * 60_000; // 60분 이내 수신 신호만 const STALE_MS = 60 * 60_000;
const now = Date.now(); const now = Date.now();
const nameToShip = new Map<string, Ship>(); const nameToShip = new Map<string, Ship>();
@ -139,26 +139,35 @@ export function FleetClusterLayer({ ships, analysisMap, clusters, onShipSelect,
} }
} }
const map = new Map<string, { parent: Ship | null; gears: Ship[] }>(); // 1단계: 같은 모선명 어구 수집 (60분 이내만)
const rawGroups = new Map<string, Ship[]>();
for (const s of ships) { for (const s of ships) {
// 60분 이내 수신 신호만
if (now - s.lastSeen > STALE_MS) continue; if (now - s.lastSeen > STALE_MS) continue;
const m = (s.name || '').match(gearPattern); const m = (s.name || '').match(gearPattern);
if (!m) continue; if (!m) continue;
const parentName = m[1].trim(); const parentName = m[1].trim();
const arr = rawGroups.get(parentName) ?? [];
arr.push(s);
rawGroups.set(parentName, arr);
}
// 2단계: 거리 기반 서브 클러스터링 (같은 이름이라도 멀면 분리)
const map = new Map<string, { parent: Ship | null; gears: Ship[] }>();
for (const [parentName, gears] of rawGroups) {
const parent = nameToShip.get(parentName) ?? null; const parent = nameToShip.get(parentName) ?? null;
// 모선이 있으면 거리 제한 적용 // 기준점: 모선 있으면 모선 위치, 없으면 첫 어구
if (parent) { const anchor = parent ?? gears[0];
const dlat = Math.abs(s.lat - parent.lat); if (!anchor) continue;
const dlng = Math.abs(s.lng - parent.lng);
if (dlat > MAX_DIST_DEG || dlng > MAX_DIST_DEG) continue;
}
const entry = map.get(parentName) ?? { parent, gears: [] }; const nearby = gears.filter(g => {
entry.gears.push(s); const dlat = Math.abs(g.lat - anchor.lat);
map.set(parentName, entry); const dlng = Math.abs(g.lng - anchor.lng);
return dlat <= MAX_DIST_DEG && dlng <= MAX_DIST_DEG;
});
if (nearby.length === 0) continue;
map.set(parentName, { parent, gears: nearby });
} }
return map; return map;
}, [ships]); }, [ships]);