feat(core,view): bent coping stage 3 — footings and piles in stretch frames

- Footings, blindings and piles on a bent axis are placed in their stretch's
  frame; 일체기초 is grouped per stretch, so a combined footing never crosses
  the kink (separate footings, each aligned with its stretch).
- Footings, blindings and piles are trimmed at the mitre plane like the coping.
- The stage-2 refusal for bent foundations is removed; the Level-half-width
  refusal for columns at the kink remains.
- Tests: T형 footing crossing the kink stays in stretch 0; 2주형 with columns
  on both sides gives one footing per stretch, with mitre clipping in the scene.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
ypshimandClaude Haiku 5.5 committed 2026-10-22 09:38:01 +09:00
1 parent c9dae4ff9b
commit 9e1e25f8fe
5 files changed
+56 -23

No files matched your search

+17 -9
View File
@@ -77,6 +77,7 @@ export interface ColumnModel {
export interface FootingModel {
s: number;
k: number;
top: number;
bottom: number;
length: number;
@@ -85,6 +86,7 @@ export interface FootingModel {
export interface BlindingModel {
s: number;
k: number;
top: number;
length: number;
width: number;
@@ -178,7 +180,7 @@ export function solveIp4(ip1: Vec2, ip2: Vec2, ip3: Vec2, angleDeg: number): Vec
* Builds the first-stage model of a T-type pier from one input record. Pure function.
* Coordinates: g = arc length from the coping start (BP1), so g = 0 at BP1 and g = L at BP2.
* Each object carries its stretch k and a local s measured from that stretch's base (k = 0: BP1, k = 1: IP4).
* A bent coping (IP4 angle ≠ 0) is supported for 현장타설말뚝 only; footings and piles on a bent axis are stage 3.
* A bent coping (IP4 angle ≠ 0) puts each footing in its stretch's frame; footings that would cross the kink are not combined.
*/
export function buildPier(input: PierInput): PierModel {
const ip = (name: string) => {
@@ -191,9 +193,6 @@ export function buildPier(input: PierInput): PierModel {
const ip3 = ip('IP3');
const ip4 = ip('IP4');
const bent = ip4.angleDeg !== 0;
if (bent && input.foundationType !== '현장타설말뚝') {
throw new Error('미실시: 꺾인 코핑의 확대기초·말뚝은 3단계에서 구현합니다. 현재는 현장타설말뚝만 지원합니다.');
}
const L = input.copingLengthMm / 1000;
const B = input.copingWidthMm / 1000;
@@ -325,6 +324,14 @@ export function buildPier(input: PierInput): PierModel {
}
}
// Footings are grouped per stretch so that a 일체기초 never crosses the kink; each group is aligned with its stretch.
const footingSets: { s: number; k: number; length: number }[] = [];
for (let k = 0; k < stretchCount; k++) {
for (const g of footingGroups(colG.filter((_, i) => colK[i] === k))) {
footingSets.push({ s: g.s - base[k], k, length: g.length });
}
}
const footingTop = input.foundationType === '현장타설말뚝' ? input.footingBottomEl : input.footingBottomEl + DIM.footingH;
const columns: ColumnModel[] = colG.map((g, i) => ({
s: g - base[colK[i]],
@@ -345,17 +352,18 @@ export function buildPier(input: PierInput): PierModel {
piles.push({ s: c.s, k: c.k, n: 0, top: input.footingBottomEl, bottom: pileTip, diameter: DIM.columnDiameter });
});
} else {
for (const g of footingGroups(colG)) {
footings.push({ s: g.s, top: footingTop, bottom: input.footingBottomEl, length: g.length, width: DIM.footingW });
for (const f of footingSets) {
footings.push({ s: f.s, k: f.k, top: footingTop, bottom: input.footingBottomEl, length: f.length, width: DIM.footingW });
blindings.push({
s: g.s,
s: f.s,
k: f.k,
top: input.footingBottomEl,
length: g.length + DIM.blindingMargin,
length: f.length + DIM.blindingMargin,
width: DIM.footingW + DIM.blindingMargin,
thickness: DIM.blindingT,
});
if (input.foundationType === '말뚝기초') {
piles.push(...pilesFor(g.s, input.footingBottomEl, pileLength, g.length));
piles.push(...pilesFor(f.s, input.footingBottomEl, pileLength, f.length).map((p) => ({ ...p, k: f.k })));
}
}
}