feat(rebar,view): coping end height h1, taper h2 and Level width as inputs on ② (1단계)

The three values are inputs on the coping card, with the P1 values (1000 · 1500 · 2100) when absent, and they are tracked
like the other shape inputs. The geometry and the coping rebar read them from one CopingGeom: the U heights follow the
closed form (h1 − 2c) + h2·min(x_s, x_L0)/x_L0, which reproduces the P1 values. The side rows are assumed to keep their
position relative to the Level underside (명세 확인 필요). P1 results are unchanged; the full suite passes.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-23 11:44:44 +09:00
1 parent 5b5db60657
commit 0a5edfb152
9 files changed
+169 -45

No files matched your search

+14 -6
View File
@@ -1,6 +1,7 @@
import { buildAxis, copingSpan, fromAxis, kinkArc, nearKink, toAxis } from './axis';
import { layoutText, resolveRowCounts, rowLayout, type PileGeometry } from './piles';
import type { PierInput, Row } from './types';
import { type CopingGeom, P1_COPING_GEOM } from './coping-geom';
/** Dimensions in m. Sources: intent.PR sheet (P1 rules) and spec.md §3 defaults. */
export const DIM = {
@@ -161,6 +162,8 @@ export interface PierModel {
mitre: Vec2 | null;
levelBottom: number;
endBottom: number;
/** Coping heights and Level width in mm, as used by the coping rebar (1단계). */
copingGeom: CopingGeom;
bearings: BearingLocal[];
blocks: BlockModel[];
columns: ColumnModel[];
@@ -216,6 +219,10 @@ export function buildPier(input: PierInput): PierModel {
const L = input.copingLengthMm / 1000;
const B = input.copingWidthMm / 1000;
// Coping heights and Level width (m): inputs, with the P1 values when absent (1단계).
const copingH1 = (input.copingH1Mm ?? P1_COPING_GEOM.h1) / 1000;
const copingH2 = (input.copingH2Mm ?? P1_COPING_GEOM.h2) / 1000;
const levelW = (input.levelWidthMm ?? P1_COPING_GEOM.levelWidth) / 1000;
const planHalfB = B / 2;
const ip1v: Vec2 = { e: ip1.x, n: ip1.y };
const ip2v: Vec2 = { e: ip2.x, n: ip2.y };
@@ -290,20 +297,20 @@ export function buildPier(input: PierInput): PierModel {
// Columns (spec §4.5). Positions are coping coordinates; a column must stay a Level half-width away from the kink.
const colG = columnPositions(input.type, L);
if (kinkG !== null) {
const near = nearKink(axis, colG.map((g) => sStart + g), DIM.levelWidth / 2);
const near = nearKink(axis, colG.map((g) => sStart + g), levelW / 2);
if (near.length) throw new Error('미실시: 꺾임점 근처(Level 반폭 이내)에 기둥이 있습니다. 기둥 위치를 확인하세요.');
}
const colK = colG.map((g) => (kinkG !== null && g > kinkG ? 1 : 0));
// Coping underside: ends at (top − end height h1 = 1000), Level zone at (top − h1 − h2 taper height = 1500).
const levelBottom = input.copingTopEl - DIM.copingH1 - DIM.copingH2;
const endBottom = input.copingTopEl - DIM.copingH1;
const levelStart = Math.min(...colG) - DIM.levelWidth / 2;
const levelEnd = Math.max(...colG) + DIM.levelWidth / 2;
const levelBottom = input.copingTopEl - copingH1 - copingH2;
const endBottom = input.copingTopEl - copingH1;
const levelStart = Math.min(...colG) - levelW / 2;
const levelEnd = Math.max(...colG) + levelW / 2;
if (levelStart < 0 || levelEnd > L) throw new Error('코핑 길이가 Level 구간보다 짧습니다.');
// Underside from the right end to the left end. Between columns (2·3주형) it drops 300 below Level with 300 × 300 haunches (spec §4.5, Q3).
const underside: [number, number][] = [[L, endBottom]];
const levelZones = [...colG].sort((a, b) => b - a).map((s) => [s - DIM.levelWidth / 2, s + DIM.levelWidth / 2] as const);
const levelZones = [...colG].sort((a, b) => b - a).map((s) => [s - levelW / 2, s + levelW / 2] as const);
levelZones.forEach(([zoneStart, zoneEnd], k) => {
underside.push([zoneEnd, levelBottom], [zoneStart, levelBottom]);
const next = levelZones[k + 1];
@@ -432,6 +439,7 @@ export function buildPier(input: PierInput): PierModel {
mitre: axis.mitre,
levelBottom,
endBottom,
copingGeom: { h1: copingH1 * 1000, h2: copingH2 * 1000, levelWidth: levelW * 1000 },
bearings: [...frontPlaced, ...backPlaced].map((b) => ({ no: b.no, row: b.row, k: b.k, s: b.s, g: b.g, n: b.n, z: b.z })),
blocks,
columns,