feat(rebar): 전·후열 단차 300 mm 이상 블록 보강 C17·C18
전열·후열 상면 차가 300 mm 이상인 구간의 높은 쪽 블록에 (결정 2026-11-10, step-bars.ts): - C17 ㄷ형 띠 H16 @전단간격: 단차면 + c ~ 측면 − c, 위 = 높은 상면 − c, 다리 낮은 상면 아래 l_d까지 - C18 수평 피부철근 H16 @측면간격: 단차면 안쪽, 낮은 상면 + 측면간격마다 T형(철근표·3D)과 다주형(편 좌표 → 꺾임 접기) 모두에 넣는다. 구간마다 따로 두고 이웃 구간과 잇지 않는다 (가정). Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8f808f453e
commit
33aa2d9a61
5 files changed
+142
-4
No files matched your search
@@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
import type { PierModel } from '../geometry';
|
import type { PierModel } from '../geometry';
|
||||||
import { DEFAULT_MATERIAL, developmentLength, fyOf, hookLength, type Material, NOMINAL_DIAMETER, spliceLength } from './common';
|
import { DEFAULT_MATERIAL, developmentLength, fyOf, hookLength, type Material, NOMINAL_DIAMETER, spliceLength } from './common';
|
||||||
import { stepBars } from './step-bars';
|
import { stepBars, stepBlockBars } from './step-bars';
|
||||||
import { copingFold, foldBar, type FoldPiece, inWedge, isTransverse, onMitre } from './coping-fold';
|
import { copingFold, foldBar, type FoldPiece, inWedge, isTransverse, onMitre } from './coping-fold';
|
||||||
|
|
||||||
export type CopingPoint = [number, number, number];
|
export type CopingPoint = [number, number, number];
|
||||||
@@ -296,6 +296,9 @@ export function multicolCopingInfo(model: PierModel, material: Material = DEFAUL
|
|||||||
stepMin: MULTI_REBAR.stepMin * 1000, across: top.filter((_, i) => i % 2 === 0) });
|
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 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 });
|
for (const message of stairs.warnings) warnings.push({ code: 'RB-S01', message });
|
||||||
|
// 전·후열 단차 300 이상: 높은 쪽 블록에 C17 ㄷ형 띠 (전단간격) · C18 피부철근 (측면간격), H16 (결정 2026-11-10).
|
||||||
|
for (const b of stepBlockBars(model, { cover: c * 1000, d: d('H16'), ld: Math.round(developmentLength(d('H16'), fy('H16'), material.fck)),
|
||||||
|
tieSpacing: settings.spacingS, skinSpacing: settings.sideSpacing })) add(b.name, 'H16', b.pts);
|
||||||
|
|
||||||
// Bent coping (결정 2026-11-10, coping-fold.ts): runs along the axis turn at their mitre point; bars across the width that
|
// Bent coping (결정 2026-11-10, coping-fold.ts): runs along the axis turn at their mitre point; bars across the width that
|
||||||
// would cut the mitre are left out, and one shear set (the position nearest the kink) is laid on the mitre.
|
// would cut the mitre are left out, and one shear set (the position nearest the kink) is laid on the mitre.
|
||||||
|
|||||||
@@ -110,3 +110,73 @@ export function stepBars(model: PierModel, opt: StepOptions): { bars: StepBar[];
|
|||||||
}
|
}
|
||||||
return { bars, warnings };
|
return { bars, warnings };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 전·후열 단차 블록 보강의 최소 단차 (mm, 결정 2026-11-10). */
|
||||||
|
export const STEP_BLOCK_MIN_MM = 300;
|
||||||
|
|
||||||
|
export interface StepBlockBar {
|
||||||
|
name: 'C17' | 'C18';
|
||||||
|
/** Unfolded centre line (g m, EL m, n m). */
|
||||||
|
pts: [number, number, number][];
|
||||||
|
/** Developed length (mm). */
|
||||||
|
length: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StepBlockOptions {
|
||||||
|
/** Cover c (mm). */
|
||||||
|
cover: number;
|
||||||
|
/** H16 diameter and development length l_d (mm). */
|
||||||
|
d: number;
|
||||||
|
ld: number;
|
||||||
|
/** C17 spacing along the axis = 전단간격, C18 vertical spacing = 측면간격 (mm). */
|
||||||
|
tieSpacing: number;
|
||||||
|
skinSpacing: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 전·후열 단차 블록 보강 (결정 2026-11-10): 전열·후열 상면 차가 300 mm 이상인 구간에서, 높은 쪽 블록에
|
||||||
|
* - C17 ㄷ형 띠철근 (H16): 블록 폭 방향 (코핑 안 단차면 + c ~ 측면 − c), 위 = 높은 상면 − c, 다리 양쪽을 낮은 상면 아래 l_d까지.
|
||||||
|
* 교축 방향으로 전단간격, 구간 시작 + c ~ 끝 − c에 고르게.
|
||||||
|
* - C18 수평 피부철근 (H16): 단차면 안쪽 (C17 다리 안), 낮은 상면 + 측면간격마다 높은 상면 − c 아래까지, 구간 시작 + c ~ 끝 − c.
|
||||||
|
* 구간 = 전열·후열 계단 경계를 합친 사이. 구간마다 따로 두고 이웃 구간과 잇지 않는다 (가정).
|
||||||
|
*/
|
||||||
|
export function stepBlockBars(model: PierModel, opt: StepBlockOptions): StepBlockBar[] {
|
||||||
|
const parts = model.copingParts.filter((p) => p.k === 0);
|
||||||
|
if (parts.length !== 2 || !model.backSegments) return [];
|
||||||
|
const half = model.copingB / 2;
|
||||||
|
const c = opt.cover / 1000, ld = opt.ld / 1000, d = opt.d / 1000;
|
||||||
|
const [front] = parts;
|
||||||
|
const split = front.nFrom > -half + 1e-9 ? front.nFrom : front.nTo;
|
||||||
|
const frontDir = Math.sign((front.nFrom + front.nTo) / 2 - split);
|
||||||
|
const topAt = (segs: { s0: number; s1: number; top: number }[], x: number) =>
|
||||||
|
(segs.find((s) => x >= s.s0 && x < s.s1) ?? segs[segs.length - 1]).top;
|
||||||
|
const bounds = [...new Set([0, model.copingL, ...model.segments.map((s) => s.s0), ...model.backSegments.map((s) => s.s0)].map((v) => Math.round(v * 1000) / 1000))].sort((a, b) => a - b);
|
||||||
|
const len = (pts: [number, number, number][]) => pts.slice(1).reduce((s, p, i) => s + Math.hypot(p[0] - pts[i][0], p[1] - pts[i][1], p[2] - pts[i][2]), 0) * 1000;
|
||||||
|
const out: StepBlockBar[] = [];
|
||||||
|
for (let i = 1; i < bounds.length; i++) {
|
||||||
|
const a = bounds[i - 1], b = bounds[i], mid = (a + b) / 2;
|
||||||
|
const fTop = topAt(model.segments, mid), bTop = topAt(model.backSegments, mid);
|
||||||
|
if (Math.abs(fTop - bTop) * 1000 < STEP_BLOCK_MIN_MM - 1e-6) continue;
|
||||||
|
const backHigh = bTop > fTop;
|
||||||
|
const dir = backHigh ? -frontDir : frontDir;
|
||||||
|
const hi = Math.max(fTop, bTop), lo = Math.min(fTop, bTop);
|
||||||
|
const nA = split + dir * c, nB = dir * (half - c);
|
||||||
|
const zt = hi - c, legEnd = lo - ld;
|
||||||
|
const span = b - a - 2 * c;
|
||||||
|
if (span <= 0) continue;
|
||||||
|
const s = opt.tieSpacing / 1000;
|
||||||
|
const count = Math.floor(span / s + 1e-9) + 1;
|
||||||
|
const start = a + c + (span - (count - 1) * s) / 2;
|
||||||
|
for (let k = 0; k < count; k++) {
|
||||||
|
const x = start + k * s;
|
||||||
|
const pts: [number, number, number][] = [[x, legEnd, nA], [x, zt, nA], [x, zt, nB], [x, legEnd, nB]];
|
||||||
|
out.push({ name: 'C17', pts, length: len(pts) });
|
||||||
|
}
|
||||||
|
const nSkin = nA + dir * d;
|
||||||
|
for (let z = lo + opt.skinSpacing / 1000; z < zt - 1e-9; z += opt.skinSpacing / 1000) {
|
||||||
|
const pts: [number, number, number][] = [[a + c, z, nSkin], [b - c, z, nSkin]];
|
||||||
|
out.push({ name: 'C18', pts, length: len(pts) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
@@ -4,14 +4,15 @@ import { copingDefaults } from './coping-settings';
|
|||||||
import { DEFAULT_COLUMN_REBAR } from './column-settings';
|
import { DEFAULT_COLUMN_REBAR } from './column-settings';
|
||||||
import { DEFAULT_FOOTING_REBAR, type FootingRebarSettings } from './footing-settings';
|
import { DEFAULT_FOOTING_REBAR, type FootingRebarSettings } from './footing-settings';
|
||||||
import { bottomPiece, topBarLength, widthLayout, topSplicePieces } from './coping-main';
|
import { bottomPiece, topBarLength, widthLayout, topSplicePieces } from './coping-main';
|
||||||
import { shearBars, shearBarsMulti, copingSideBars, SIDE_HOOK_LEG, c14Bars, c14Length, tStepBars, stepDevLength, undersideAt, shearULength, capLength, PIECES_PER_POSITION } from './coping';
|
import { shearBars, shearBarsMulti, copingSideBars, SIDE_HOOK_LEG, c14Bars, c14Length, COPING_REBAR, tStepBars, stepDevLength, undersideAt, shearULength, capLength, PIECES_PER_POSITION } from './coping';
|
||||||
import { sideRowLevels } from '../coping-geom';
|
import { sideRowLevels } from '../coping-geom';
|
||||||
import { CAST_PENDING } from './cast-in-place';
|
import { CAST_PENDING } from './cast-in-place';
|
||||||
import { castRebarLayout } from './cast-layout';
|
import { castRebarLayout } from './cast-layout';
|
||||||
import { multicolCopingInfo } from './multicol-coping';
|
import { multicolCopingInfo } from './multicol-coping';
|
||||||
|
import { stepBlockBars } from './step-bars';
|
||||||
import { columnRebar, columnInputFor } from './column';
|
import { columnRebar, columnInputFor } from './column';
|
||||||
import { bottomBars, crossBars, sideBars, assemblyBars, shearB9 } from './footing';
|
import { bottomBars, crossBars, sideBars, assemblyBars, shearB9 } from './footing';
|
||||||
import { DEFAULT_MATERIAL, FckByMember, fyOf, isAssumedMaterial, Material, materialFor, splitPieces, STANDARD_BAR } from './common';
|
import { DEFAULT_MATERIAL, developmentLength, FckByMember, fyOf, isAssumedMaterial, Material, materialFor, NOMINAL_DIAMETER, splitPieces, STANDARD_BAR } from './common';
|
||||||
|
|
||||||
/** 근거 badge (spec §6.1): where the value comes from. */
|
/** 근거 badge (spec §6.1): where the value comes from. */
|
||||||
export type Basis = 'input' | 'default' | 'calc' | 'assumed';
|
export type Basis = 'input' | 'default' | 'calc' | 'assumed';
|
||||||
@@ -57,6 +58,7 @@ const MULTI_NOTE: Record<string, string> = {
|
|||||||
C9: '전단 · 테이퍼·헌치', C10: '전단 · 기둥 Level', C11: '전단 · 기둥 사이 오목',
|
C9: '전단 · 테이퍼·헌치', C10: '전단 · 기둥 Level', C11: '전단 · 기둥 사이 오목',
|
||||||
C12: '측면 상단 (전 길이), 다리 위치마다', C13: '측면 하단 변화구간 (하면에서 끊김), 다리 위치마다',
|
C12: '측면 상단 (전 길이), 다리 위치마다', C13: '측면 하단 변화구간 (하면에서 끊김), 다리 위치마다',
|
||||||
C14: '크로스타이 연직 600 · 교각축 1200 엇갈림', C15: '계단부 ⊓ (가장 높은 계단)', C16: '계단부 L형 (그 밖의 계단, 낮은 쪽 다리)',
|
C14: '크로스타이 연직 600 · 교각축 1200 엇갈림', C15: '계단부 ⊓ (가장 높은 계단)', C16: '계단부 L형 (그 밖의 계단, 낮은 쪽 다리)',
|
||||||
|
C17: '전·후열 단차 300 이상 블록 ㄷ형 띠 (전단간격)', C18: '전·후열 단차 블록 수평 피부철근 (측면간격)',
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Table metadata per bar (코핑철근.md, 확대기초철근 (1).md, 기둥철근 (1).md, 받침블럭철근.md). */
|
/** Table metadata per bar (코핑철근.md, 확대기초철근 (1).md, 기둥철근 (1).md, 받침블럭철근.md). */
|
||||||
@@ -79,6 +81,8 @@ const META: Record<string, Pick<RebarRow, 'spacing' | 'actual' | 'position' | 'd
|
|||||||
C14: { spacing: '1000 / 2000', actual: '1000', position: '직각 수평 (위 2줄 · 아래 엇갈림)', direction: '교각축 직각', shape: '⊓ (폭 방향)', basis: 'calc' },
|
C14: { spacing: '1000 / 2000', actual: '1000', position: '직각 수평 (위 2줄 · 아래 엇갈림)', direction: '교각축 직각', shape: '⊓ (폭 방향)', basis: 'calc' },
|
||||||
C15: { spacing: '250', actual: '250', position: '계단부 가장 높은 구간', direction: '교각축', shape: '거꾸로 된 U', 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' },
|
C16: { spacing: '250', actual: '250', position: '계단부 그 밖의 구간 (최저 상면 + 100 이상)', direction: '교각축', shape: 'L형', basis: 'calc' },
|
||||||
|
C17: { spacing: '250', actual: '250', position: '전·후열 단차 300 이상 블록', direction: '교각축 직각', shape: 'ㄷ형', basis: 'calc' },
|
||||||
|
C18: { spacing: '250', actual: '250', position: '전·후열 단차 블록 단차면', direction: '교각축', shape: '직선', basis: 'calc' },
|
||||||
P1: { spacing: '원주 46등분', actual: '—', position: '외측 r 875', direction: '연직', shape: '아래 끝 90° 갈고리, 커플러 이음', 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' },
|
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' },
|
'주철근 커플러': { spacing: '@3000 (P2 +150)', actual: '—', position: 'P1·P2 각 줄', direction: '원통', shape: 'L 150 · Ø60', basis: 'default' },
|
||||||
@@ -311,6 +315,18 @@ export function rebarSummary(
|
|||||||
note: `${name === 'C15' ? '계단부, 가장 높은 구간 (거꾸로 U)' : '계단부, 그 밖의 계단 구간 (L형, 낮은 쪽 다리)'} · ${pieces.map((q) => `${q.length} × ${q.count}`).join(' / ')}` });
|
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 });
|
for (const message of steps.warnings) warnings.push({ code: 'RB-S01', target: 'coping', message });
|
||||||
|
// 전·후열 단차 블록 보강 C17 · C18 (결정 2026-11-10): 단차 300 mm 이상인 구간만.
|
||||||
|
const block = stepBlockBars(model, { cover: COPING_REBAR.cover, d: NOMINAL_DIAMETER.H16, ld: Math.round(developmentLength(NOMINAL_DIAMETER.H16, fyOf(mCoping, 'H16'), mCoping.fck)),
|
||||||
|
tieSpacing: model.copingRebar.spacingS, skinSpacing: model.copingRebar.sideSpacing });
|
||||||
|
for (const name of ['C17', 'C18'] as const) {
|
||||||
|
const bars = block.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: 'H16', count: bars.length, length: pieces.length === 1 ? pieces[0].length : null, ...(pieces.length > 1 ? { pieces } : {}),
|
||||||
|
note: name === 'C17' ? '전·후열 단차 300 이상 블록, ㄷ형 띠 (다리 낮은 상면 아래 l_d)' : '전·후열 단차 블록, 단차면 수평 피부철근' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Column (기둥철근.md · plan C4), P1 defaults
|
// Column (기둥철근.md · plan C4), P1 defaults
|
||||||
|
|||||||
+7
-1
@@ -8,10 +8,11 @@ import { columnRebar, columnInputFor } from '../core/rebar/column';
|
|||||||
import { castRebarLayout } from '../core/rebar/cast-layout';
|
import { castRebarLayout } from '../core/rebar/cast-layout';
|
||||||
import { multicolCopingBars } from '../core/rebar/multicol-coping';
|
import { multicolCopingBars } from '../core/rebar/multicol-coping';
|
||||||
import { copingFold, foldBar } from '../core/rebar/coping-fold';
|
import { copingFold, foldBar } from '../core/rebar/coping-fold';
|
||||||
|
import { stepBlockBars } from '../core/rebar/step-bars';
|
||||||
import { barDepths, barsAcross } from '../core/rebar/bearing-block';
|
import { barDepths, barsAcross } from '../core/rebar/bearing-block';
|
||||||
import { blockFramePoint } from '../core/geometry';
|
import { blockFramePoint } from '../core/geometry';
|
||||||
import { INTEGRATED_BLOCK } from '../core/integrated-block';
|
import { INTEGRATED_BLOCK } from '../core/integrated-block';
|
||||||
import { bendRadius, DEFAULT_MATERIAL, FckByMember, hookLength, Material, materialFor, NOMINAL_DIAMETER } from '../core/rebar/common';
|
import { bendRadius, DEFAULT_MATERIAL, developmentLength, FckByMember, fyOf, hookLength, Material, materialFor, NOMINAL_DIAMETER } from '../core/rebar/common';
|
||||||
import { diameterGroupIndex, DIAMETER_GROUPS, memberOfBar, type RebarMemberKey } from '../core/rebar/color';
|
import { diameterGroupIndex, DIAMETER_GROUPS, memberOfBar, type RebarMemberKey } from '../core/rebar/color';
|
||||||
import { stretchMatrix } from './scene';
|
import { stretchMatrix } from './scene';
|
||||||
|
|
||||||
@@ -307,6 +308,11 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
|||||||
tBar(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);
|
tBar(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 전·후열 단차 300 이상 블록 보강 C17 · C18 (결정 2026-11-10, step-bars.ts).
|
||||||
|
const blockLd = Math.round(developmentLength(NOMINAL_DIAMETER.H16, fyOf(mCoping, 'H16'), mCoping.fck));
|
||||||
|
for (const b of stepBlockBars(m, { cover: COPING_REBAR.cover, d: NOMINAL_DIAMETER.H16, ld: blockLd, tieSpacing: m.copingRebar.spacingS, skinSpacing: m.copingRebar.sideSpacing })) {
|
||||||
|
for (let i = 1; i < b.pts.length; i++) tBar(b.name, 0, b.pts[i - 1], b.pts[i], NOMINAL_DIAMETER.H16, COLOR.coping);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Columns: P1 / P2 main bars on their radii, ties P3 / P5 / P4 as rings, P6 crossties across the column.
|
// Columns: P1 / P2 main bars on their radii, ties P3 / P5 / P4 as rings, P6 crossties across the column.
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { describe, expect, it } from 'vitest';
|
|||||||
import { buildPier } from '../src/core/geometry';
|
import { buildPier } from '../src/core/geometry';
|
||||||
import { tStepBars } from '../src/core/rebar/coping';
|
import { tStepBars } from '../src/core/rebar/coping';
|
||||||
import { multicolCopingInfo } from '../src/core/rebar/multicol-coping';
|
import { multicolCopingInfo } from '../src/core/rebar/multicol-coping';
|
||||||
|
import { stepBlockBars } from '../src/core/rebar/step-bars';
|
||||||
|
import { rebarSummary } from '../src/core/rebar/summary';
|
||||||
import type { PierInput } from '../src/core/types';
|
import type { PierInput } from '../src/core/types';
|
||||||
import { loadP1 } from './helpers';
|
import { loadP1 } from './helpers';
|
||||||
|
|
||||||
@@ -84,3 +86,44 @@ describe('계단부 철근 일반 규칙', () => {
|
|||||||
expect(info.warnings.some((w) => w.code === 'RB-M04')).toBe(false);
|
expect(info.warnings.some((w) => w.code === 'RB-M04')).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('전·후열 단차 블록 보강 C17 · C18 (결정 2026-11-10)', () => {
|
||||||
|
const raised = (dz: number, extra: Partial<PierInput> = {}) => {
|
||||||
|
const p1 = loadP1();
|
||||||
|
return buildPier({ ...p1, ...extra, bearings: p1.bearings.map((b) => (b.row === '후열' && b.no === 7 ? { ...b, z: b.z + dz, seatEl: b.seatEl! + dz } : b)) });
|
||||||
|
};
|
||||||
|
const opts = (m: ReturnType<typeof buildPier>) => ({ cover: 100, d: 15.9, ld: 600, tieSpacing: m.copingRebar.spacingS, skinSpacing: m.copingRebar.sideSpacing });
|
||||||
|
|
||||||
|
it('a 400 mm step: C17 ㄷ ties across the higher (back) block @전단간격, legs l_d below the lower top; one C18 row', () => {
|
||||||
|
const m = raised(0.4);
|
||||||
|
const bars = stepBlockBars(m, opts(m));
|
||||||
|
const c17 = bars.filter((b) => b.name === 'C17'), c18 = bars.filter((b) => b.name === 'C18');
|
||||||
|
expect(c17.length).toBe(10);
|
||||||
|
const [, back] = m.copingParts.filter((p) => p.k === 0);
|
||||||
|
const hi = m.backSegments![1].top, lo = m.segments[1].top;
|
||||||
|
for (const b of c17) {
|
||||||
|
for (const p of b.pts) { expect(p[2]).toBeGreaterThanOrEqual(back.nFrom - 1e-9); expect(p[2]).toBeLessThanOrEqual(back.nTo + 1e-9); }
|
||||||
|
expect(b.pts[1][1]).toBeCloseTo(hi - 0.1, 9);
|
||||||
|
expect(b.pts[0][1]).toBeCloseTo(lo - 0.6, 9);
|
||||||
|
expect(b.pts[0][0]).toBeGreaterThan(2.196 + 0.1 - 1e-6);
|
||||||
|
expect(b.pts[0][0]).toBeLessThan(4.701 - 0.1 + 1e-6);
|
||||||
|
}
|
||||||
|
expect(Math.abs(c17[1].pts[0][0] - c17[0].pts[0][0])).toBeCloseTo(0.25, 9);
|
||||||
|
expect(c18.length).toBe(1);
|
||||||
|
expect(c18[0].pts[0][1]).toBeCloseTo(lo + 0.25, 9);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('below 300 mm no block bars', () => {
|
||||||
|
const m = raised(0.25);
|
||||||
|
expect(stepBlockBars(m, opts(m))).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('they reach the T형 철근표 and the multi-column bars', () => {
|
||||||
|
const rows = rebarSummary(raised(0.4)).rows;
|
||||||
|
expect(rows.find((r) => r.name === 'C17')!.count).toBe(10);
|
||||||
|
expect(rows.find((r) => r.name === 'C18')!.count).toBe(1);
|
||||||
|
const multi = multicolCopingInfo(raised(0.4, { type: '2주형', columnCount: 2, foundationType: '말뚝기초', groundEl: 30, pileLengthMm: 24000 }));
|
||||||
|
expect(multi.bars.some((b) => b.name === 'C17')).toBe(true);
|
||||||
|
expect(multi.bars.some((b) => b.name === 'C18')).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user