feat(abut-rebar): ③ 교대 화면 틀과 확대기초 배근 카드
- ③에서 교대를 고르면 부재 · 교대 목록(받침블럭 → 벽체 → 흉벽·브라켓 → 확대기초 → 날개벽 → 접속슬래브)과 카드를 보여 줌. 확대기초만 규칙이 있고 나머지는 '다음 단계'. 선택한 교대만 3D에 그림 - 확대기초 카드: 보기 탭 3개(교대축 직각 단면 · 교대축 단면 · 상면 평면)와 번호 풍선 강조, 범례, 기본간격 · 배근 방향 ① / ② · 피복 · 여유 · B9 배수 입력, 자동 값(cycle 간격 · B10 위 여유 · l_s · 옆붙임), 철근표(묶음별 실간격 수정 · 수정됨 · 되돌리기, 비고 펼치기), 근거 줄, RB-AF 알림 - 입력은 AbutRecord.rebar.footing에 바꾼 값만 저장 · 프로젝트 파일 검증. fck는 공통 설정의 기초부 값 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e00e43ca61
commit
b06bf368b6
9 files changed
+591
-10
No files matched your search
@@ -8,6 +8,7 @@ import { WING_DIMS_DEFAULT, wingDimsIssues, type WingDims } from './wings';
|
||||
import { ABUT_SHAPE_DEFAULT, normalizeShape, shapeIssues, type AbutShape } from './shape';
|
||||
import { resolveSlab, slabIssues, type AbutSlab, type SlabForm } from './slab';
|
||||
import type { AbutGround } from './ground';
|
||||
import { footingRebarIssues, resolveFootingRebar, type AbutFootingRebarSettings } from './rebar/footing';
|
||||
import { abutBearingRuleIssues, resolveBearingRule, type AbutBearingRule } from './bearing-table';
|
||||
|
||||
export type AbutEditKey = 'seatEl' | 'foundationBottomEl' | 'groundEl' | 'pileLengthMm' | 'skewDeg' | 'slopeI';
|
||||
@@ -164,6 +165,19 @@ export function setAbutGround(rec: AbutRecord, patch: Partial<AbutGround>): Abut
|
||||
return { ...rec, ground };
|
||||
}
|
||||
|
||||
/**
|
||||
* ③ 저판 배근 입력 (2026-11-04): merges the values; undefined removes one (a 철근별 간격 goes back to the 기본간격).
|
||||
* Refused with a Korean message when the settings would not lay out.
|
||||
*/
|
||||
export function applyFootingRebar(rec: AbutRecord, patch: Partial<AbutFootingRebarSettings>): AbutRecord {
|
||||
for (const v of Object.values(patch)) if (typeof v === 'number' && !Number.isFinite(v)) throw new Error('숫자를 입력하세요.');
|
||||
const footing: Partial<AbutFootingRebarSettings> = { ...(rec.rebar?.footing ?? {}), ...patch };
|
||||
for (const key of Object.keys(footing) as (keyof AbutFootingRebarSettings)[]) if (footing[key] === undefined) delete footing[key];
|
||||
const issues = footingRebarIssues(resolveFootingRebar(footing));
|
||||
if (issues.length > 0) throw new Error(issues[0]);
|
||||
return { ...rec, rebar: { ...(rec.rebar ?? {}), footing } };
|
||||
}
|
||||
|
||||
/** Changes one 접속슬래브 dim, refused with a Korean message when the slab would not build. */
|
||||
export function applySlabEdit(rec: AbutRecord, key: (typeof SLAB_EDIT_FIELDS)[number]['key'], value: number): AbutRecord {
|
||||
if (!Number.isFinite(value)) throw new Error('숫자를 입력하세요.');
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { AbutBearingRule } from './bearing-table';
|
||||
import type { WingDims } from './wings';
|
||||
import type { AbutSlab } from './slab';
|
||||
import type { AbutGround } from './ground';
|
||||
import type { AbutFootingRebarSettings } from './rebar/footing';
|
||||
|
||||
type Cell = string | number | null | undefined;
|
||||
type Grid = Cell[][];
|
||||
@@ -65,6 +66,8 @@ export interface AbutRecord {
|
||||
slab?: Partial<AbutSlab>;
|
||||
/** 지반·지층 입력 (② 지반·지층 카드, 교각과 같은 필드). Absent = 육상, 지하수위 없음, 지층 행 없음. */
|
||||
ground?: AbutGround;
|
||||
/** ③ 배근 입력 (부재별, 바꾼 값만). Absent = 엑셀 Abut 시트 기본값. */
|
||||
rebar?: { footing?: Partial<AbutFootingRebarSettings> };
|
||||
/** 예전 "좌우 같게" 값 (2026-11-04 이전 파일). 지금은 읽기만 하고 쓰지 않는다. */
|
||||
wingsLinked?: boolean;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
* What the 3D view draws for the selection (2026-11-03, 형상계획 ②).
|
||||
* In ② only the selected object is drawn: a selected abutment hides the piers, and a selected pier hides the abutments.
|
||||
* In ① (형상 생성) the abutments are always drawn, as before; the piers follow 전체 보기 in ①, not this rule.
|
||||
* In ③ (2026-11-04, 교대 배근) a selected abutment is drawn alone too; with a pier selected, ③ draws as before.
|
||||
*/
|
||||
|
||||
/** True when the pier scene (and its rebar) should be built for this stage and selection. */
|
||||
export function piersShown(stage: string, abutActive: string | null): boolean {
|
||||
return !(stage === 'plan' && abutActive !== null);
|
||||
return !((stage === 'plan' || stage === 'rebar') && abutActive !== null);
|
||||
}
|
||||
|
||||
/** True when the abutment with this name should be drawn. */
|
||||
export function abutShown(stage: string, abutActive: string | null, name: string): boolean {
|
||||
if (stage === 'rebar') return abutActive === null || name === abutActive;
|
||||
if (stage !== 'plan') return true;
|
||||
return name === abutActive;
|
||||
}
|
||||
@@ -162,6 +162,13 @@ export function checkStoredAbutments(list: unknown): void {
|
||||
if (!ok) throw new Error(`${who}: 지반 값 ${key}이(가) 맞지 않습니다.`);
|
||||
}
|
||||
}
|
||||
if (a.rebar !== undefined) {
|
||||
for (const [key, v] of Object.entries(a.rebar.footing ?? {})) {
|
||||
const x: unknown = v;
|
||||
const ok = key === 'dir' ? x === 'skew' || x === 'perp' : finite(x);
|
||||
if (!ok) throw new Error(`${who}: 저판 배근 값 ${key}이(가) 맞지 않습니다.`);
|
||||
}
|
||||
}
|
||||
if (a.wingsLinked !== undefined && typeof a.wingsLinked !== 'boolean') throw new Error(`${who}: 좌우 같게 값이 맞지 않습니다.`);
|
||||
if (a.wings !== undefined) {
|
||||
const forms = ['general', 'short', 'none'];
|
||||
|
||||
Reference in new issue
Block a user