diff --git a/src/core/solplate.ts b/src/core/solplate.ts index 36c394d..fc1fc14 100644 --- a/src/core/solplate.ts +++ b/src/core/solplate.ts @@ -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 }; diff --git a/src/main.ts b/src/main.ts index 8fff36b..a38f24f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -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'] }, diff --git a/src/view/scene.ts b/src/view/scene.ts index 0db5909..4c7d4a2 100644 --- a/src/view/scene.ts +++ b/src/view/scene.ts @@ -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 = { coping: '코핑', @@ -12,6 +12,7 @@ export const PART_LABELS: Record = { blinding: '버림콘크리트', blocks: '받침블럭', pads: '모르타르 패드', + bearings: '교량받침 본체', solplates: '솔플레이트', ground: '지반', }; @@ -24,6 +25,7 @@ const COLORS: Record = { 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); } diff --git a/tests/solplate-scene.test.ts b/tests/solplate-scene.test.ts index 42bdd41..beaa6eb 100644 --- a/tests/solplate-scene.test.ts +++ b/tests/solplate-scene.test.ts @@ -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); + }); });