feat(rebar): 계단부 C15·C16을 모델의 실제 계단으로 만든다 (T형·다주형 공통)
T형은 P1 문서의 고정 위치(2.196~12.000 m)·높이·11개를 써서 코핑 길이가 다르면 철근이 코핑 밖으로 나갔고, 다주형은 높은 계단 전체에 C15 하나만 두었다. 공통 규칙 (step-bars.ts): - 열마다(전·후열 단차가 있으면 각 쪽) 최저 상면 + h_16(100) 이상 구간이 계단, 경계는 mm 반올림 - 이웃보다 모두 높은 구간 C15(⊓), 나머지 계단 C16(L형, 낮은 쪽 다리, 높은 쪽으로 l_d 연장) - 폭 방향: T형은 주철근 내부 격자 하나 건너, 다주형은 상면 주철근 하나 건너 - 양쪽이 높은 계단은 RB-S01 알림, RB-M04 폐지. 꺾임은 편 좌표의 한 개(꺾은 철근) P1 문서값(C15 11 × 3852, C16 22 × 4070/4069, 137.5 · 10@250)을 그대로 재현한다. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9f336e2be4
commit
7340f8c1a1
8 files changed
+263
-105
No files matched your search
+10
-47
@@ -5,6 +5,9 @@
|
||||
import { DEFAULT_MATERIAL, developmentLength, fyOf, hookLength, Material, NOMINAL_DIAMETER } from './common';
|
||||
import { type CopingGeom, P1_COPING_GEOM } from '../coping-geom';
|
||||
import { DEFAULT_COPING_REBAR } from './coping-settings';
|
||||
import { widthLayout } from './coping-main';
|
||||
import { type StepBar, stepBars, STEP_MIN_MM } from './step-bars';
|
||||
import type { PierModel } from '../geometry';
|
||||
export const COPING_REBAR = {
|
||||
/** 피복 (최외측 철근 중심까지). */
|
||||
cover: 100,
|
||||
@@ -138,17 +141,6 @@ export function copingSideBars(L: number, zBottom: number, zBreak: number, g: Co
|
||||
/** C15 (거꾸로 된 U, 3852) and C16 (L형, 4070 / 4069) lengths, mm (코핑철근.md §7). */
|
||||
export const STEP_LENGTHS = { C15: 3852, C16: [4070, 4069] as const, C14: 3447.5 } as const;
|
||||
|
||||
/**
|
||||
* Stair zone of the P1 coping (코핑철근.md §7.1): each segment from x to x (mm from the coping start), and its top rise
|
||||
* above the lowest top (mm). The stair positions are the document's; the model has no stair geometry yet.
|
||||
*/
|
||||
export const STAIR_SEGMENTS = [
|
||||
{ from: 2196, to: 4701, rise: 72 }, // 2구간
|
||||
{ from: 4701, to: 7207, rise: 144 }, // 3구간
|
||||
{ from: 7207, to: 9712, rise: 215 }, // 4구간
|
||||
{ from: 9712, to: 12000, rise: 287 }, // 5구간 (to = L in the document)
|
||||
] as const;
|
||||
|
||||
/** C14 end gap e_14 (코핑철근.md §8.1) and the inset of its ends from the side faces: c + (d_shear + d_14)/2 = 122.25. */
|
||||
const C14_END_GAP = 500;
|
||||
export const C14_INSET = COPING_REBAR.cover + (NOMINAL_DIAMETER.H25 + NOMINAL_DIAMETER.H19) / 2;
|
||||
@@ -212,44 +204,15 @@ export function c14Length(B: number): number {
|
||||
return B - 2 * C14_INSET + 2 * Math.round(hookLength('main90', NOMINAL_DIAMETER.H19)); // legs rounded to mm (296)
|
||||
}
|
||||
|
||||
export interface StepBar {
|
||||
/** Position across the width, mm from the centre line. */
|
||||
n: number;
|
||||
/** Start and end along the coping (mm). */
|
||||
x0: number;
|
||||
x1: number;
|
||||
/** EL of the horizontal run (m). */
|
||||
z: number;
|
||||
/** Legs: C15 hangs at both ends, C16 only at its start. */
|
||||
legs: 'both' | 'start';
|
||||
/** Leg length l_d (mm). */
|
||||
leg: number;
|
||||
/** Developed length (mm): the horizontal run plus the leg(s) at its ends. */
|
||||
length: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* C15 (거꾸로 된 U, on the highest segment) and C16 (L형, on segments 3 and 4), 11 bars each across the width (코핑철근.md §7).
|
||||
* Across: 137 from the cover line, then @pitch (피복선 기준). pitch = 2 × 주철근 기본간격 (승인 2026-10-26; 250 at P1).
|
||||
* Along: from each segment start + c to the next end − c.
|
||||
* C15 · C16 of a T형 coping from the model's own steps (결정 2026-11-10, src/core/rebar/step-bars.ts).
|
||||
* Across: every second interior main-bar grid line from the first (P1: 137.5 from the cover line, 10@250, 11 bars).
|
||||
*/
|
||||
export function stairBars(L: number, B: number, topEl: number, m: Material = DEFAULT_MATERIAL, pitch = 2 * DEFAULT_COPING_REBAR.mainSpacing): { c15: StepBar[]; c16: StepBar[] } {
|
||||
const ld = stepDevLength(m);
|
||||
const c = COPING_REBAR.cover;
|
||||
const ns = Array.from({ length: 11 }, (_, k) => -B / 2 + c + 137 + pitch * k);
|
||||
const seg = STAIR_SEGMENTS;
|
||||
const top = (i: number) => topEl + seg[i].rise / 1000;
|
||||
const c15Z = top(3) - c / 1000;
|
||||
const c16Z = (i: number) => top(i) - c / 1000 - NOMINAL_DIAMETER.H19 / 1000; // (d_C15 + d_C16)/2 = 19.1
|
||||
const x0c15 = seg[3].from + c;
|
||||
const x1c15 = L - c;
|
||||
const c15: StepBar[] = ns.map((n) => ({ n, x0: x0c15, x1: x1c15, z: c15Z, legs: 'both', leg: ld, length: x1c15 - x0c15 + 2 * ld }));
|
||||
const c16: StepBar[] = [1, 2].flatMap((i) => {
|
||||
const x0 = seg[i].from + c;
|
||||
const x1 = seg[i].to - c + ld; // the horizontal run runs on past the segment end by l_d
|
||||
return ns.map((n): StepBar => ({ n, x0, x1, z: c16Z(i), legs: 'start', leg: ld, length: x1 - x0 + ld }));
|
||||
});
|
||||
return { c15, c16 };
|
||||
export function tStepBars(model: PierModel, m: Material = DEFAULT_MATERIAL): { bars: StepBar[]; warnings: string[] } {
|
||||
const B = model.copingB * 1000;
|
||||
const w = widthLayout(B, model.copingRebar);
|
||||
const across = Array.from({ length: Math.floor(w.n / 2) + 1 }, (_, k) => (w.yE + w.g + 2 * k * w.spacing - B / 2) / 1000);
|
||||
return stepBars(model, { cover: COPING_REBAR.cover, ld: stepDevLength(m), d: NOMINAL_DIAMETER.H19, stepMin: STEP_MIN_MM, across });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
import type { PierModel } from '../geometry';
|
||||
import { DEFAULT_MATERIAL, developmentLength, fyOf, hookLength, type Material, NOMINAL_DIAMETER, spliceLength } from './common';
|
||||
import { stepBars } from './step-bars';
|
||||
|
||||
export type CopingPoint = [number, number, number];
|
||||
export interface CopingBar { name: string; size: string; diameterMm: number; pts: CopingPoint[]; length: number }
|
||||
@@ -48,7 +49,7 @@ export const MULTI_REBAR = {
|
||||
standardMm: 8000,
|
||||
/** C14: vertical pitch, pitch along the axis, stagger between rows. */
|
||||
c14Vertical: 0.6, c14Along: 1.2, c14Stagger: 0.6,
|
||||
/** h_16: a step at least this much above the end top gets C15 (m). */
|
||||
/** h_16: a step at least this much above the row's lowest top gets C15 / C16 (m, step-bars.ts). */
|
||||
stepMin: 0.1,
|
||||
} as const;
|
||||
|
||||
@@ -283,18 +284,12 @@ export function multicolCopingInfo(model: PierModel, material: Material = DEFAUL
|
||||
}
|
||||
});
|
||||
|
||||
// --- C15 계단부 (§8): 끝단보다 h_16 이상 높은 계단 전체에 ⊓ 하나 ------------------------------------------
|
||||
const front = model.segments;
|
||||
const endTop = Math.min(front[0].top, front.at(-1)!.top);
|
||||
const high = front.filter(g => g.top - endTop >= MULTI_REBAR.stepMin - 1e-9);
|
||||
if (high.length) {
|
||||
const from = high[0].s0 + c, to = high.at(-1)!.s1 - c;
|
||||
const z15 = Math.min(...high.map(g => g.top)) - c;
|
||||
const ld = developmentLength(d('H19'), fy('H19'), material.fck) / 1000;
|
||||
top.filter((_, i) => i % 2 === 0).forEach(y => add('C15', 'H19', [[from, z15 - ld, y], [from, z15, y], [to, z15, y], [to, z15 - ld, y]]));
|
||||
const above = Math.max(...front.map(g => g.top)) - (z15 + c);
|
||||
if (above > MULTI_REBAR.stepMin + 1e-9) warnings.push({ code: 'RB-M04', message: `가장 높은 계단 상면이 C15보다 ${Math.round(above * 1000)} mm 높습니다 (h_16 ${MULTI_REBAR.stepMin * 1000} 초과). C16 병행은 미정 (Q-M7).` });
|
||||
}
|
||||
// --- C15 · C16 계단부: T형과 같은 규칙 (결정 2026-11-10, step-bars.ts) ---------------------------------------
|
||||
// 가장 높은 계단마다 ⊓ (C15), 그 밖의 계단(최저 상면 + h_16 이상)마다 L형 (C16). 폭 방향은 상면 주철근 하나 건너.
|
||||
const stairs = stepBars(model, { cover: c * 1000, ld: Math.round(developmentLength(d('H19'), fy('H19'), material.fck)), d: d('H19'),
|
||||
stepMin: MULTI_REBAR.stepMin * 1000, across: top.filter((_, i) => i % 2 === 0) });
|
||||
for (const b of stairs.bars) add(b.name, 'H19', b.pts.map(([x, z]): CopingPoint => [x / 1000, z, b.n]));
|
||||
for (const message of stairs.warnings) warnings.push({ code: 'RB-S01', message });
|
||||
|
||||
// RB-M03: 상면 1단 외 철근이 12 m를 넘으면 이음 미정 (Q-M12).
|
||||
const long = [...new Set(bars.filter(x => !['C1', 'C4'].includes(x.name) && x.length > 12000).map(x => x.name))];
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* C15 · C16 계단부 철근, T형·다주형 공통 규칙 (결정 2026-11-10, 코핑철근.md §7을 모델 계단으로 일반화). Pure.
|
||||
*
|
||||
* - 열마다 (전·후열 단차가 있으면 전열·후열 코핑 쪽 각각, 없으면 전체 폭) 그 열의 계단(model.segments / backSegments)을 본다.
|
||||
* 상면이 같은 이웃 구간은 하나로 합친다. 경계는 mm로 반올림한다 (도면 치수, 문서 값 재현).
|
||||
* - 계단 구간 = 그 열의 최저 상면보다 h_16 이상 높은 구간. 없으면 철근 없음.
|
||||
* - C15 (⊓): 이웃보다 모두 높은 구간마다. z = 상면 − c, 수평 = 구간 시작 + c ~ 구간 끝 − c, 다리 양끝 l_d.
|
||||
* - C16 (L): 나머지 계단 구간. 연직 다리는 낮은 쪽 끝 (낮은 이웃 쪽, 코핑 끝에 붙어 안쪽이 높으면 코핑 끝 쪽) + c,
|
||||
* 수평은 높은 쪽으로 구간 끝 − c 에서 l_d 더 (코핑 끝 − c 를 넘지 않음). z = 상면 − c − d_H19.
|
||||
* - 양쪽 이웃이 모두 높은 계단 구간은 규칙 밖이라 철근을 두지 않고 알린다 (RB-S01).
|
||||
* - 꺾인 코핑: 좌표가 코핑을 편 g이므로 꺾임점을 지나는 철근은 꺾은 한 개다 (결정 2026-11-10).
|
||||
* - 다리와 상면 주철근 간섭은 미정으로 둔다 (Q-K10).
|
||||
*/
|
||||
import type { PierModel } from '../geometry';
|
||||
|
||||
/** h_16 (mm): the least rise above the row's lowest top that gets a step bar (코핑철근.md, Q-K10 유지 2026-11-10). */
|
||||
export const STEP_MIN_MM = 100;
|
||||
|
||||
export type StepRow = '전체' | '전열' | '후열';
|
||||
|
||||
export interface StepBar {
|
||||
name: 'C15' | 'C16';
|
||||
row: StepRow;
|
||||
/** Across the width (m, model n). */
|
||||
n: number;
|
||||
/** Horizontal run, x0 < x1 (mm from the coping start), and its EL (m). */
|
||||
x0: number;
|
||||
x1: number;
|
||||
z: number;
|
||||
/** Where the leg(s) hang: both ends (C15), or the start / end of the run (C16). */
|
||||
legs: 'both' | 'start' | 'end';
|
||||
/** Leg length l_d (mm). */
|
||||
leg: number;
|
||||
/** Developed length (mm): run plus leg(s). */
|
||||
length: number;
|
||||
/** Centre line (x mm, EL m) from the first leg end to the last. */
|
||||
pts: [number, number][];
|
||||
}
|
||||
|
||||
export interface StepOptions {
|
||||
/** Cover c (mm). */
|
||||
cover: number;
|
||||
/** Development length l_d (mm). */
|
||||
ld: number;
|
||||
/** H19 diameter (mm): C16 sits this much below its top so it passes under the higher bar. */
|
||||
d: number;
|
||||
/** h_16 (mm). */
|
||||
stepMin: number;
|
||||
/** Candidate positions across the width (m, model n), e.g. every second main-bar grid line. */
|
||||
across: number[];
|
||||
}
|
||||
|
||||
interface Step { s0: number; s1: number; top: number }
|
||||
|
||||
/** Merge neighbours with the same top (within 1 mm) and round the bounds to mm. */
|
||||
function merged(segments: { s0: number; s1: number; top: number }[]): Step[] {
|
||||
const out: Step[] = [];
|
||||
for (const g of segments) {
|
||||
const s = { s0: Math.round(g.s0 * 1000), s1: Math.round(g.s1 * 1000), top: g.top };
|
||||
const last = out[out.length - 1];
|
||||
if (last && Math.abs(last.top - s.top) < 0.001) last.s1 = s.s1;
|
||||
else out.push(s);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export function stepBars(model: PierModel, opt: StepOptions): { bars: StepBar[]; warnings: string[] } {
|
||||
const L = Math.round(model.copingL * 1000);
|
||||
const c = opt.cover;
|
||||
const half = model.copingB / 2;
|
||||
const parts = model.copingParts.filter((p) => p.k === 0);
|
||||
// Rows: with a lateral step the front and back parts (order [front, back]), each to its own width; else the whole width.
|
||||
const rows: { row: StepRow; segments: Step[]; lo: number; hi: number }[] = parts.length === 2 && model.backSegments
|
||||
? ([['전열', model.segments, parts[0]], ['후열', model.backSegments, parts[1]]] as const).map(([row, segs, p]) => ({
|
||||
row,
|
||||
segments: merged(segs),
|
||||
// The split line is a step face inside the coping: keep the cover from it as from the side faces.
|
||||
lo: p.nFrom + (p.nFrom > -half + 1e-9 ? c / 1000 : 0),
|
||||
hi: p.nTo - (p.nTo < half - 1e-9 ? c / 1000 : 0),
|
||||
}))
|
||||
: [{ row: '전체', segments: merged(model.segments), lo: -half, hi: half }];
|
||||
|
||||
const bars: StepBar[] = [];
|
||||
const warnings: string[] = [];
|
||||
for (const r of rows) {
|
||||
const ns = opt.across.filter((n) => n >= r.lo - 1e-9 && n <= r.hi + 1e-9);
|
||||
const zMin = Math.min(...r.segments.map((g) => g.top));
|
||||
r.segments.forEach((g, i) => {
|
||||
if ((g.top - zMin) * 1000 < opt.stepMin - 1e-6) return;
|
||||
const left = r.segments[i - 1], right = r.segments[i + 1];
|
||||
const leftHigher = !!left && left.top > g.top + 1e-6;
|
||||
const rightHigher = !!right && right.top > g.top + 1e-6;
|
||||
const ld = opt.ld;
|
||||
if (!leftHigher && !rightHigher) {
|
||||
const x0 = g.s0 + c, x1 = g.s1 - c, z = g.top - c / 1000;
|
||||
for (const n of ns) bars.push({ name: 'C15', row: r.row, n, x0, x1, z, legs: 'both', leg: ld, length: x1 - x0 + 2 * ld,
|
||||
pts: [[x0, z - ld / 1000], [x0, z], [x1, z], [x1, z - ld / 1000]] });
|
||||
} else if (rightHigher && !leftHigher) {
|
||||
const x0 = g.s0 + c, x1 = Math.min(g.s1 - c + ld, L - c), z = g.top - (c + opt.d) / 1000;
|
||||
for (const n of ns) bars.push({ name: 'C16', row: r.row, n, x0, x1, z, legs: 'start', leg: ld, length: x1 - x0 + ld,
|
||||
pts: [[x0, z - ld / 1000], [x0, z], [x1, z]] });
|
||||
} else if (leftHigher && !rightHigher) {
|
||||
const x1 = g.s1 - c, x0 = Math.max(g.s0 + c - ld, c), z = g.top - (c + opt.d) / 1000;
|
||||
for (const n of ns) bars.push({ name: 'C16', row: r.row, n, x0, x1, z, legs: 'end', leg: ld, length: x1 - x0 + ld,
|
||||
pts: [[x1, z - ld / 1000], [x1, z], [x0, z]] });
|
||||
} else {
|
||||
warnings.push(`${r.row === '전체' ? '' : `${r.row} `}계단 ${(g.s0 / 1000).toFixed(3)}~${(g.s1 / 1000).toFixed(3)} m는 양쪽이 더 높아 C15·C16 규칙 밖입니다. 철근을 두지 않았습니다.`);
|
||||
}
|
||||
});
|
||||
}
|
||||
return { bars, warnings };
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { copingDefaults } from './coping-settings';
|
||||
import { DEFAULT_COLUMN_REBAR } from './column-settings';
|
||||
import { DEFAULT_FOOTING_REBAR, type FootingRebarSettings } from './footing-settings';
|
||||
import { bottomPiece, topBarLength, widthLayout, topSplicePieces } from './coping-main';
|
||||
import { shearBars, shearBarsMulti, copingSideBars, SIDE_HOOK_LEG, c14Bars, c14Length, stairBars, stepDevLength, undersideAt, shearULength, capLength, PIECES_PER_POSITION } from './coping';
|
||||
import { shearBars, shearBarsMulti, copingSideBars, SIDE_HOOK_LEG, c14Bars, c14Length, tStepBars, stepDevLength, undersideAt, shearULength, capLength, PIECES_PER_POSITION } from './coping';
|
||||
import { sideRowLevels } from '../coping-geom';
|
||||
import { CAST_PENDING } from './cast-in-place';
|
||||
import { castRebarLayout } from './cast-layout';
|
||||
@@ -56,7 +56,7 @@ const MULTI_NOTE: Record<string, string> = {
|
||||
C7: '하면 전 길이, Level 꺾임점 겹침, 양끝 위로 갈고리', C8: '경간마다 오목 하면, 기둥 중심 ± 2230 안쪽',
|
||||
C9: '전단 · 테이퍼·헌치', C10: '전단 · 기둥 Level', C11: '전단 · 기둥 사이 오목',
|
||||
C12: '측면 상단 (전 길이), 다리 위치마다', C13: '측면 하단 변화구간 (하면에서 끊김), 다리 위치마다',
|
||||
C14: '크로스타이 연직 600 · 교각축 1200 엇갈림', C15: '계단부 ⊓ (끝단보다 100 이상 높은 계단 전체)',
|
||||
C14: '크로스타이 연직 600 · 교각축 1200 엇갈림', C15: '계단부 ⊓ (가장 높은 계단)', C16: '계단부 L형 (그 밖의 계단, 낮은 쪽 다리)',
|
||||
};
|
||||
|
||||
/** Table metadata per bar (코핑철근.md, 확대기초철근 (1).md, 기둥철근 (1).md, 받침블럭철근.md). */
|
||||
@@ -77,8 +77,8 @@ const META: Record<string, Pick<RebarRow, 'spacing' | 'actual' | 'position' | 'd
|
||||
C12: { spacing: '250', actual: '250', position: '측면 상단 (끝면까지)', direction: '교각축', shape: '일자 + 좌우 ㄷ형', basis: 'calc' },
|
||||
C13: { spacing: '250', actual: '250', position: '측면 하단 변화구간 (경사 하면에서 끊김)', direction: '교각축', shape: '일자 + 좌우 ㄷ형', basis: 'calc' },
|
||||
C14: { spacing: '1000 / 2000', actual: '1000', position: '직각 수평 (위 2줄 · 아래 엇갈림)', direction: '교각축 직각', shape: '⊓ (폭 방향)', basis: 'calc' },
|
||||
C15: { spacing: '250', actual: '250', position: '계단부 가장 높은 5구간', direction: '교각축', shape: '거꾸로 된 U', basis: 'calc' },
|
||||
C16: { spacing: '250', actual: '250', position: '계단부 3·4구간', direction: '교각축', shape: 'L형', basis: 'calc' },
|
||||
C15: { spacing: '250', actual: '250', position: '계단부 가장 높은 구간', direction: '교각축', shape: '거꾸로 된 U', basis: 'calc' },
|
||||
C16: { spacing: '250', actual: '250', position: '계단부 그 밖의 구간 (최저 상면 + 100 이상)', direction: '교각축', shape: 'L형', basis: 'calc' },
|
||||
P1: { spacing: '원주 46등분', actual: '—', position: '외측 r 875', direction: '연직', shape: '아래 끝 90° 갈고리, 커플러 이음', basis: 'calc' },
|
||||
P2: { spacing: '원주 46등분', actual: '—', position: '내측 r 843.2', direction: '연직', shape: '직선, 커플러 이음', basis: 'calc' },
|
||||
'주철근 커플러': { spacing: '@3000 (P2 +150)', actual: '—', position: 'P1·P2 각 줄', direction: '원통', shape: 'L 150 · Ø60', basis: 'default' },
|
||||
@@ -298,9 +298,18 @@ export function rebarSummary(
|
||||
const lineCount = (line: number) => c14.filter((b) => b.line === line).length;
|
||||
const omitted = c14.filter((b) => !b.legs).length;
|
||||
rows.push({ member: 'coping', name: 'C14', size: 'H19', count: c14.length, length: c14Length(model.copingB * 1000), note: `위 2 줄 ${lineCount(1)} · ${lineCount(2)}본씩, 아래 ${[3, 4, 5, 6].map(lineCount).join(' · ')} (합 ${c14.length}) · 연직 발 생략 ${omitted}개 (하면 밖)` });
|
||||
const stairs = stairBars(model.copingL * 1000, model.copingB * 1000, model.copingRefTop, mCoping, 2 * model.copingRebar.mainSpacing);
|
||||
rows.push({ member: 'coping', name: 'C15', size: 'H19', count: stairs.c15.length, length: stairs.c15[0].length, note: '계단부, 가장 높은 구간 (거꾸로 U)' });
|
||||
rows.push({ member: 'coping', name: 'C16', size: 'H19', count: stairs.c16.length, length: stairs.c16[0].length, note: `계단부, 3·4구간 (${Math.round(stairs.c16[0].length)} / ${Math.round(stairs.c16[stairs.c16.length - 1].length)})` });
|
||||
// C15 · C16 from the model's own steps (결정 2026-11-10): none when no step is h_16 above the lowest top.
|
||||
const steps = tStepBars(model, mCoping);
|
||||
for (const name of ['C15', 'C16'] as const) {
|
||||
const bars = steps.bars.filter((b) => b.name === name);
|
||||
if (!bars.length) continue;
|
||||
const byLength = new Map<number, number>();
|
||||
for (const b of bars) byLength.set(Math.round(b.length), (byLength.get(Math.round(b.length)) ?? 0) + 1);
|
||||
const pieces = [...byLength].map(([length, count]) => ({ length, count }));
|
||||
rows.push({ member: 'coping', name, size: 'H19', count: bars.length, length: pieces.length === 1 ? pieces[0].length : null, ...(pieces.length > 1 ? { pieces } : {}),
|
||||
note: `${name === 'C15' ? '계단부, 가장 높은 구간 (거꾸로 U)' : '계단부, 그 밖의 계단 구간 (L형, 낮은 쪽 다리)'} · ${pieces.map((q) => `${q.length} × ${q.count}`).join(' / ')}` });
|
||||
}
|
||||
for (const message of steps.warnings) warnings.push({ code: 'RB-S01', target: 'coping', message });
|
||||
}
|
||||
|
||||
// Column (기둥철근.md · plan C4), P1 defaults
|
||||
|
||||
+7
-19
@@ -2,7 +2,7 @@ import * as THREE from 'three';
|
||||
import type { PierModel } from '../core/geometry';
|
||||
import { assemblyEndOffset, assemblyGridIndices, assemblyJs, b10Levels, b9Bars, gridPositions, grid, layers, legLength, legOffsets, sideDepth } from '../core/rebar/footing';
|
||||
import { bottomPiece, MAIN, topSplicePieces, widthLayout } from '../core/rebar/coping-main';
|
||||
import { C14_INSET, c14Bars, CAP, COPING_REBAR, SHEAR_LOOP_STEP, shearBars, shearBarsMulti, shearUHeight, copingSideBars, SIDE_HOOK_LEG, stairBars, undersideAt } from '../core/rebar/coping';
|
||||
import { C14_INSET, c14Bars, CAP, COPING_REBAR, SHEAR_LOOP_STEP, shearBars, shearBarsMulti, shearUHeight, copingSideBars, SIDE_HOOK_LEG, tStepBars, undersideAt } from '../core/rebar/coping';
|
||||
import { sideRowLevels } from '../core/coping-geom';
|
||||
import { columnRebar, columnInputFor } from '../core/rebar/column';
|
||||
import { castRebarLayout } from '../core/rebar/cast-layout';
|
||||
@@ -287,25 +287,13 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
||||
addBar('C14', 0, [xm, b.z, c14Nb], [xm, b.z - c14Hook, c14Nb], NOMINAL_DIAMETER.H19, COLOR.coping);
|
||||
}
|
||||
}
|
||||
// C15 (거꾸로 된 U) and C16 (L형) on the stair (코핑철근.md §7): 11 bars each across the width.
|
||||
const stairs = stairBars(L * 1000, B * 1000, topEl, mCoping, 2 * m.copingRebar.mainSpacing);
|
||||
for (const s of stairs.c15) {
|
||||
const n = mm(s.n);
|
||||
const ld = mm(s.leg);
|
||||
const x0 = mm(s.x0);
|
||||
const x1 = mm(s.x1);
|
||||
addBar('C15', 0, [x0, s.z - ld, n], [x0, s.z, n], NOMINAL_DIAMETER.H19, COLOR.coping);
|
||||
addBar('C15', 0, [x0, s.z, n], [x1, s.z, n], NOMINAL_DIAMETER.H19, COLOR.coping);
|
||||
addBar('C15', 0, [x1, s.z, n], [x1, s.z - ld, n], NOMINAL_DIAMETER.H19, COLOR.coping);
|
||||
// C15 (⊓) and C16 (L형) on the model's own steps (결정 2026-11-10, src/core/rebar/step-bars.ts).
|
||||
for (const b of tStepBars(m, mCoping).bars) {
|
||||
const n = b.n;
|
||||
for (let i = 1; i < b.pts.length; i++) {
|
||||
addBar(b.name, 0, [mm(b.pts[i - 1][0]), b.pts[i - 1][1], n], [mm(b.pts[i][0]), b.pts[i][1], n], NOMINAL_DIAMETER.H19, COLOR.coping);
|
||||
}
|
||||
}
|
||||
for (const s of stairs.c16) {
|
||||
const n = mm(s.n);
|
||||
const ld = mm(s.leg);
|
||||
const x0 = mm(s.x0);
|
||||
const x1 = mm(s.x1);
|
||||
addBar('C16', 0, [x0, s.z - ld, n], [x0, s.z, n], NOMINAL_DIAMETER.H19, COLOR.coping);
|
||||
addBar('C16', 0, [x0, s.z, n], [x1, s.z, n], NOMINAL_DIAMETER.H19, COLOR.coping);
|
||||
}
|
||||
}
|
||||
|
||||
// Columns: P1 / P2 main bars on their radii, ties P3 / P5 / P4 as rings, P6 crossties across the column.
|
||||
|
||||
Reference in new issue
Block a user