fix(map): fill 3-tier LOD로 타일 seam 해결
- 심해 fill 폴리곤이 globe 타일 경계에서 seam 아티팩트 발생 - bathymetry-fill: z3-7 (depth >= -2000, 천해만) - bathymetry-fill-medium: z7-9 (depth >= -4000) - bathymetry-fill-deep: z9+ (전체 depth) - applyDepthGradient: 3개 fill 레이어 모두 적용 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
부모
2095503e50
커밋
3a001ca9b6
@ -102,7 +102,6 @@ function applyWaterBaseColor(map: maplibregl.Map, fillColor: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function applyDepthGradient(map: maplibregl.Map, stops: DepthColorStop[]) {
|
function applyDepthGradient(map: maplibregl.Map, stops: DepthColorStop[]) {
|
||||||
if (!map.getLayer('bathymetry-fill')) return;
|
|
||||||
const depth = ['to-number', ['get', 'depth']];
|
const depth = ['to-number', ['get', 'depth']];
|
||||||
const sorted = [...stops].sort((a, b) => a.depth - b.depth);
|
const sorted = [...stops].sort((a, b) => a.depth - b.depth);
|
||||||
if (sorted.length === 0) return;
|
if (sorted.length === 0) return;
|
||||||
@ -115,10 +114,13 @@ function applyDepthGradient(map: maplibregl.Map, stops: DepthColorStop[]) {
|
|||||||
if (shallowest.depth < 0) {
|
if (shallowest.depth < 0) {
|
||||||
expr.push(0, lightenHex(shallowest.color, 1.8));
|
expr.push(0, lightenHex(shallowest.color, 1.8));
|
||||||
}
|
}
|
||||||
try {
|
for (const layerId of ['bathymetry-fill', 'bathymetry-fill-medium', 'bathymetry-fill-deep']) {
|
||||||
map.setPaintProperty('bathymetry-fill', 'fill-color', expr as never);
|
if (!map.getLayer(layerId)) continue;
|
||||||
} catch {
|
try {
|
||||||
// ignore
|
map.setPaintProperty(layerId, 'fill-color', expr as never);
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,9 @@ export const SHALLOW_WATER_FILL_DEFAULT = '#14606e';
|
|||||||
export const SHALLOW_WATER_LINE_DEFAULT = '#114f5c';
|
export const SHALLOW_WATER_LINE_DEFAULT = '#114f5c';
|
||||||
|
|
||||||
const BATHY_ZOOM_RANGES: BathyZoomRange[] = [
|
const BATHY_ZOOM_RANGES: BathyZoomRange[] = [
|
||||||
{ id: 'bathymetry-fill', mercator: [3, 24], globe: [3, 24] },
|
{ id: 'bathymetry-fill', mercator: [3, 7], globe: [3, 7] },
|
||||||
|
{ id: 'bathymetry-fill-medium', mercator: [7, 9], globe: [7, 9] },
|
||||||
|
{ id: 'bathymetry-fill-deep', mercator: [9, 24], globe: [9, 24] },
|
||||||
{ id: 'bathymetry-borders-major', mercator: [3, 7], globe: [3, 7] },
|
{ id: 'bathymetry-borders-major', mercator: [3, 7], globe: [3, 7] },
|
||||||
{ id: 'bathymetry-borders', mercator: [7, 24], globe: [7, 24] },
|
{ id: 'bathymetry-borders', mercator: [7, 24], globe: [7, 24] },
|
||||||
{ id: 'bathymetry-lines-coarse', mercator: [5, 7], globe: [5, 7] },
|
{ id: 'bathymetry-lines-coarse', mercator: [5, 7], globe: [5, 7] },
|
||||||
@ -111,18 +113,47 @@ export function injectOceanBathymetryLayers(style: StyleSpecification, maptilerK
|
|||||||
const depthIn = (depths: number[]) =>
|
const depthIn = (depths: number[]) =>
|
||||||
['in', depth, ['literal', depths]] as unknown[];
|
['in', depth, ['literal', depths]] as unknown[];
|
||||||
|
|
||||||
// === Fill (contour polygons) — 전체 depth, 줌에 따라 자연스럽게 표시 ===
|
// === Fill (contour polygons) — 3-tier LOD ===
|
||||||
|
// 심해 폴리곤이 여러 벡터 타일에 걸칠 때 globe tessellation 타일 경계에서
|
||||||
|
// seam 아티팩트 발생 → 줌아웃에서는 shallow만, 줌인에서 점진적으로 심해 포함
|
||||||
|
const bathyFillPaint = {
|
||||||
|
'fill-color': bathyFillColor,
|
||||||
|
'fill-opacity': ['interpolate', ['linear'], ['zoom'], 0, 0.9, 5, 0.88, 8, 0.84, 10, 0.78],
|
||||||
|
};
|
||||||
|
|
||||||
|
// z3-7: depth >= -2000 (천해만 — 타일 seam 방지)
|
||||||
const bathyFill: LayerSpecification = {
|
const bathyFill: LayerSpecification = {
|
||||||
id: 'bathymetry-fill',
|
id: 'bathymetry-fill',
|
||||||
type: 'fill',
|
type: 'fill',
|
||||||
source: oceanSourceId,
|
source: oceanSourceId,
|
||||||
'source-layer': 'contour',
|
'source-layer': 'contour',
|
||||||
minzoom: 3,
|
minzoom: 3,
|
||||||
|
maxzoom: 7,
|
||||||
|
filter: ['>=', depth, -2000] as unknown as unknown[],
|
||||||
|
paint: bathyFillPaint,
|
||||||
|
} as unknown as LayerSpecification;
|
||||||
|
|
||||||
|
// z7-9: depth >= -4000 (중심해 포함)
|
||||||
|
const bathyFillMedium: LayerSpecification = {
|
||||||
|
id: 'bathymetry-fill-medium',
|
||||||
|
type: 'fill',
|
||||||
|
source: oceanSourceId,
|
||||||
|
'source-layer': 'contour',
|
||||||
|
minzoom: 7,
|
||||||
|
maxzoom: 9,
|
||||||
|
filter: ['>=', depth, -4000] as unknown as unknown[],
|
||||||
|
paint: bathyFillPaint,
|
||||||
|
} as unknown as LayerSpecification;
|
||||||
|
|
||||||
|
// z9+: 전체 depth (풀 디테일 — 뷰포트가 작아 타일 seam 무관)
|
||||||
|
const bathyFillDeep: LayerSpecification = {
|
||||||
|
id: 'bathymetry-fill-deep',
|
||||||
|
type: 'fill',
|
||||||
|
source: oceanSourceId,
|
||||||
|
'source-layer': 'contour',
|
||||||
|
minzoom: 9,
|
||||||
maxzoom: 24,
|
maxzoom: 24,
|
||||||
paint: {
|
paint: bathyFillPaint,
|
||||||
'fill-color': bathyFillColor,
|
|
||||||
'fill-opacity': ['interpolate', ['linear'], ['zoom'], 0, 0.9, 5, 0.88, 8, 0.84, 10, 0.78],
|
|
||||||
},
|
|
||||||
} as unknown as LayerSpecification;
|
} as unknown as LayerSpecification;
|
||||||
|
|
||||||
// === Borders (contour polygon edges) — 2-tier LOD ===
|
// === Borders (contour polygon edges) — 2-tier LOD ===
|
||||||
@ -326,6 +357,8 @@ export function injectOceanBathymetryLayers(style: StyleSpecification, maptilerK
|
|||||||
|
|
||||||
const toInsert = [
|
const toInsert = [
|
||||||
bathyFill,
|
bathyFill,
|
||||||
|
bathyFillMedium,
|
||||||
|
bathyFillDeep,
|
||||||
bathyBordersMajor,
|
bathyBordersMajor,
|
||||||
bathyBorders,
|
bathyBorders,
|
||||||
bathyLinesCoarse,
|
bathyLinesCoarse,
|
||||||
|
|||||||
불러오는 중...
Reference in New Issue
Block a user