feat(abut): 교대 솔플레이트도 2026-11-06 결정으로 (짝 받침 S · T 하나 · 거더 하면 고정)
교대 받침 카드(spec_abut §5, QA-15)를 교각과 같은 계산(sole-plate.ts)으로 바꾸고 C안 모듈을 정리한다. - S: 짝 받침(A1 ↔ P1 전열, A2 ↔ Pn) 계산, 없으면 교대 종단경사 i(엑셀 Abut). 직접 수정 가능 - L = A + 100, W = B + 100 (A × B 기본 700 × 640, P1 전열 값 가정), 받침 1열이라 T 하나 - h3 기본값 = 받침 시트 받침높이 − T_ref (A1 275 − 30 = 245): 엑셀 받침높이의 거더 하면을 지킴. 시안은 P1의 h3 181을 가정했으나 교대 시트에 받침높이가 있어 이렇게 둔다 (입력으로 바꿀 수 있음) - 블럭 콘크리트 = 블럭 높이 − 패드 − (T − T_ref), E는 그대로 - 입력 칸: h3 · T_ref · T_min · 여유 · A · B · T · S (h3·T·S는 비우면 자동). C안 값(lengthMm 등)은 무시 - A1 검증: S −1.908 … −1.902 % (짝 P1 전열), L 800 · W 740 · T 30 · T1 38 · T2 22, E 400 - src/core/solplate-rule.ts(C안)와 그 테스트 삭제, 솔플레이트 기하 테스트는 새 계획으로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a0b0929e13
commit
87b445965b
7 files changed
+184
-205
No files matched your search
@@ -1,27 +1,36 @@
|
||||
/**
|
||||
* 교대 받침 카드 (2026-11-03, 시안 ② 교량받침·받침블럭·솔플레이트, 교각 카드와 같은 형식). 순수 함수.
|
||||
*
|
||||
* - 솔플레이트는 교각과 같은 규칙(C안, src/core/solplate-rule.ts)을 쓴다: 받침높이 H(솔플레이트 포함)는 교대 받침 시트 값
|
||||
* (운곡교 A1 275 mm)으로 고정하고, 교직 L · 교축 W · 종단 기울기 S를 입력한다. 중심 두께 T = ⌈22 + L·|S|/200⌉,
|
||||
* T1·T2 = T ± L·|S|/200, 받침 본체 h3 = H − T. 기본값은 교각과 같은 1000 × 1100 · −0.5 % (가정, QA-15, 결정 2026-11-03).
|
||||
* - 높이: E = h1 (블럭 콘크리트) + h2 (몰탈패드 50) + h3 + h4 (= T) = h1 + h2 + H. z = 패드 상면 = EL.X.
|
||||
* - 솔플레이트 (결정 2026-11-06, spec_abut §5·QA-15, src/core/sole-plate.ts): S = 같은 거더의 짝 받침(A1 ↔ P1 전열,
|
||||
* A2 ↔ Pn)으로 계산, 짝이 없으면 교대 종단경사 i(엑셀 Abut). L = A + 100, W = B + 100 (A × B 기본 700 × 640, 교각 P1
|
||||
* 전열 값 가정). 받침이 1열이라 T는 교대 전체에 하나: max(22, ⌈22 + L·|S|/2⌉). 거더 하면 고정 → 블럭 상면 = z − (T − T_ref).
|
||||
* - h3 기본값 = 받침 시트의 받침높이 − T_ref (A1 275 − 30 = 245): 엑셀 받침높이가 정한 거더 하면을 그대로 둔다
|
||||
* (시안은 교각 P1의 h3 181을 가정했으나 교대 시트에 받침높이가 있어 그 값을 지킨다).
|
||||
* - 높이: E = h1 (블럭 콘크리트) + h2 (몰탈패드 50) + h3 + h4 (= T). z = 패드 상면 = EL.X.
|
||||
*/
|
||||
import { solplatePlan, solplateRuleIssues } from '../solplate-rule';
|
||||
import type { SolplatePlan, SolplateRule } from '../types';
|
||||
import type { BearingPair } from '../bearing-pair';
|
||||
import { type BearingSole, SOLE_DEFAULTS, structureSoles } from '../sole-plate';
|
||||
import { ABUT_PAD_MM, type AbutModel } from './geometry';
|
||||
import type { AbutMembers } from './members';
|
||||
|
||||
/** 교대 솔플레이트 입력 (2026-11-06). Every value optional; absent = the default. */
|
||||
export interface AbutBearingRule {
|
||||
/** 솔플레이트 교직 L (mm). */
|
||||
lengthMm: number;
|
||||
/** 솔플레이트 교축 W (mm). */
|
||||
widthMm: number;
|
||||
/** 종단 기울기 S (%). */
|
||||
slopePct: number;
|
||||
/** 받침 본체 높이 h3 (mm). Absent = 받침높이 − T_ref. */
|
||||
h3Mm?: number;
|
||||
tRefMm: number;
|
||||
tMinMm: number;
|
||||
/** 솔플 여유 L − A = W − B (mm). */
|
||||
marginMm: number;
|
||||
/** 받침 평면 A (거더 방향) × B (mm), every bearing. */
|
||||
aMm: number;
|
||||
bMm: number;
|
||||
/** T typed (mm). Absent = 자동. */
|
||||
tMm?: number;
|
||||
/** S typed for every bearing (%). Absent = 짝 받침 계산. */
|
||||
slopePct?: number;
|
||||
}
|
||||
|
||||
/** 기본값: 교각 솔플레이트 규칙과 같은 1000 × 1100 · −0.5 % (QA-15, 사용자 결정 2026-11-03). */
|
||||
export const ABUT_BEARING_RULE_DEFAULT: AbutBearingRule = { lengthMm: 1000, widthMm: 1100, slopePct: -0.5 };
|
||||
export const ABUT_BEARING_RULE_DEFAULT: AbutBearingRule = { tRefMm: SOLE_DEFAULTS.tRefMm, tMinMm: SOLE_DEFAULTS.tMinMm, marginMm: SOLE_DEFAULTS.marginMm, aMm: SOLE_DEFAULTS.aMm, bMm: SOLE_DEFAULTS.bMm };
|
||||
/** 받침블럭 평면 (mm, 정사각) and 몰탈패드 평면 (mm), spec_abut §4.2. */
|
||||
export const ABUT_BLOCK_MM = 1200;
|
||||
export const ABUT_PAD_PLAN_MM = 1000;
|
||||
@@ -30,17 +39,34 @@ const I01_MIN_MM = 50 + 13;
|
||||
|
||||
const CIRCLED = ['①', '②', '③', '④', '⑤', '⑥', '⑦', '⑧', '⑨', '⑩'];
|
||||
|
||||
export function resolveBearingRule(changes?: Partial<AbutBearingRule>): AbutBearingRule {
|
||||
return { ...ABUT_BEARING_RULE_DEFAULT, ...(changes ?? {}) };
|
||||
/** Keys the 2026-11-06 rule reads; values stored by the C안 (lengthMm, widthMm, kind) are ignored. */
|
||||
const RULE_KEYS = ['h3Mm', 'tRefMm', 'tMinMm', 'marginMm', 'aMm', 'bMm', 'tMm', 'slopePct'] as const;
|
||||
|
||||
export function resolveBearingRule(changes?: Partial<AbutBearingRule> & Record<string, unknown>): AbutBearingRule {
|
||||
const own = Object.fromEntries(Object.entries(changes ?? {}).filter(([k]) => (RULE_KEYS as readonly string[]).includes(k)));
|
||||
return { ...ABUT_BEARING_RULE_DEFAULT, ...own };
|
||||
}
|
||||
|
||||
/** The pier rule with the 교대 받침높이 H (from the 받침 sheet). */
|
||||
export function abutSolplateRule(rule: AbutBearingRule, heightMm: number): SolplateRule {
|
||||
return { heightMm, lengthMm: rule.lengthMm, widthMm: rule.widthMm, slopePct: rule.slopePct };
|
||||
/** Bridge context of the abutment card: the girder pairs and the 교대 종단경사 i (decimal). */
|
||||
export interface AbutSoleContext {
|
||||
pairs?: BearingPair[];
|
||||
slopeI?: number;
|
||||
}
|
||||
|
||||
export function abutSolplatePlan(rule: AbutBearingRule, heightMm: number): SolplatePlan {
|
||||
return solplatePlan(abutSolplateRule(rule, heightMm));
|
||||
/** Solplate of every bearing of the abutment (one row). */
|
||||
export function abutSoles(model: AbutModel, rule: AbutBearingRule, heightMm: number, ctx: AbutSoleContext = {}): BearingSole[] {
|
||||
const plates = Object.fromEntries(model.bearings.map((b) => [String(b.no), { aMm: rule.aMm, bMm: rule.bMm }]));
|
||||
return structureSoles(
|
||||
model.name,
|
||||
model.bearings.map((b) => ({ no: b.no, row: '1열', azimuthDeg: b.azimuthDeg ?? 0 })),
|
||||
{
|
||||
h3Mm: rule.h3Mm ?? heightMm - rule.tRefMm, tRefMm: rule.tRefMm, tMinMm: rule.tMinMm, marginMm: rule.marginMm, plates,
|
||||
tByRow: rule.tMm === undefined ? undefined : { '1열': rule.tMm },
|
||||
slopePct: rule.slopePct === undefined ? undefined : Object.fromEntries(model.bearings.map((b) => [String(b.no), rule.slopePct!])),
|
||||
},
|
||||
ctx.pairs ?? [],
|
||||
ctx.slopeI === undefined ? undefined : ctx.slopeI * 100,
|
||||
);
|
||||
}
|
||||
|
||||
export interface AbutElevationRow {
|
||||
@@ -67,11 +93,13 @@ export interface AbutElevationRow {
|
||||
rotDeg: number;
|
||||
}
|
||||
|
||||
export function abutElevationRows(model: AbutModel, rule: AbutBearingRule, heightMm: number): AbutElevationRow[] {
|
||||
export function abutElevationRows(model: AbutModel, rule: AbutBearingRule, heightMm: number, ctx: AbutSoleContext = {}): AbutElevationRow[] {
|
||||
const half = ABUT_BLOCK_MM / 2000;
|
||||
const plan = abutSolplatePlan(rule, heightMm);
|
||||
const soles = new Map(abutSoles(model, rule, heightMm, ctx).map((x) => [x.no, x]));
|
||||
return model.bearings.map((b) => {
|
||||
const h1 = b.blockHeightMm - ABUT_PAD_MM;
|
||||
const plan = soles.get(b.no)!;
|
||||
// 거더 하면 고정: the block concrete loses T − T_ref (2026-11-06, Q-SH7).
|
||||
const h1 = b.blockHeightMm - ABUT_PAD_MM - plan.dropMm;
|
||||
const E = h1 + ABUT_PAD_MM + plan.h3 + plan.T;
|
||||
const gaps = model.stepBounds.map((x) => Math.abs(x - b.s) - half);
|
||||
return {
|
||||
@@ -81,7 +109,7 @@ export function abutElevationRows(model: AbutModel, rule: AbutBearingRule, heigh
|
||||
seatEl: b.seatEl,
|
||||
h1,
|
||||
h2: ABUT_PAD_MM,
|
||||
z: b.z,
|
||||
z: b.z - plan.dropMm / 1000,
|
||||
h3: plan.h3,
|
||||
h4: plan.T,
|
||||
E,
|
||||
@@ -98,37 +126,47 @@ export interface AbutSolplateRow {
|
||||
no: number;
|
||||
/** 기울기 (%). */
|
||||
S: number;
|
||||
/** S 근거 (계산 / 입력 / 가정 / 수정됨 / 없음) and the 짝 받침, e.g. "P1-①". */
|
||||
source: string;
|
||||
pair?: string;
|
||||
L: number;
|
||||
W: number;
|
||||
T: number;
|
||||
T1: number;
|
||||
T2: number;
|
||||
/** 검산 문구 "T1 − T2 = L·|S|/100". */
|
||||
/** 검산 문구 "T1 − T2 ≈ L·|S|/100" (W08, 1 mm 이내). */
|
||||
check: string;
|
||||
warnings: string[];
|
||||
}
|
||||
|
||||
export function abutSolplateRows(model: AbutModel, rule: AbutBearingRule, heightMm: number): AbutSolplateRow[] {
|
||||
const p = abutSolplatePlan(rule, heightMm);
|
||||
return model.bearings.map((b) => ({
|
||||
no: b.no,
|
||||
S: p.slopePct,
|
||||
L: p.L,
|
||||
W: p.W,
|
||||
T: p.T,
|
||||
T1: p.T1,
|
||||
T2: p.T2,
|
||||
check: `${(p.T1 - p.T2).toFixed(1)} = ${((p.L * Math.abs(p.slopePct)) / 100).toFixed(1)}`,
|
||||
}));
|
||||
export function abutSolplateRows(model: AbutModel, rule: AbutBearingRule, heightMm: number, ctx: AbutSoleContext = {}): AbutSolplateRow[] {
|
||||
return abutSoles(model, rule, heightMm, ctx).map((p) => {
|
||||
const rhs = (p.L * Math.abs(p.slopePct)) / 100;
|
||||
return {
|
||||
no: p.no, S: p.slopePct, source: p.slopeSource,
|
||||
pair: p.pair ? `${p.pair.structure}-${CIRCLED[p.pair.no - 1] ?? p.pair.no}` : undefined,
|
||||
L: p.L, W: p.W, T: p.T, T1: p.T1, T2: p.T2,
|
||||
check: `${p.T1 - p.T2} ≈ ${rhs.toFixed(1)} ${Math.abs(p.T1 - p.T2 - rhs) <= 1 + 1e-9 ? '일치' : '불일치 (W08)'}`,
|
||||
warnings: p.warnings,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/** Input problems of the 교대 받침 규칙 (the pier rule's checks with the 교대 H). Empty when it can build a solplate. */
|
||||
/** Input problems of the 교대 솔플레이트 입력. Empty when it can build a solplate. */
|
||||
export function abutBearingRuleIssues(rule: AbutBearingRule, heightMm: number): string[] {
|
||||
return solplateRuleIssues(abutSolplateRule(rule, heightMm));
|
||||
const out: string[] = [];
|
||||
for (const k of ['tRefMm', 'tMinMm', 'aMm', 'bMm'] as const) if (!(Number.isFinite(rule[k]) && rule[k] > 0)) out.push(`${k}는 0보다 커야 합니다.`);
|
||||
if (!(Number.isFinite(rule.marginMm) && rule.marginMm >= 0)) out.push('솔플 여유는 0 이상이어야 합니다.');
|
||||
if (rule.tMm !== undefined && !(Number.isFinite(rule.tMm) && rule.tMm > 0)) out.push('T는 0보다 커야 합니다.');
|
||||
if (rule.slopePct !== undefined && !Number.isFinite(rule.slopePct)) out.push('S는 숫자여야 합니다.');
|
||||
const h3 = rule.h3Mm ?? heightMm - rule.tRefMm;
|
||||
if (!(Number.isFinite(h3) && h3 > 0)) out.push(`받침 높이 h3 (${h3})는 0보다 커야 합니다. 받침높이 ${heightMm}와 T_ref를 확인하세요.`);
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 검사 줄 (시안): W02 블럭 콘크리트, W04 블럭이 교좌면 안, W03 블럭 끝 ~ 계단 경계, I01 블럭 철근. 문제 없으면 "없음". */
|
||||
export function abutBearingChecks(model: AbutModel, members: AbutMembers, rule: AbutBearingRule, heightMm: number): string[] {
|
||||
const rows = abutElevationRows(model, rule, heightMm);
|
||||
export function abutBearingChecks(model: AbutModel, members: AbutMembers, rule: AbutBearingRule, heightMm: number, ctx: AbutSoleContext = {}): string[] {
|
||||
const rows = abutElevationRows(model, rule, heightMm, ctx);
|
||||
const minH1 = Math.min(...rows.map((r) => r.h1));
|
||||
const half = ABUT_BLOCK_MM / 2000;
|
||||
// Block plan across the wall: centre t = frontSide × lateral, between the 흉벽 front (t 0) and the 벽체 front.
|
||||
|
||||
+20
-10
@@ -267,20 +267,30 @@ export const SHAPE_EDIT_FIELDS: { key: keyof AbutShape; label: string; group: 'w
|
||||
];
|
||||
|
||||
/** 받침 규칙 입력칸 (② 교량받침 카드): 교각 솔플레이트 규칙과 같은 칸. 받침높이 H는 교대 받침 시트 값으로 고정 (2026-11-03). */
|
||||
export const BEARING_RULE_FIELDS: { key: 'lengthMm' | 'widthMm' | 'slopePct'; label: string }[] = [
|
||||
{ key: 'lengthMm', label: '솔플레이트 교직 L (mm)' },
|
||||
{ key: 'widthMm', label: '솔플레이트 교축 W (mm)' },
|
||||
{ key: 'slopePct', label: '종단 기울기 S (%)' },
|
||||
/** 교대 솔플레이트 입력 칸 (2026-11-06). Optional ones (h3, T, S) go back to the automatic value when cleared. */
|
||||
export const BEARING_RULE_FIELDS: { key: keyof AbutBearingRule; label: string; optional?: boolean }[] = [
|
||||
{ key: 'h3Mm', label: '받침 높이 h3 (mm, 비우면 받침높이 − T_ref)', optional: true },
|
||||
{ key: 'tRefMm', label: 'T_ref · 엑셀 z 산정 때 두께 (mm)' },
|
||||
{ key: 'tMinMm', label: '솔플 최소두께 T_min (mm)' },
|
||||
{ key: 'marginMm', label: '솔플 여유 L − A = W − B (mm)' },
|
||||
{ key: 'aMm', label: '받침 A · 거더 방향 (mm)' },
|
||||
{ key: 'bMm', label: '받침 B (mm)' },
|
||||
{ key: 'tMm', label: '솔플레이트 T (mm, 비우면 자동)', optional: true },
|
||||
{ key: 'slopePct', label: 'S 직접 수정 (%, 비우면 짝 받침 계산)', optional: true },
|
||||
];
|
||||
|
||||
/**
|
||||
* Changes one 받침 규칙 value. L and W must be greater than 0, S any number, and the rule must still build a solplate with
|
||||
* the 교대 받침높이 H (the pier rule's checks).
|
||||
* Changes one 솔플레이트 입력 value (2026-11-06); `undefined` clears an optional one back to automatic. The result must
|
||||
* still build a solplate (positive sizes, h3 > 0 with the 교대 받침높이).
|
||||
*/
|
||||
export function applyBearingRule(rec: AbutRecord, key: keyof AbutBearingRule, value: number): AbutRecord {
|
||||
const n = Number(value);
|
||||
if (!Number.isFinite(n)) throw new Error('솔플레이트 규칙 값은 숫자여야 합니다.');
|
||||
const bearingRule = { ...(rec.bearingRule ?? {}), [key]: n };
|
||||
export function applyBearingRule(rec: AbutRecord, key: keyof AbutBearingRule, value: number | undefined): AbutRecord {
|
||||
const bearingRule: Record<string, unknown> = { ...(rec.bearingRule ?? {}) };
|
||||
if (value === undefined) delete bearingRule[key];
|
||||
else {
|
||||
const n = Number(value);
|
||||
if (!Number.isFinite(n)) throw new Error('솔플레이트 입력 값은 숫자여야 합니다.');
|
||||
bearingRule[key] = n;
|
||||
}
|
||||
const issues = abutBearingRuleIssues(resolveBearingRule(bearingRule), rec.bearingHeightMm);
|
||||
if (issues.length > 0) throw new Error(issues[0]);
|
||||
return { ...rec, bearingRule };
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
/**
|
||||
* 솔플레이트 규칙 (C안, 2026-11-03). Pure: the solplate every bearing of a pier gets from its rule. The rule gives the
|
||||
* 받침높이 H (solplate included), the plan size (교직 L across the 교각축 직각, 교축 W along the 교축) and the slope S (%).
|
||||
* The centre thickness T is the smallest whole mm that keeps the thin end T2 at 22 mm or more: T = ⌈22 + L·|S|/200⌉.
|
||||
* The bearing body is then h3 = H − T.
|
||||
*/
|
||||
import type { SolplatePlan, SolplateRule } from './types';
|
||||
|
||||
/** 공통 기본값 (2026-11-03): 받침높이 211 mm, 교직 1000 × 교축 1100 mm, 종단 기울기 −0.5 %. */
|
||||
export const SOLPLATE_RULE_DEFAULT: SolplateRule = { heightMm: 211, lengthMm: 1000, widthMm: 1100, slopePct: -0.5 };
|
||||
|
||||
/** Smallest allowed thickness at the thin end (mm). */
|
||||
export const SOLPLATE_MIN_T2_MM = 22;
|
||||
|
||||
/** Centre thickness T (mm, whole mm): the thin end T2 = T − L·|S|/200 is at least 22 mm. */
|
||||
export function solplateCenterT(lengthMm: number, slopePct: number): number {
|
||||
return Math.ceil(SOLPLATE_MIN_T2_MM + (lengthMm * Math.abs(slopePct)) / 200);
|
||||
}
|
||||
|
||||
/** The solplate plan of a rule: T, T1 = T + L·|S|/200, T2 = T − L·|S|/200, h3 = H − T. */
|
||||
export function solplatePlan(rule: SolplateRule): SolplatePlan {
|
||||
const T = solplateCenterT(rule.lengthMm, rule.slopePct);
|
||||
const drop = (rule.lengthMm * Math.abs(rule.slopePct)) / 200;
|
||||
return { L: rule.lengthMm, W: rule.widthMm, slopePct: rule.slopePct, T, T1: T + drop, T2: T - drop, h3: rule.heightMm - T };
|
||||
}
|
||||
|
||||
/** Input problems of a rule, in Korean; empty when the rule can build a solplate. */
|
||||
export function solplateRuleIssues(rule: SolplateRule): string[] {
|
||||
const issues: string[] = [];
|
||||
if (!(rule.lengthMm > 0) || !(rule.widthMm > 0)) issues.push('솔플레이트 교직·교축 길이는 0보다 커야 합니다.');
|
||||
if (!Number.isFinite(rule.slopePct)) issues.push('종단 기울기는 숫자여야 합니다.');
|
||||
if (!(rule.heightMm > 0)) issues.push('받침높이는 0보다 커야 합니다.');
|
||||
if (issues.length === 0) {
|
||||
const plan = solplatePlan(rule);
|
||||
if (!(rule.heightMm > plan.T)) issues.push(`받침높이는 솔플레이트 중심 두께 ${plan.T} mm보다 커야 합니다.`);
|
||||
}
|
||||
return issues;
|
||||
}
|
||||
+21
-25
@@ -62,7 +62,6 @@ import {
|
||||
ABUT_PAD_PLAN_MM,
|
||||
abutBearingChecks,
|
||||
abutElevationRows,
|
||||
abutSolplatePlan,
|
||||
abutSolplateRows,
|
||||
resolveBearingRule,
|
||||
} from './core/abut/bearing-table';
|
||||
@@ -120,7 +119,6 @@ import { findPileSpec, PHC_PILES, STEEL_PILES } from './core/pile-spec';
|
||||
import { footingPlanSvg, footingSideSvg } from './view/footing-svg';
|
||||
import { P1_COPING_GEOM } from './core/coping-geom';
|
||||
import { SOLE_DEFAULTS, type SoleSettings, soleSettingsIssues } from './core/sole-plate';
|
||||
import { SOLPLATE_MIN_T2_MM } from './core/solplate-rule';
|
||||
import { bridgePairs } from './core/bridge-pairs';
|
||||
import type { BearingPair } from './core/bearing-pair';
|
||||
import { type BarSummary, elevationRows, solplateRows } from './core/bearing-table';
|
||||
@@ -955,9 +953,10 @@ function fillAbutBearingCard(
|
||||
}
|
||||
const m3 = (v: number) => v.toFixed(3);
|
||||
const H = rec.bearingHeightMm;
|
||||
const plan = abutSolplatePlan(rule, H);
|
||||
const elev = abutElevationRows(model, rule, H);
|
||||
const sol = abutSolplateRows(model, rule, H);
|
||||
// 솔플레이트 S: 짝 받침(P1 전열 등) 계산, 없으면 교대 종단경사 i (2026-11-06).
|
||||
const ctx = { pairs: state.bridgePairs, slopeI: rec.slopeI };
|
||||
const elev = abutElevationRows(model, rule, H, ctx);
|
||||
const sol = abutSolplateRows(model, rule, H, ctx);
|
||||
// 상세 보기 (받침 ①–⑤): the three 삽도 draw the picked bearing.
|
||||
const pickNo = elev.some((r) => r.no === state.abutBearingNo) ? state.abutBearingNo : elev[0].no;
|
||||
box.append(
|
||||
@@ -991,7 +990,7 @@ function fillAbutBearingCard(
|
||||
figs.append(fig);
|
||||
}
|
||||
box.append(figs);
|
||||
box.append(el('p', `받침 ELEVATION TABLE (mm, EL·위치는 m) · 거리는 IP3(① 쪽)에서 · h3 = H − T, h4 = T (솔플레이트 규칙)`, 'lbl'));
|
||||
box.append(el('p', `받침 ELEVATION TABLE (mm, EL·위치는 m) · 거리는 IP3(① 쪽)에서 · h3 받침 (기본 받침높이 ${H} − T_ref), h4 = T · 거더 하면 고정`, 'lbl'));
|
||||
box.append(
|
||||
table(
|
||||
['No.', '위치 s', '구간', '교좌면 EL', 'h1 블럭', 'h2 패드', 'z = EL.X', 'h3 받침', 'h4 솔플', 'E', '솔플 상면 EL', '블럭 ~ 계단 경계', '방위각 CAD / 진북 (°)', '블럭 회전 (°)'],
|
||||
@@ -1003,40 +1002,37 @@ function fillAbutBearingCard(
|
||||
]),
|
||||
),
|
||||
);
|
||||
box.append(el('p', '솔플레이트 상세 TABLE (mm) · 솔플레이트 규칙', 'lbl'));
|
||||
box.append(el('p', '솔플레이트 상세 TABLE (mm) · S는 같은 거더 양끝 받침에서 계산', 'lbl'));
|
||||
box.append(
|
||||
table(
|
||||
['No.', 'S (%)', 'L', 'W', 'T', 'T1', 'T2', '검산 T1 − T2 = L·|S|/100'],
|
||||
sol.map((r) => [String(r.no), r.S.toFixed(3), String(r.L), String(r.W), String(r.T), r.T1.toFixed(1), r.T2.toFixed(1), r.check]),
|
||||
['No.', '짝 받침', 'S (%)', 'S 근거', 'L', 'W', 'T', 'T1 (오르막 쪽)', 'T2', '검산 T1 − T2 ≈ L·|S|/100', '검사'],
|
||||
sol.map((r) => [String(r.no), r.pair ?? '없음', r.S.toFixed(3), r.source, String(r.L), String(r.W), String(r.T), String(r.T1), String(r.T2), r.check, r.warnings.length ? r.warnings.join(' · ') : '—']),
|
||||
),
|
||||
);
|
||||
// 솔플레이트 규칙 (교각 카드와 같은 형식, 2026-11-03): H는 교대 받침 시트 값으로 고정, L · W · S를 입력한다.
|
||||
const d = ABUT_BEARING_RULE_DEFAULT;
|
||||
box.append(el('p', `솔플레이트 규칙 (이 교대 · 기본 ${d.lengthMm} × ${d.widthMm} · ${d.slopePct} %) · 받침높이 H ${H} mm 고정 (솔플레이트 포함)`, 'lbl'));
|
||||
// 솔플레이트 입력 (결정 2026-11-06): 교각 카드와 같은 항목, 받침이 1열이라 T 하나.
|
||||
box.append(el('p', `솔플레이트 입력 (이 교대) · T = max(T_min, ⌈T_min + L·|S|/2⌉) · 거더 하면 고정 → 블럭 상면 = z − (T − T_ref)`, 'lbl'));
|
||||
const auto = sol[0];
|
||||
for (const f of BEARING_RULE_FIELDS) {
|
||||
const id = idOf(`rule-${f.key}`);
|
||||
const lab = el('label', f.label);
|
||||
lab.htmlFor = id;
|
||||
const input = numberInput(id, String(rule[f.key]));
|
||||
if (rule[f.key] !== ABUT_BEARING_RULE_DEFAULT[f.key]) input.classList.add('changed-input');
|
||||
const stored = (rec.bearingRule as Record<string, unknown> | undefined)?.[f.key];
|
||||
const value = f.optional ? (typeof stored === 'number' ? String(stored) : '') : String(rule[f.key]);
|
||||
const input = numberInput(id, value);
|
||||
const base = f.key === 'h3Mm' ? `${H - rule.tRefMm}` : f.key === 'tMm' ? `자동 ${auto?.T ?? '—'}` : f.key === 'slopePct' ? `계산 ${auto ? auto.S.toFixed(3) : '—'}` : String(ABUT_BEARING_RULE_DEFAULT[f.key]);
|
||||
if (f.optional) input.placeholder = base;
|
||||
if (typeof stored === 'number' && stored !== ABUT_BEARING_RULE_DEFAULT[f.key]) input.classList.add('changed-input');
|
||||
input.addEventListener('change', () => {
|
||||
try {
|
||||
apply(applyBearingRule(rec, f.key, Number(input.value)));
|
||||
apply(applyBearingRule(rec, f.key, input.value.trim() === '' && f.optional ? undefined : Number(input.value)));
|
||||
} catch (err) {
|
||||
fail(err, input, String(rule[f.key]));
|
||||
fail(err, input, value);
|
||||
}
|
||||
});
|
||||
box.append(lab, input, el('span', `기본 ${ABUT_BEARING_RULE_DEFAULT[f.key]}`, 'muted small'));
|
||||
box.append(lab, input, el('span', `기본 ${base}`, 'muted small'));
|
||||
}
|
||||
box.append(
|
||||
el(
|
||||
'p',
|
||||
`중심 두께 T = ${plan.T} mm (T2 ≥ ${SOLPLATE_MIN_T2_MM} mm) · 받침 본체 h3 = H − T = ${plan.h3} mm · T1 = ${plan.T1.toFixed(1)} mm · T2 = ${plan.T2.toFixed(1)} mm`,
|
||||
'muted small',
|
||||
),
|
||||
);
|
||||
box.append(el('p', `블럭 평면 ${ABUT_BLOCK_MM} × ${ABUT_BLOCK_MM} (기본값) · 몰탈패드 ${ABUT_PAD_PLAN_MM} × ${ABUT_PAD_PLAN_MM} × 50 (기본값) · 블럭 높이 = min(z) − 교좌면 (계산)`, 'muted small'));
|
||||
box.append(el('p', `검사 · ${abutBearingChecks(model, members, rule, H).join(' · ')}`, 'muted small abut-checks'));
|
||||
box.append(el('p', `검사 · ${abutBearingChecks(model, members, rule, H, ctx).join(' · ')}`, 'muted small abut-checks'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user