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>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-26 12:02:33 +09:00
1 parent 2af5cfb144
commit 43a18182f3
7 files changed
+216 -6

No files matched your search

+29
View File
@@ -7,6 +7,7 @@ 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 { 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';
import { diameterGroupIndex, DIAMETER_GROUPS, memberOfBar, type RebarMemberKey } from '../core/rebar/color';
import { stretchMatrix } from './scene';
@@ -474,6 +475,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
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 P = (a: number, c: number, y: number): [number, number, number] => {
@@ -490,6 +492,33 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
}
}
// 일체 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).
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 };
const P = (a: number, c: number, y: number): [number, number, number] => {
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;
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;
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);
}
for (const off of Array.from({ length: acrossS.count }, (_, i) => (acrossS.firstEnd + i * acrossS.spacing) / 1000 - INTEGRATED_BLOCK.depth / 2000)) {
addBar('S1', k, P(off, -halfN, z1), P(off, halfN, z1), dBar, COLOR.block);
addBar('S1', k, P(off, -halfN, z1 - legM), P(off, -halfN, z1), dBar, COLOR.block);
addBar('S1', k, P(off, halfN, z1), P(off, halfN, z1 - legM), dBar, COLOR.block);
}
}
const show = (names: ReadonlySet<string> | null, isolate: boolean) => {
// 커플러 as a name selects every coupler bar.
const isOn = (key: string) => names === null || names.has(key) || (names.has('커플러') && key.includes('커플러'));