fix(shape): 전·후열 나눔선을 교각 전체에서 하나로 둔다

횡방향 단차 코핑의 전·후열 나눔선을 구간마다 계산해, 꺾인 교각에서 두 구간의 판이 꺾임점에서 옆으로
어긋났다 (산외교 P11: −0.05 / +0.11). 두 열 전체 받침의 평균 n 하나를 쓰고, 어느 받침이든 그 선에서 블럭
반폭(0.6 m)보다 가까우면 지금처럼 구간별 선을 쓴다.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-11-10 15:51:10 +09:00
1 parent 9777938aa8
commit a39a1ba8d2
2 files changed
+43 -3

No files matched your search

+36
View File
@@ -53,3 +53,39 @@ describe('꺾임점 근처 계단 경계 (A, 2026-11-10)', () => {
expect(m.backSegments![2].s0).toBeCloseTo(own, 9);
});
});
describe('전·후열 나눔선 하나 (B, 2026-11-10)', () => {
const split = (m: ReturnType<typeof buildPier>, k: number) => {
const [front] = m.copingParts.filter((p) => p.k === k);
return Math.abs(front.nFrom) < Math.abs(front.nTo) ? front.nFrom : front.nTo;
};
const meanN = (m: ReturnType<typeof buildPier>, row: string, k?: number) => {
const rows = m.bearings.filter((b) => b.row === row && (k === undefined || b.k === k));
return rows.reduce((s, b) => s + b.n, 0) / rows.length;
};
it('both stretches use the same line, the mean of the two rows over the whole pier (no jog at the kink)', () => {
const m = buildPier(p11());
expect(m.copingParts).toHaveLength(4);
const nAll = (meanN(m, '전열') + meanN(m, '후열')) / 2;
expect(split(m, 0)).toBeCloseTo(nAll, 9);
expect(split(m, 1)).toBeCloseTo(nAll, 9);
// Per stretch the lines would differ by about 0.16 m.
const per = (k: number) => (meanN(m, '전열', k) + meanN(m, '후열', k)) / 2;
expect(Math.abs(per(0) - per(1))).toBeGreaterThan(0.1);
});
it('falls back to a line per stretch when a bearing would be closer than half a block to the common line', () => {
const input = p11();
const base = buildPier(input);
const nrm = base.stretches[1].nrm;
// Move back ⑦ towards the axis (+n side here is the front), to n ≈ +0.1.
const b7 = base.bearings.find((b) => b.no === 7)!;
const d = 0.1 - b7.n;
const bearings = input.bearings.map((b) => (b.no === 7 ? { ...b, x: b.x + d * nrm.e, y: b.y + d * nrm.n } : b));
const m = buildPier({ ...input, bearings });
const nAll = (meanN(m, '전열') + meanN(m, '후열')) / 2;
expect(m.bearings.some((b) => Math.abs(b.n - nAll) < DIM.blockSize / 2)).toBe(true);
for (const k of [0, 1]) expect(split(m, k)).toBeCloseTo((meanN(m, '전열', k) + meanN(m, '후열', k)) / 2, 9);
});
});