fix(bearing): 짝 받침을 목록 순서가 아니라 거더 기하로 찾음 (두 노선 광주·완도)
운곡교(완도,광주) 데이터에서 구조물 목록이 A1-광주, A1-완도, P1-완도 … P6-완도, P1-광주 … P6-광주, A2-광주, A2-완도 순서라 "바로 다음 구조물"만 보던 짝짓기가 A1-광주→P1-광주와 P6-완도→A2-완도를 놓쳤다. 이제 모든 다른 구조물의 받침 중 거더를 따라 진행 방향으로 처음 만나는 받침(방위각 ≤ 0.1°, 거더선 ≤ 0.1 m)을 짝으로 한다. 이 데이터에서 14개 연결 × 5 = 70쌍, WS01·WS04 없음, S −2.028 ~ −1.754 %. 교대만 있는 다경간 입력(A1·A2 353 m, 방위각 8° 차)은 짝 없음 → 교대 종단경사 사용 (정상). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2668f17bf2
commit
54c855ab1a
2 files changed
+18
-6
No files matched your search
@@ -52,7 +52,7 @@ const DEG = Math.PI / 180;
|
||||
const angleDiffDeg = (a: number, b: number) => Math.abs(((a - b + 540) % 360) - 180);
|
||||
|
||||
/**
|
||||
* Girder pairs between neighbouring structures (Q-SH1, Q-SH4). For each bearing b on structure k the candidates on k + 1 lie
|
||||
* Girder pairs over the bridge (Q-SH1, Q-SH4). For each bearing b the candidates on the other structures lie
|
||||
* ahead along b's azimuth, within 0.1° of its azimuth and 0.1 m of its girder line. The pair is the first one reached along
|
||||
* the girder: on a straight bridge the next span's bearing (후열) lies on the same line further on, so "closest to the line"
|
||||
* alone would be a tie (2026-11-06 review). WS04 when another candidate is within 0.5 m of it along the girder.
|
||||
@@ -60,11 +60,13 @@ const angleDiffDeg = (a: number, b: number) => Math.abs(((a - b + 540) % 360) -
|
||||
*/
|
||||
export function girderPairs(structures: PairStructure[]): BearingPair[] {
|
||||
const pairs: BearingPair[] = [];
|
||||
for (let k = 0; k + 1 < structures.length; k++) {
|
||||
const here = structures[k], next = structures[k + 1];
|
||||
// Every other structure is searched, not only the next one in the list: with two lines (광주 · 완도) the list order
|
||||
// A1-광주, A1-완도, P1-완도 … mixes the lines, and the geometry alone tells which bearing ends the girder (2026-11-06).
|
||||
for (const here of structures) {
|
||||
const others = structures.filter((s) => s !== here).flatMap((s) => s.bearings.map((c) => ({ ...c, structure: s.name })));
|
||||
for (const b of here.bearings) {
|
||||
const u = { e: Math.sin(b.azimuthDeg * DEG), n: Math.cos(b.azimuthDeg * DEG) };
|
||||
const candidates = next.bearings.map((c) => {
|
||||
const candidates = others.map((c) => {
|
||||
const d = { e: c.x - b.x, n: c.y - b.y };
|
||||
return { c, along: d.e * u.e + d.n * u.n, offset: Math.abs(d.e * u.n - d.n * u.e), dAz: angleDiffDeg(c.azimuthDeg, b.azimuthDeg), d };
|
||||
}).filter((t) => t.along > 0 && t.dAz <= PAIR_AZIMUTH_TOL_DEG && t.offset <= PAIR_OFFSET_TOL_M)
|
||||
@@ -83,9 +85,9 @@ export function girderPairs(structures: PairStructure[]): BearingPair[] {
|
||||
if (fromCheckSec > AZIMUTH_CHECK_SEC || toCheckSec > AZIMUTH_CHECK_SEC) warnings.push('WS01');
|
||||
if (ambiguous) warnings.push('WS04');
|
||||
pairs.push({
|
||||
from: { structure: here.name, no: b.no }, to: { structure: next.name, no: best.c.no },
|
||||
from: { structure: here.name, no: b.no }, to: { structure: best.c.structure, no: best.c.no },
|
||||
distanceM, offsetM: best.offset, azimuthDiffDeg: best.dAz, directionDeg, fromCheckSec, toCheckSec,
|
||||
slopePct, uphill: best.c.z > b.z ? next.name : here.name, warnings,
|
||||
slopePct, uphill: best.c.z > b.z ? best.c.structure : here.name, warnings,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,3 +124,13 @@ describe('교대만 있는 프로젝트 (가져오기 허용 2026-11-06)', () =>
|
||||
expect(back.abutments?.map((a) => a.name)).toEqual(['A1']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('두 노선 (광주 · 완도) — 목록 순서와 무관하게 거더 기하로 짝 (2026-11-06)', () => {
|
||||
it('A1-광주, A1-완도, P1-완도, P1-광주 in that order still pair 광주 with 광주 and 완도 with 완도', () => {
|
||||
const shift = (s: PairStructure, name: string, de: number): PairStructure => ({ name, bearings: s.bearings.map((b) => ({ ...b, x: b.x + de })) });
|
||||
const list = [shift(A1, 'A1-광주', 13), shift(A1, 'A1-완도', 0), shift(P1, 'P1-완도', 0), shift(P1, 'P1-광주', 13)];
|
||||
const pairs = girderPairs(list);
|
||||
expect(pairs).toHaveLength(10);
|
||||
expect(pairs.every((p) => p.from.structure.slice(3) === p.to.structure.slice(3) && p.from.structure.startsWith('A1') && p.from.no === p.to.no)).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user