perf(B06): 카드 기하를 두 번 계산하던 것을 한 번으로

행 높이를 재는 1차와 실제 그리는 2차가 같은 측점의 crossPlotMetrics 를 각각 계산했음.
측점 67곳 기준 3.2ms/장이라 진입에서 draw 자기 시간 213ms 의 대부분이었음
(보조 창 CPU 프로파일).

- crossPlotMetrics 를 crossPlotBase(강제 높이 전) + crossPlotFromBase(높이만 얹기)로
  가름. 기존 시그니처는 둘을 잇는 감싸개로 유지.
- Section_View 1차에서 base 를 만들어 2차 카드에 그대로 넘김.
- 1차 반폭도 카드가 실제로 쓰는 값(effectiveCardHalfWidth, 자동 줌아웃 포함)으로 맞춤 —
  전에는 1차가 원래 반폭으로 재 카드·행 높이 기준이 어긋났음.
- 쓰이지 않게 된 crossCardNaturalHeight 와 그 재수출 삭제.

자체검증(공용 브라우저) — 카드 67장·SVG 67개 그대로, 같은 행 카드 높이 통일 유지
(rowsUniform true), 높이 범위 292~1,119px. 시험 400 통과·17 건너뜀, typecheck 통과.
효과 수치는 보조 창의 격리된 프로젝트에서 3회 중앙값으로 재기로 함(내 창은 편차가 큼).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-06 22:54:12 +09:00
co-authored by Claude Opus 5
parent c0bfcba34b
commit 4df5d0a7ea
3 changed files with 86 additions and 34 deletions
+20 -10
View File
@@ -63,8 +63,12 @@ import {
svgText,
validElevation,
} from "./B06_Section_UI_Section_Common";
import { crossPlotMetrics, effectiveCardHalfWidth } from "./B06_Section_UI_Cross_View_Metrics";
export { crossCardNaturalHeight } from "./B06_Section_UI_Cross_View_Metrics";
import {
type CrossPlotBase,
crossPlotFromBase,
crossPlotMetrics,
effectiveCardHalfWidth,
} from "./B06_Section_UI_Cross_View_Metrics";
/**
* 횡단 카드 요소. 선택 표시와 면적 강조를 **카드를 다시 만들지 않고** 갈아 끼우는 핸들을 단다
@@ -144,6 +148,8 @@ export function createCrossSectionCard(
/** 세월교 측벽·BOX암거 구체 조작 제어(2026-08-25). */
ford?: FordControl,
box?: BoxControl,
/** 행 높이를 재며 이미 만들어 둔 기하 — 있으면 다시 계산하지 않는다(2026-09-06). */
plotBase?: CrossPlotBase | null,
): CrossCardElement {
// 링크 카드 = 구조물이 옆 측점에 서 있고 그 연장이 여기까지 온 경우. 관만 숨기고
// 선택·조정은 연다 — 연동을 풀어 이 측점 위치를 따로 잡을 수 있어야 한다
@@ -274,14 +280,18 @@ export function createCrossSectionCard(
appendCardHeader(card, section, stationInterval, onDesignChange);
const metrics = crossPlotMetrics(
section,
verticalExaggeration,
widthPx,
effectiveHalfWidth,
designElevation,
forcedHeightPx,
);
// 행 높이를 재며 만든 기하가 있으면 그대로 쓴다 — 같은 측점의 기하를 두 번 계산하던
// 것이 B06 진입에서 `draw` 자기 시간의 대부분이었다(2026-09-06 CPU 프로파일).
const metrics = plotBase
? crossPlotFromBase(plotBase, forcedHeightPx)
: crossPlotMetrics(
section,
verticalExaggeration,
widthPx,
effectiveHalfWidth,
designElevation,
forcedHeightPx,
);
if (!metrics) {
card.append(emptyView(L("B06_Profile_View_NoCross")));
} else {