feat(abut): 교대 형상·입력 패널과 교각 받침·솔플레이트 개편
- 교대 형상(src/core/abut, 3D 장면, 목록·카메라·맞춤)과 교대 입력 패널 추가 - 교각 받침 기준 카드 제거, 솔플레이트 규칙을 교각별 입력으로 변경 - 받침 ELEVATION·솔플레이트 TABLE을 모델값으로 연결 - 교대 입력값 카드: 형식 행에 시점·종점 표시, 제목을 "A1 입력값 [입력]"으로 변경 - 테스트 614건 통과, 타입 검사 통과 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b1b2ad1ddb
commit
1d31d2f3a9
44 files changed
+2571
-120
No files matched your search
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 교대 부재 · AA3 (2026-11-03, spec_abut §4.3–4.6): 벽체, 흉벽 상단, 저판, 말뚝의 치수와 위치. Pure.
|
||||
*
|
||||
* - 교대축 기준 t: 전면 쪽이 +. 벽체 전면 +1.6 m (교좌면 끝), 배면 −0.8 m (브라켓 배면). 두께 2.4 m.
|
||||
* - 흉벽: t −0.5 ~ 0 m. 상단 EL(s) = 교좌면 EL(구간 ①) + 흉벽 높이 2.5 m + i_b × (s − s_1), i_b = 받침 z의 축 방향 경사.
|
||||
* - 저판: 하면 = 기초 하단 EL, 두께 1.1 m. 폭은 t −1.8 ~ +2.8 m (앞굽 1.2, 뒷굽 1.0, 벽체 2.4). 길이 = 교좌면 길이 L.
|
||||
* - 말뚝: 열 위치 t = −1.15 / +0.85 / +2.15 m. 열 안 본수 = int((L − 1.3)/2.0) + 1, 양끝 0.65 m 띄움, 균등 간격.
|
||||
* 말뚝 선단 EL = 기초 하단 EL − 말뚝길이. (skew 평행사변형에서 열 끝이 밀리는 보정은 아직 없다 — QA-5 이후.)
|
||||
* - 벽체 높이 = 구간 교좌면 EL − (기초 하단 EL + 저판 두께).
|
||||
*/
|
||||
import type { AbutModel } from './geometry';
|
||||
import { resolveShape, type AbutShape, type ResolvedShape } from './shape';
|
||||
|
||||
export interface WallSegment {
|
||||
/** 축 위 구간 범위 (IP1에서 m). */
|
||||
sFrom: number;
|
||||
sTo: number;
|
||||
/** 구간의 교좌면 EL (구간 i). */
|
||||
seatEl: number;
|
||||
/** 벽체 높이 (m) = seat − (footing bottom + footing thickness). */
|
||||
heightM: number;
|
||||
}
|
||||
|
||||
export interface PileRow {
|
||||
/** 횡방향 위치 t (m, 전면 +). */
|
||||
t: number;
|
||||
/** 축 위 말뚝 위치 (IP1에서 m). */
|
||||
s: number[];
|
||||
}
|
||||
|
||||
export interface AbutMembers {
|
||||
/** The shape values in use (defaults merged with the user's changes), in m. */
|
||||
shape: ResolvedShape;
|
||||
wallSegments: WallSegment[];
|
||||
/** 흉벽 상단 EL: s = 0 (IP1 끝)과 s = L (IP3 끝), 축 방향 경사 i_b (소수, + = IP3 쪽으로 올라감). */
|
||||
parapetTopStartEl: number;
|
||||
parapetTopEndEl: number;
|
||||
parapetSlope: number;
|
||||
footingTopEl: number;
|
||||
footingBottomEl: number | undefined;
|
||||
piles: PileRow[];
|
||||
pileBottomEl: number | undefined;
|
||||
}
|
||||
|
||||
/** 흉벽 상단 EL at axial position s (m). */
|
||||
export function parapetTopEl(seatFirst: number, bearingSFirst: number, slope: number, s: number, parapetHeightM: number): number {
|
||||
return seatFirst + parapetHeightM + slope * (s - bearingSFirst);
|
||||
}
|
||||
|
||||
export function buildMembers(model: AbutModel, foundation: { bottomEl?: number; pileLengthMm?: number } = {}, shapeChanges?: Partial<AbutShape>): AbutMembers {
|
||||
const L = model.length;
|
||||
const shape = resolveShape(shapeChanges);
|
||||
const sorted = [...model.bearings].sort((a, b) => a.s - b.s);
|
||||
const bounds = [0, ...model.stepBounds, L];
|
||||
const footingBottomEl = foundation.bottomEl;
|
||||
const footingTopEl = footingBottomEl === undefined ? NaN : footingBottomEl + shape.footingThicknessM;
|
||||
|
||||
const wallSegments: WallSegment[] = sorted.map((b, k) => ({
|
||||
sFrom: bounds[k],
|
||||
sTo: bounds[k + 1],
|
||||
seatEl: b.seatEl,
|
||||
heightM: b.seatEl - footingTopEl,
|
||||
}));
|
||||
|
||||
// 받침 ①(첫 입력)과 마지막 입력 받침이 흉벽 상단선을 정한다 (spec §4.4).
|
||||
const first = model.bearings[0];
|
||||
const last = model.bearings[model.bearings.length - 1];
|
||||
const slope = (last.z - first.z) / (last.s - first.s);
|
||||
const parapetTopStartEl = parapetTopEl(first.seatEl, first.s, slope, 0, shape.parapetHeightM);
|
||||
const parapetTopEndEl = parapetTopEl(first.seatEl, first.s, slope, L, shape.parapetHeightM);
|
||||
|
||||
const count = Math.floor((L - 2 * shape.pileEdgeM) / shape.pileSpacingM) + 1;
|
||||
const spacing = count > 1 ? (L - 2 * shape.pileEdgeM) / (count - 1) : 0;
|
||||
const piles: PileRow[] = shape.pileRowsT.map((t) => ({
|
||||
t,
|
||||
s: Array.from({ length: count }, (_, k) => shape.pileEdgeM + k * spacing),
|
||||
}));
|
||||
const pileBottomEl = footingBottomEl === undefined || foundation.pileLengthMm === undefined ? undefined : footingBottomEl - foundation.pileLengthMm / 1000;
|
||||
|
||||
return {
|
||||
shape,
|
||||
wallSegments,
|
||||
parapetTopStartEl,
|
||||
parapetTopEndEl,
|
||||
parapetSlope: slope,
|
||||
footingTopEl,
|
||||
footingBottomEl,
|
||||
piles,
|
||||
pileBottomEl,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user