feat(view): solplate in the 3D model (2단계): wedges from the drawing's A, B, S; read the solplate table from DXF

Each bearing gets a solplate wedge: tapered along the 교축 with T1 on the 시점 side, underside at the bearing top (block
top + h3). A, B come from the drawing's ELEVATION table, S and T1/T2 from the SOLPLATE table (NO, S(%), L, W, T, T1, T2),
read by position. The 공통 규칙 (T 30, margin 100, h3 181) feed the plan; changing them regenerates the piers. A new
"솔플레이트" part can be shown or hidden. A solplate table is read only when its S values are found; a missing S is reported.
Also commits the option-1 test change (drawing EL.X minus Excel z).

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-23 14:46:53 +09:00
1 parent 1d8746d533
commit a50f4f5ee5
10 files changed
+579 -13

No files matched your search

+10 -2
View File
@@ -69,6 +69,8 @@ export interface BlockModel {
padTop: number;
/** Skew (deg, −90…90] of the bearing row against the perpendicular of the stretch axis; the block sides follow the row. */
rowSkewDeg: number;
/** Solplate plan of this bearing (A, B, S, T, margin, h3), when the input gives it. */
plan?: { A: number; B: number; S: number; T: number; margin: number; h3: number };
}
/** Skew of a bearing row (deg) from the bearing azimuth and the stretch axis direction u (see {@link BlockModel.rowSkewDeg}). */
@@ -400,13 +402,19 @@ export function buildPier(input: PierInput): PierModel {
const blocks: BlockModel[] = [];
const bearingAz = new Map(input.bearings.map((r) => [r.no, r.azimuthDeg]));
const skewOf = (no: number, k: number) => rowSkewDeg(bearingAz.get(no) ?? NaN, axis.segments[k].u);
// Solplate plans from the input (승인 2026-10-23); the 공통 규칙 default is T 30, margin 100, h3 181.
const rules = input.solplate ?? { T: 30, margin: 100, h3: 181 };
const planOf = (no: number) => {
const p = input.bearingPlans?.find((q) => q.no === no);
return p ? { A: p.A, B: p.B, S: p.S, T: rules.T, margin: rules.margin, h3: rules.h3 } : undefined;
};
frontPlaced.forEach((b) => {
const bottom = segmentTop(segments, b.g);
blocks.push({ no: b.no, row: '전열', k: b.k, s: b.s, g: b.g, n: b.n, bottom, top: b.z - DIM.padThickness, padTop: b.z, rowSkewDeg: skewOf(b.no, b.k) });
blocks.push({ no: b.no, row: '전열', k: b.k, s: b.s, g: b.g, n: b.n, bottom, top: b.z - DIM.padThickness, padTop: b.z, rowSkewDeg: skewOf(b.no, b.k), plan: planOf(b.no) });
});
backPlaced.forEach((b) => {
const bottom = b.z - h2;
blocks.push({ no: b.no, row: '후열', k: b.k, s: b.s, g: b.g, n: b.n, bottom, top: b.z - DIM.padThickness, padTop: b.z, rowSkewDeg: skewOf(b.no, b.k) });
blocks.push({ no: b.no, row: '후열', k: b.k, s: b.s, g: b.g, n: b.n, bottom, top: b.z - DIM.padThickness, padTop: b.z, rowSkewDeg: skewOf(b.no, b.k), plan: planOf(b.no) });
});
const blockHeightFront = blocks.find((b) => b.row === '전열')!.top - blocks.find((b) => b.row === '전열')!.bottom;