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:
1 parent
9777938aa8
commit
a39a1ba8d2
2 files changed
+43
-3
No files matched your search
@@ -409,12 +409,16 @@ export function buildPier(input: PierInput, ctx: PierContext = {}): PierModel {
|
|||||||
const meanN = (rows: { n: number }[]) => rows.reduce((sum, r) => sum + r.n, 0) / rows.length;
|
const meanN = (rows: { n: number }[]) => rows.reduce((sum, r) => sum + r.n, 0) / rows.length;
|
||||||
const copingParts: CopingPart[] = [];
|
const copingParts: CopingPart[] = [];
|
||||||
const stretchCount = kinkG === null ? 1 : 2;
|
const stretchCount = kinkG === null ? 1 : 2;
|
||||||
|
// One front/back line for the whole pier (2026-11-10), so the parts of the two stretches meet at the kink without a
|
||||||
|
// sideways jog; per stretch only when some bearing would be closer than half a block to that line.
|
||||||
|
const nAll = (meanN(frontPlaced) + meanN(backPlaced)) / 2;
|
||||||
|
const oneLine = [...frontPlaced, ...backPlaced].every((b) => Math.abs(b.n - nAll) >= halfBlock);
|
||||||
for (let k = 0; k < stretchCount; k++) {
|
for (let k = 0; k < stretchCount; k++) {
|
||||||
const fRows = frontPlaced.filter((b) => b.k === k);
|
const fRows = oneLine ? frontPlaced : frontPlaced.filter((b) => b.k === k);
|
||||||
const bRows = backPlaced.filter((b) => b.k === k);
|
const bRows = oneLine ? backPlaced : backPlaced.filter((b) => b.k === k);
|
||||||
const nStep = fRows.length && bRows.length
|
const nStep = fRows.length && bRows.length
|
||||||
? (meanN(fRows) + meanN(bRows)) / 2
|
? (meanN(fRows) + meanN(bRows)) / 2
|
||||||
: (meanN(frontPlaced) + meanN(backPlaced)) / 2;
|
: nAll;
|
||||||
if (lateralStep) {
|
if (lateralStep) {
|
||||||
// The front row may lie on either side of the axis (it depends on the IP1 → IP3 direction), so each part takes the
|
// The front row may lie on either side of the axis (it depends on the IP1 → IP3 direction), so each part takes the
|
||||||
// side of its own row; the order stays [front, back].
|
// side of its own row; the order stays [front, back].
|
||||||
|
|||||||
@@ -53,3 +53,39 @@ describe('꺾임점 근처 계단 경계 (A, 2026-11-10)', () => {
|
|||||||
expect(m.backSegments![2].s0).toBeCloseTo(own, 9);
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user