fix(abut): 수축줄눈을 받침 사이 중간에 · 기본 개수 ceil(L/10) − 1 · 3D 선 표시
spec_abut §3 · §4.9 (QA-7 가정)와 맞지 않던 세 가지를 고친다. - 위치: 등분점(1개면 L/2)이 아니라 가장 가까운 '받침 사이 중간'(= 교좌면 계단 경계). 이전에는 운곡교 교대 5기 모두 줄눈이 가운데 받침 ③ 블럭을 지났다 (A1: 줄눈 6.099 · 받침 6.037). 이제 A1은 IP3에서 4.905 m - 개수: 입력이 없으면 ceil(L/10) − 1 (길이에 따라 자동, 이전에는 1 고정). 입력 칸은 비우면 자동 - 3D: 벽체 전면 · 흉벽 전면 · 벽체 배면 · 흉벽 배면에 선으로 표시(저판은 연속이라 없음), '벽체·흉벽' 토글을 따름 - 공통 계산 core/abut/joints.ts를 ② 정면·배면 삽도, 교대 상세 요약, 입력 칸 안내, 3D가 함께 씀 - 테스트: 개수 규칙, A1 위치 = ②·③ 중간 = 계단 경계, 여러 개 · 받침 부족 시 등분, 3D 선 4면 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1fda705b75
commit
bff1502ecf
8 files changed
+158
-13
No files matched your search
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 교대 수축줄눈 (spec_abut §3 · §4.9, plan_abut AA13, QA-7 가정). Pure.
|
||||
*
|
||||
* - 개수: 입력값, 없으면 ceil(벽체 길이 / 10 m) − 1 (0 이상).
|
||||
* - 위치: 등분점 L·j / (n + 1)에서 가장 가까운 '받침 사이 중간'으로 옮긴다 (같은 거리면 s가 작은 쪽). 받침 사이 중간은
|
||||
* 교좌면 계단 경계와 같은 자리라 줄눈이 받침블럭을 지나지 않는다. 받침이 2개 미만이거나 중간점이 모자라면 등분점.
|
||||
* - 벽체 · 흉벽에만 두고 확대기초는 연속이다 (교대확대기초철근.md). 철근은 끊지 않는다 (spec_abut §6.1).
|
||||
*/
|
||||
|
||||
/** 기본 개수: ceil(L / 10) − 1, L in m. */
|
||||
export function defaultJointCount(lengthM: number): number {
|
||||
return Math.max(0, Math.ceil(lengthM / 10 - 1e-9) - 1);
|
||||
}
|
||||
|
||||
/** The count in use: the typed value, else the default from the length. */
|
||||
export function jointCount(lengthM: number, typed?: number): number {
|
||||
return typed ?? defaultJointCount(lengthM);
|
||||
}
|
||||
|
||||
/** Joint positions s (m from IP1, sorted). `bearingS` = the bearings' s along the 교대축. */
|
||||
export function jointPositions(lengthM: number, bearingS: number[], typed?: number): number[] {
|
||||
const n = jointCount(lengthM, typed);
|
||||
const sorted = [...bearingS].sort((a, b) => a - b);
|
||||
const mids = sorted.slice(1).map((s, i) => (s + sorted[i]) / 2);
|
||||
const used = new Set<number>();
|
||||
const out: number[] = [];
|
||||
for (let j = 1; j <= n; j++) {
|
||||
const ideal = (lengthM * j) / (n + 1);
|
||||
let best = -1;
|
||||
mids.forEach((m, i) => {
|
||||
if (used.has(i)) return;
|
||||
if (best < 0 || Math.abs(m - ideal) < Math.abs(mids[best] - ideal) - 1e-9) best = i;
|
||||
});
|
||||
if (best >= 0) { used.add(best); out.push(mids[best]); } else out.push(ideal);
|
||||
}
|
||||
return out.sort((a, b) => a - b);
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
* 교대 상세 (2026-11-03, 교각 상세와 같은 개념): the values the 삽도 shows, computed from the model. Read only.
|
||||
* Each row is [label, value]. Lengths in mm, levels in m, as in the 삽도.
|
||||
*/
|
||||
import { jointPositions } from './joints';
|
||||
import type { AbutRecord } from './parse';
|
||||
import { buildAbut, type AbutModel } from './geometry';
|
||||
import { toAbutInput } from './parse';
|
||||
@@ -38,7 +39,7 @@ export function abutSummaryRows(rec: AbutRecord): [string, string][] {
|
||||
['저판 폭 (앞굽 끝 / 뒷굽 끝)', `${Math.round(shape.footingFrontM * 1000)} / ${Math.round(shape.footingBackM * 1000)} mm`],
|
||||
['말뚝 (열 × 본수)', `${members.piles.length} × ${members.piles[0]?.s.length ?? 0} = ${members.piles.length * (members.piles[0]?.s.length ?? 0)} 본`],
|
||||
['말뚝 선단 EL', members.pileBottomEl === undefined ? '—' : m3(members.pileBottomEl)],
|
||||
['수축줄눈 (ceil(L/10) − 1)', `${Math.max(0, Math.ceil(L / 10) - 1)} 개`],
|
||||
['수축줄눈 (기본 ceil(L/10) − 1, 받침 사이 중간)', (() => { const js = jointPositions(L, model.bearings.map((b) => b.s), rec.shape?.shrinkJointCount); return js.length ? `${js.length} 개 · IP3에서 ${js.map((s) => (L - s).toFixed(3)).reverse().join(' / ')} m` : '0 개'; })()],
|
||||
];
|
||||
if (wings.length > 0) {
|
||||
const w = wings[0];
|
||||
|
||||
Reference in new issue
Block a user