From 7bec1ae86d99719d5976b55a1240a685b6fd21e5 Mon Sep 17 00:00:00 2001 From: htlee Date: Mon, 16 Feb 2026 13:44:26 +0900 Subject: [PATCH] =?UTF-8?q?fix(map):=20globe=20=EC=88=98=EC=97=AD=20line?= =?UTF-8?q?=20vertex=20=EC=B4=88=EA=B3=BC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zones-line도 globe tessellation에서 73,300+ vertex로 폭증. globe 모드에서 수역 소스 데이터를 ring당 60점으로 서브샘플링. 원본 2100+ vertex → ~240 vertex → globe tessellation 후 65535 이내. mercator 모드에서는 원본 데이터 유지. Co-Authored-By: Claude Opus 4.6 --- .../src/widgets/map3d/hooks/useZonesLayer.ts | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/apps/web/src/widgets/map3d/hooks/useZonesLayer.ts b/apps/web/src/widgets/map3d/hooks/useZonesLayer.ts index 19b143e..6215356 100644 --- a/apps/web/src/widgets/map3d/hooks/useZonesLayer.ts +++ b/apps/web/src/widgets/map3d/hooks/useZonesLayer.ts @@ -12,6 +12,33 @@ import type { BaseMapId, MapProjectionId } from '../types'; import { kickRepaint, onMapStyleReady } from '../lib/mapCore'; import { guardedSetVisibility } from '../lib/layerHelpers'; +/** Globe tessellation에서 vertex 65535 초과를 방지하기 위해 좌표 수를 줄임. + * 수역 폴리곤(해안선 디테일 2100+ vertex)이 globe에서 70,000+로 폭증하므로 + * ring당 최대 maxPts개로 서브샘플링. 라벨 centroid에는 영향 없음. */ +function simplifyZonesForGlobe(zones: ZonesGeoJson): ZonesGeoJson { + const MAX_PTS = 60; + const subsample = (ring: GeoJSON.Position[]): GeoJSON.Position[] => { + if (ring.length <= MAX_PTS) return ring; + const step = Math.ceil(ring.length / MAX_PTS); + const out: GeoJSON.Position[] = [ring[0]]; + for (let i = step; i < ring.length - 1; i += step) out.push(ring[i]); + out.push(ring[0]); // close ring + return out; + }; + return { + ...zones, + features: zones.features.map((f) => ({ + ...f, + geometry: { + ...f.geometry, + coordinates: f.geometry.coordinates.map((polygon) => + polygon.map((ring) => subsample(ring)), + ), + }, + })), + }; +} + export function useZonesLayer( mapRef: MutableRefObject, projectionBusyRef: MutableRefObject, @@ -61,11 +88,13 @@ export function useZonesLayer( if (!map.isStyleLoaded()) return; try { + // globe: 서브샘플링된 데이터로 vertex 폭증 방지, mercator: 원본 데이터 + const sourceData = projection === 'globe' ? simplifyZonesForGlobe(zones) : zones; const existing = map.getSource(srcId) as GeoJSONSource | undefined; if (existing) { - existing.setData(zones); + existing.setData(sourceData); } else { - map.addSource(srcId, { type: 'geojson', data: zones } as GeoJSONSourceSpecification); + map.addSource(srcId, { type: 'geojson', data: sourceData } as GeoJSONSourceSpecification); } const style = map.getStyle();