feat(view): solplate taper across the 교각축 직각 (thick T1 at the (−) side); 교량받침 본체 as a box

The solplate's L (A + margin) runs across the 교각축 직각 and its W (B + margin) along the 교축; the top tapers across L with
T1 at the (−) side (T1 = T + L·|S|/200). The 교량받침 본체 is one box per bearing: the solplate plan less 100 mm on each
side, from the mortar top (EL.X) up h3 = 181 mm, turned with the bearing row. It is shown with the bearing group.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-23 14:56:26 +09:00
1 parent a108a76707
commit 22fd1dc5f4
4 files changed
+36 -17

No files matched your search

+15 -14
View File
@@ -1,12 +1,13 @@
/**
* 솔플레이트 기하 (1단계, 승인 2026-10-23). Pure: the solplate of one bearing, from its block (position, rowSkew) and the
* 공통 규칙 values. The solplate sits on the bearing (h3) and tapers along the 교축 방향 (s): the thick end T1 is on the
* 시점 side (s = −L/2), the thin end T2 on the 종점 side (s = +L/2). Lengths in m, as in the model.
* 솔플레이트 기하 (승인 2026-10-23). Pure: the solplate of one bearing, from its block (position, rowSkew) and the
* 공통 규칙 values. The plan is L = A + margin across the 교각축 직각 (n) and W = B + margin along the 교축 (s). The top
* tapers across L: the thick end T1 is at the (−) side of the 교각축 직각 direction (n = −L/2), the thin end T2 at (+) (n = +L/2).
* The underside is the bearing top (block top EL.X + h3). Lengths in m, as in the model.
*/
import { blockFramePoint, type BlockModel } from './geometry';
export interface SolplateParams {
/** 받침 평면 A (mm, along 교축 s) and B (mm, along the 교각축 직각 n). */
/** 받침 평면 A (mm, across the 교각축 직각) and B (mm, along the 교축). */
A: number;
B: number;
/** 솔플 여유 (mm): L = A + margin, W = B + margin. */
@@ -18,15 +19,15 @@ export interface SolplateParams {
}
export interface SolplateGeometry {
/** Length along 교축 (m) and width along 교각축 직각 (m). */
/** Length across the 교각축 직각 (m, = A + margin) and width along the 교축 (m, = B + margin). */
L: number;
W: number;
/** Thickness at the 시점 end (T1) and the 종점 end (T2) (m). */
/** Thickness at the (−) side (T1) and the (+) side (T2) of the 교각축 직각 direction (m). */
T1: number;
T2: number;
/** Underside (EL m): the bearing top = block top (EL.X) + h3. */
bottom: number;
/** Eight corners: [s, y, n] in the model's local frame (EL m). */
/** Eight corners: [s, y, n] in the model's local frame (EL m); order (a, c, bottom|top) with a along s and c along n. */
corners: [number, number, number][];
/** Volume (m³): L·W·(T1 + T2)/2. */
volume: number;
@@ -34,21 +35,21 @@ export interface SolplateGeometry {
/** Solplate of the bearing at `block`, with the bearing height h3 (mm) and the 공통 규칙 parameters. */
export function solplateGeometry(block: BlockModel, h3: number, p: SolplateParams): SolplateGeometry {
const L = (p.A + p.margin) / 1000;
const W = (p.B + p.margin) / 1000;
// Thickness change from the centre to each end: L·|S|/2, with S in % (mm).
const L = (p.A + p.margin) / 1000; // across the 교각축 직각 (n)
const W = (p.B + p.margin) / 1000; // along the 교축 (s)
// Thickness change from the centre to each side: L·|S|/2, with S in % (mm).
const drop = ((p.A + p.margin) * Math.abs(p.slopePct)) / 200 / 1000;
const T = p.T / 1000;
const T1 = T + drop;
const T2 = T - drop;
const bottom = block.padTop + h3 / 1000;
const thickAt = (a: number) => T1 + ((T2 - T1) * (a + L / 2)) / L;
const thickAt = (c: number) => T1 + ((T2 - T1) * (c + L / 2)) / L;
const corners: [number, number, number][] = [];
for (const a of [-L / 2, L / 2]) {
for (const c of [-W / 2, W / 2]) {
for (const a of [-W / 2, W / 2]) {
for (const c of [-L / 2, L / 2]) {
const [s, n] = blockFramePoint(block, a, c);
corners.push([s, bottom, n]);
corners.push([s, bottom + thickAt(a), n]);
corners.push([s, bottom + thickAt(c), n]);
}
}
return { L, W, T1, T2, bottom, corners, volume: (L * W * (T1 + T2)) / 2 };
+1 -1
View File
@@ -45,7 +45,7 @@ interface Pier extends PierValues {
type Stage = 'shape' | 'plan' | 'rebar' | 'quantity';
const PART_GROUPS: { label: string; parts: PartName[] }[] = [
{ label: '받침·받침블럭', parts: ['blocks', 'pads'] },
{ label: '받침·받침블럭', parts: ['blocks', 'pads', 'bearings'] },
{ label: '솔플레이트', parts: ['solplates'] },
{ label: '코핑', parts: ['coping'] },
{ label: '기둥', parts: ['columns'] },
+9 -2
View File
@@ -2,7 +2,7 @@ import * as THREE from 'three';
import type { PierModel } from '../core/geometry';
import { solplateGeometry } from '../core/solplate';
export type PartName = 'coping' | 'columns' | 'footings' | 'piles' | 'blinding' | 'blocks' | 'pads' | 'solplates' | 'ground';
export type PartName = 'coping' | 'columns' | 'footings' | 'piles' | 'blinding' | 'blocks' | 'pads' | 'bearings' | 'solplates' | 'ground';
export const PART_LABELS: Record<PartName, string> = {
coping: '코핑',
@@ -12,6 +12,7 @@ export const PART_LABELS: Record<PartName, string> = {
blinding: '버림콘크리트',
blocks: '받침블럭',
pads: '모르타르 패드',
bearings: '교량받침 본체',
solplates: '솔플레이트',
ground: '지반',
};
@@ -24,6 +25,7 @@ const COLORS: Record<PartName, number> = {
blinding: 0xe6e2d8,
blocks: 0xd6dde5,
pads: 0x8898aa,
bearings: 0x5b6676,
solplates: 0x6f7c8a,
ground: 0x6b8f4e,
};
@@ -140,7 +142,12 @@ export function buildPierScene(m: PierModel): PierScene {
pad.translate(b.s, b.padTop - 0.025, b.n);
add('pads', pad, 1, b.k);
if (b.plan) {
// Solplate: a wedge that tapers along the 교축 (T1 on the 시점 side), on the bearing (승인 2026-10-23).
// 교량받침 본체 (승인 2026-10-23): the solplate plan less 100 mm on each side, from the mortar top up to the solplate.
const body = new THREE.BoxGeometry((b.plan.B + b.plan.margin) / 1000 - 0.2, b.plan.h3 / 1000, (b.plan.A + b.plan.margin) / 1000 - 0.2);
body.rotateY(turn);
body.translate(b.s, b.padTop + b.plan.h3 / 2000, b.n);
add('bearings', body, 1, b.k);
// Solplate: a wedge that tapers across the 교각축 직각 (T1 at the (−) side), on the bearing (승인 2026-10-23).
const sp = solplateGeometry(b, b.plan.h3, { A: b.plan.A, B: b.plan.B, margin: b.plan.margin, T: b.plan.T, slopePct: b.plan.S });
add('solplates', wedgeGeometry(sp.corners), 1, b.k);
}
+11
View File
@@ -31,4 +31,15 @@ describe('솔플레이트 모델과 3D (2단계, 승인 2026-10-23)', () => {
const scene = buildPierScene(buildPier(loadP1()));
expect(scene.parts.solplates.children.length).toBe(0);
});
it('the 교량받침 본체 is one box per bearing: the solplate plan less 100 mm on each side, height h3 (181 mm)', () => {
const m = buildPier({ ...loadP1(), bearingPlans: plans, solplate: { T: 30, margin: 100, h3: 181 } });
const scene = buildPierScene(m);
const bodies = scene.parts.bearings.children;
expect(bodies.length).toBe(10);
const one = new THREE.Box3().setFromObject(bodies[0]);
expect(one.max.y - one.min.y).toBeCloseTo(0.181, 3);
// Body 1: L = 800 − 200 = 600 across the 교각축 직각, W = 740 − 200 = 540 along the 교축; the row skew turns it a few degrees.
expect(Math.max(one.max.x - one.min.x, one.max.z - one.min.z)).toBeGreaterThan(0.54);
});
});