feat(rebar): coping front view and 단면·폐합 section from the 3D bar records (승인 2026-10-26)

- rebar3d records every bar (name, stretch, local points, diameter) next to its
  mesh, so the 2D drawings use the same data as the 3D view.
- view/coping-rebar-svg.ts: the 정면 (along the coping length, EL vertical) and
  the 단면·폐합 at a chosen station (the bars crossing it, C9–C11 loops included).
- ③ coping tab: 정면 / 단면·폐합 toggle and the station input.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-26 14:27:03 +09:00
1 parent 32e8dad7dc
commit 57f7c148ec
4 files changed
+157 -1

No files matched your search

+14 -1
View File
@@ -17,9 +17,19 @@ import { stretchMatrix } from './scene';
* named by its 철근표 number (C1, P3, B5, S2 …), so the table and the model can point at each other.
* Local frame: x = along the axis s, y = absolute EL (m), z = across n. Stretch matrices map it to the scene.
*/
/** One bar in the local frame (x = along s, y = EL, z = across n), before the stretch matrix. For the 정면 projection (승인 2026-10-26). */
export interface BarRecord {
name: string;
k: number;
pts: [number, number, number][];
dMm: number;
}
export interface RebarScene {
group: THREE.Group;
byName: Map<string, THREE.Mesh[]>;
/** Every bar as recorded (same data as the meshes). */
records: BarRecord[];
/** Highlight one bar name (or none): the others are dimmed. */
/** Emphasise the bars in `names` (all when null). The others are dimmed, or hidden when `isolate` is on (선택만 보기). */
show(names: ReadonlySet<string> | null, isolate: boolean): void;
@@ -60,6 +70,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
const mColumn = materialFor(common, byMember, 'column');
const group = new THREE.Group();
const byName = new Map<string, THREE.Mesh[]>();
const records: BarRecord[] = [];
const Ms = m.stretches.map((_, k) => stretchMatrix(m, k));
const L = m.copingL;
const B = m.copingB;
@@ -71,6 +82,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
*/
const addPath = (name: string, k: number, pts: [number, number, number][], dMm: number, color: number) => {
if (pts.length < 2) return;
records.push({ name, k, pts: pts.map((p) => [...p] as [number, number, number]), dMm });
const R = mm(bendRadius(dMm, common.bend));
const pv = pts.map((p) => new THREE.Vector3(p[0], p[1], p[2]));
const path = new THREE.CurvePath<THREE.Vector3>();
@@ -110,6 +122,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
};
const addBar = (name: string, k: number, a: [number, number, number], b: [number, number, number], dMm: number, color: number) => {
records.push({ name, k, pts: [[...a], [...b]], dMm });
const dir = new THREE.Vector3(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
const len = dir.length();
if (len < 1e-6) return;
@@ -564,5 +577,5 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
const items = DIAMETER_GROUPS.map((g, i) => ({ label: g.label, color: hex(DIAMETER_COLORS[i]) })).filter((_, i) => present.has(i));
return present.has(-1) ? [...items, { label: '기타', color: hex(OTHER_COLOR) }] : items;
};
return { group, byName, show, setColorMode, legend };
return { group, byName, records, show, setColorMode, legend };
}