72 lines
3.4 KiB
TypeScript
72 lines
3.4 KiB
TypeScript
import type { BlockModel, PierModel } from './geometry';
|
|
|
|
/**
|
|
* 받침 배치 규칙 (승인 2026-10-26).
|
|
* - C4·C5: 교각축 방향, 받침 중심과 받침블럭 연단 사이 거리 (승인 2026-10-26, 교각축 방향으로 확정). 블록 형상에서 계산하고 도면값과 비교한다.
|
|
* - 일체: 같은 순서끼리 (전열 1 · 후열 1, 전열 2 · 후열 2 …, 각 열의 번호 순) 두 받침의 편심거리가 100 mm를 넘으면 분리를 우선한다.
|
|
* (P1 은 전열 1–5, 후열 6–10 으로 번호가 매겨져 있어서 번호 자체가 아니라 열 안의 순서로 짝짓는다.)
|
|
* 편심거리 = 두 받침 중심의 교각축 방향 차이 |s(전열) − s(후열)|.
|
|
*/
|
|
export const PAIR_ECCENTRICITY_LIMIT_MM = 100;
|
|
|
|
export interface EdgeDistance {
|
|
no: number;
|
|
row: BlockModel['row'];
|
|
/** 교각축 방향: 받침 중심에서 블록의 낮은 쪽(−s) 연단까지 (mm) = C4. */
|
|
leftMm: number;
|
|
/** 교각축 방향: 받침 중심에서 블록의 높은 쪽(+s) 연단까지 (mm) = C5. */
|
|
rightMm: number;
|
|
}
|
|
|
|
export interface PairEccentricity {
|
|
/** 전열 번호 and 후열 번호 of the pair. */
|
|
frontNo: number;
|
|
backNo: number;
|
|
eccentricityMm: number;
|
|
/** true: 편심이 한계 이하, 일체 배치 가능. */
|
|
allowed: boolean;
|
|
}
|
|
|
|
/**
|
|
* C4·C5 from the block geometry: distances along the 교각축 from each bearing centre to the block edges (mm).
|
|
* 분리: the 1200 block is centred on its bearing, so both are 600. 일체: the pair's block is centred on the pair's mean
|
|
* 교각축 position, so each bearing's margins follow its own offset (P1: the outer margins 557).
|
|
*/
|
|
export function bearingEdgeDistances(m: PierModel): EdgeDistance[] {
|
|
const HALF_DEPTH = 0.6; // 1200 / 2 along the 교각축, m
|
|
return m.blocks.map((b) => {
|
|
const host = m.integratedBlocks.find((x) => (b.row === '전열' ? x.frontNo : x.backNo) === b.no);
|
|
const centre = host ? host.s : b.s;
|
|
const low = centre - HALF_DEPTH;
|
|
const high = centre + HALF_DEPTH;
|
|
return { no: b.no, row: b.row, leftMm: (b.s - low) * 1000, rightMm: (high - b.s) * 1000 };
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Pairs by order within each row (전열 1 · 후열 1, 2 · 2 …) with their eccentricity.
|
|
* A bearing left without a partner (the rows have different counts) is not paired.
|
|
*/
|
|
export function pairEccentricities(blocks: BlockModel[]): PairEccentricity[] {
|
|
const byNo = (a: BlockModel, b: BlockModel) => a.no - b.no;
|
|
const front = blocks.filter((b) => b.row === '전열').sort(byNo);
|
|
const back = blocks.filter((b) => b.row === '후열').sort(byNo);
|
|
const out: PairEccentricity[] = [];
|
|
for (let i = 0; i < Math.min(front.length, back.length); i++) {
|
|
const e = Math.abs(front[i].s - back[i].s) * 1000;
|
|
out.push({ frontNo: front[i].no, backNo: back[i].no, eccentricityMm: e, allowed: e <= PAIR_ECCENTRICITY_LIMIT_MM });
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* 일체 requires equal row counts, at least one pair, and every pair within the limit.
|
|
* Returns the pairs over the limit so the reason can be shown.
|
|
*/
|
|
export function integratedCheck(blocks: BlockModel[]): { allowed: boolean; overLimit: PairEccentricity[] } {
|
|
const pairs = pairEccentricities(blocks);
|
|
const overLimit = pairs.filter((p) => !p.allowed);
|
|
const equalCounts = blocks.filter(b => b.row === '전열').length === blocks.filter(b => b.row === '후열').length;
|
|
return { allowed: equalCounts && pairs.length > 0 && overLimit.length === 0, overLimit };
|
|
}
|