feat(rebar): block rebar settings as input (S1·S2 spacing separate, S1 depth from the cover and bar diameters)

- PierInput.blockRebar (partial): cover top, side cover, first gap, spacing S1
  and S2 (separate), leg length. Defaults are the P1 values, so P1 is unchanged.
- S2 depth = top cover; S1 depth = top cover + S1/2 + S2/2 (H19: 69.1 at the default).
- The model carries the settings; the bearing-block rebar, the 3D bars, and the
  summary use them.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-26 14:08:58 +09:00
1 parent c4d4957dd2
commit e1497176ea
6 files changed
+141 -74

No files matched your search

+26 -18
View File
@@ -5,7 +5,7 @@ import { bottomPiece, MAIN, 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 { sideRowLevels } from '../core/coping-geom';
import { columnRebar, columnInputFor, COLUMN_P1 } from '../core/rebar/column';
import { barsAcross, BLOCK_REBAR } from '../core/rebar/bearing-block';
import { barDepths, barsAcross } from '../core/rebar/bearing-block';
import { blockFramePoint } from '../core/geometry';
import { INTEGRATED_BLOCK } from '../core/integrated-block';
import { bendRadius, DEFAULT_MATERIAL, FckByMember, hookLength, Material, materialFor, NOMINAL_DIAMETER } from '../core/rebar/common';
@@ -466,34 +466,42 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
});
}
// Bearing blocks: S2 (upper, along s) and S1 (lower, along n), 8 bars each across the 1200 block.
// Positions from barsAcross (162.5 from the block edge, @125), bars a − 2·c_s long, legs 700 down at both ends (§3–5).
const across = barsAcross();
const half = (BLOCK_REBAR.dim - 2 * BLOCK_REBAR.cover) / 2000;
const legM = BLOCK_REBAR.legLength / 1000;
const offsets = Array.from({ length: across.count }, (_, i) => (across.firstEnd + i * across.spacing) / 1000 - BLOCK_REBAR.dim / 2000);
// Bearing blocks: S2 (upper, along s) and S1 (lower, along n). Each set has its own spacing (승인 2026-10-26).
// Positions from barsAcross (the first bar at the side cover + first gap), legs of legLength down at both ends (§3–5).
const br = m.blockRebar;
const depth = barDepths(br);
const legM = br.legLength / 1000;
const half = (1200 - 2 * br.coverSide) / 2000;
const offsetsOf = (spacing: number) => {
const a = barsAcross(1200, spacing, br);
return Array.from({ length: a.count }, (_, i) => (a.firstEnd + i * a.spacing) / 1000 - 0.6);
};
const offsetsS2 = offsetsOf(br.spacingS2);
const offsetsS1 = offsetsOf(br.spacingS1);
const dBar = NOMINAL_DIAMETER.H19;
// The bars are drawn in the block's own frame (a along its s side, c along its n side) and turned with the block.
for (const b of m.blocks) {
if (m.integratedBlocks.length > 0) break; // 일체: drawn per pair below
const z2 = b.top - BLOCK_REBAR.depthS2 / 1000;
const z1 = b.top - BLOCK_REBAR.depthS1 / 1000;
const z2 = b.top - depth.S2 / 1000;
const z1 = b.top - depth.S1 / 1000;
const P = (a: number, c: number, y: number): [number, number, number] => {
const [s, n] = blockFramePoint(b, a, c);
return [s, y, n];
};
for (const off of offsets) {
for (const off of offsetsS2) {
addBar('S2', b.k, P(-half, off, z2), P(half, off, z2), dBar, COLOR.block);
addBar('S2', b.k, P(-half, off, z2 - legM), P(-half, off, z2), dBar, COLOR.block);
addBar('S2', b.k, P(half, off, z2), P(half, off, z2 - legM), dBar, COLOR.block);
}
for (const off of offsetsS1) {
addBar('S1', b.k, P(off, -half, z1), P(off, half, z1), dBar, COLOR.block);
addBar('S1', b.k, P(off, -half, z1 - legM), P(off, -half, z1), dBar, COLOR.block);
addBar('S1', b.k, P(off, half, z1), P(off, half, z1 - legM), dBar, COLOR.block);
}
}
// 일체 block (승인 2026-10-26): S2 runs along the 교각축 (1200) with 19 bars across the 2500 (교축), and S1 runs
// along the 2500 with 8 bars across the 1200. Each S2 bar sits under its own half's top (front: offset ≤ 0).
// 일체 block (승인 2026-10-26): S2 runs along the 교각축 (1200) with the bars across the 2500 (교축); S1 runs along
// the 2500 with the bars across the 1200. Each S2 bar sits under its own half's top (front: offset ≤ 0).
for (const ib of m.integratedBlocks) {
const k = m.blocks.find((b) => b.no === ib.frontNo && b.row === '전열')!.k;
const frame = { s: ib.s, n: ib.n, rowSkewDeg: ib.rowSkewDeg };
@@ -501,13 +509,13 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
const [s, n] = blockFramePoint(frame, a, c);
return [s, y, n];
};
const acrossN = barsAcross(INTEGRATED_BLOCK.length);
const acrossS = barsAcross(INTEGRATED_BLOCK.depth);
const halfS = (INTEGRATED_BLOCK.depth - 2 * BLOCK_REBAR.cover) / 2000;
const halfN = (INTEGRATED_BLOCK.length - 2 * BLOCK_REBAR.cover) / 2000;
const z1 = Math.min(ib.topFront, ib.topBack) - BLOCK_REBAR.depthS1 / 1000;
const acrossN = barsAcross(INTEGRATED_BLOCK.length, br.spacingS2, br);
const acrossS = barsAcross(INTEGRATED_BLOCK.depth, br.spacingS1, br);
const halfS = (INTEGRATED_BLOCK.depth - 2 * br.coverSide) / 2000;
const halfN = (INTEGRATED_BLOCK.length - 2 * br.coverSide) / 2000;
const z1 = Math.min(ib.topFront, ib.topBack) - depth.S1 / 1000;
for (const off of Array.from({ length: acrossN.count }, (_, i) => (acrossN.firstEnd + i * acrossN.spacing) / 1000 - INTEGRATED_BLOCK.length / 2000)) {
const z2 = (off <= 1e-9 ? ib.topFront : ib.topBack) - BLOCK_REBAR.depthS2 / 1000;
const z2 = (off <= 1e-9 ? ib.topFront : ib.topBack) - depth.S2 / 1000;
addBar('S2', k, P(-halfS, off, z2), P(halfS, off, z2), dBar, COLOR.block);
addBar('S2', k, P(-halfS, off, z2 - legM), P(-halfS, off, z2), dBar, COLOR.block);
addBar('S2', k, P(halfS, off, z2), P(halfS, off, z2 - legM), dBar, COLOR.block);