Files
Pier_v1/src/core/rebar/bearing-block.ts
T
ypshimandClaude Haiku 5.5 43a18182f3 feat(bearing): 일체 block as one stepped block per pair, with its rebar (승인 2026-10-26)
- integrated-block.ts: per pair (전열 k · 후열 k) one block centred on the
  pair midpoint, 2500 across the 교축 and 1200 along the 교각축, with a
  stepped top (each half to its own bearing row top). Only when 일체 is chosen
  and every pair is within 100 mm; otherwise 분리 is kept (B02).
- Rebar: S2 19 bars at 125 across the 2500 (10 front half, 9 back half), each
  leg from its half's top; S1 8 bars across the 1200, 3800 long, depth from
  the lower top. Totals per pier: S1 40, S2 95 (분리: 80 / 80).
- Scene and 3D rebar draw the stepped blocks instead of the per-bearing blocks.
- The per-bearing blocks stay for the solplate, the pads, and the body.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-26 12:02:33 +09:00

113 lines
5.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { PierModel } from '../geometry';
import { INTEGRATED_BLOCK, type IntegratedBlock } from '../integrated-block';
/**
* 받침블럭 철근 (spec §6.3 · plan C2), 배치 분리: one block per bearing, 1200 × 1200.
* S2 is the upper bar (cover 50 from the block top); S1 is the lower bar (69.1 below the top).
* Both have the same layout: 7@125 = 875 with ends of 162.5 in a 1200 mm block, and legs of 700 below the bar.
*/
export const BLOCK_REBAR = {
dim: 1200,
cover: 50,
firstBarGap: 75,
spacing: 125,
legLength: 700,
/** Depth of each bar centre below the block top (mm). */
depthS2: 50,
depthS1: 69.1,
} as const;
export interface BarRow {
name: 'S1' | 'S2';
/** Bars along one block side. */
count: number;
spacing: number;
/** Position of the first bar from the block edge. */
firstEnd: number;
/** Straight length plus two legs (mm). */
length: number;
/** Coping embedment of the legs (mm): 700 − (block height − bar depth). */
embedment: number;
}
/** Bars along one 1200 mm side: available = dim − 2·(cover + first gap); gaps = floor(available / spacing). */
export function barsAcross(dim: number = BLOCK_REBAR.dim): { count: number; spacing: number; firstEnd: number } {
const available = dim - 2 * (BLOCK_REBAR.cover + BLOCK_REBAR.firstBarGap);
const gaps = Math.floor(available / BLOCK_REBAR.spacing);
const span = gaps * BLOCK_REBAR.spacing;
const leftover = available - span;
return { count: gaps + 1, spacing: BLOCK_REBAR.spacing, firstEnd: BLOCK_REBAR.cover + BLOCK_REBAR.firstBarGap + leftover / 2 };
}
/** Length of one bar (mm): the straight part a − 2·c_s plus two legs of 700 (spec §5; 2500 for the 1200 block). */
export function barLength(dim: number = BLOCK_REBAR.dim): number {
return dim - 2 * BLOCK_REBAR.cover + 2 * BLOCK_REBAR.legLength;
}
/** Rebar of one block; blockHeight is the bearing block height in mm (h1 front or h2 back, pad included). */
export function blockBars(blockHeight: number, dim: number = BLOCK_REBAR.dim): BarRow[] {
const across = barsAcross(dim);
const length = barLength(dim);
return [
{ name: 'S1', ...across, length, embedment: BLOCK_REBAR.legLength - (blockHeight - BLOCK_REBAR.depthS1) },
{ name: 'S2', ...across, length, embedment: BLOCK_REBAR.legLength - (blockHeight - BLOCK_REBAR.depthS2) },
];
}
export interface BlockRebar {
no: number;
row: '전열' | '후열';
bars: BarRow[];
}
/**
* Rebar of every block of a pier. The block height h_b is the model's own block (coping top → block top, pad excluded),
* since the bar depths are measured from the block top. h1 / h2 include the 50 pad and would count it twice.
*/
export function bearingBlockRebar(model: PierModel): BlockRebar[] {
// 일체 (승인 2026-10-26): one block per pair replaces the two per-bearing blocks.
if (model.integratedBlocks.length > 0) {
return model.integratedBlocks.map((ib) => ({ no: ib.frontNo, row: '전열', bars: integratedBlockBars(ib) }));
}
return model.blocks.map((b) => ({
no: b.no,
row: b.row,
bars: blockBars((b.top - b.bottom) * 1000),
}));
}
/**
* Rebar of one 일체 block (승인 2026-10-26, 받침블럭철근.md "일체 a 2500").
* S2 runs along the 교각축 (1200), so its bars are spaced across the 2500 length: 19 bars at 125. Its legs are measured
* from the top of the half it sits in; the bar at the step line (centre) counts with the front half.
* S1 runs along the 2500 length, 8 bars across the 1200 depth, its depth taken from the lower top (cover on the higher half is larger).
*/
export function integratedBlockBars(ib: IntegratedBlock): BarRow[] {
const half = INTEGRATED_BLOCK.length / 2;
const s2 = barsAcross(INTEGRATED_BLOCK.length);
const frontCount = Array.from({ length: s2.count }, (_, k) => s2.firstEnd + k * s2.spacing).filter((x) => x <= half + 1e-9).length;
const backCount = s2.count - frontCount;
const hFront = (ib.topFront - ib.bottom) * 1000;
const hBack = (ib.topBack - ib.bottom) * 1000;
const legS2 = (h: number) => BLOCK_REBAR.legLength - (h - BLOCK_REBAR.depthS2);
const s1 = barsAcross(INTEGRATED_BLOCK.depth);
const hLow = Math.min(hFront, hBack);
const rows: BarRow[] = [
{ name: 'S2', count: frontCount, spacing: s2.spacing, firstEnd: s2.firstEnd, length: barLength(INTEGRATED_BLOCK.depth), embedment: legS2(hFront) },
];
if (backCount > 0) rows.push({ name: 'S2', count: backCount, spacing: s2.spacing, firstEnd: s2.firstEnd, length: barLength(INTEGRATED_BLOCK.depth), embedment: legS2(hBack) });
rows.push({ name: 'S1', count: s1.count, spacing: s1.spacing, firstEnd: s1.firstEnd, length: barLength(INTEGRATED_BLOCK.length), embedment: BLOCK_REBAR.legLength - (hLow - BLOCK_REBAR.depthS1) });
return rows;
}
/** Total bars of one pier: bars per block × blocks, for S1 and S2 separately. */
export function totals(rebar: BlockRebar[]): { S1: number; S2: number } {
return rebar.reduce(
(sum, blk) => {
for (const bar of blk.bars) sum[bar.name] += bar.count;
return sum;
},
{ S1: 0, S2: 0 },
);
}