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

+9 -3
View File
@@ -44,6 +44,12 @@ export function stretchMatrix(m: PierModel, k: number): THREE.Matrix4 {
* so each stretch's full-length slab is trimmed to its own half and the two meet at the mitred joint.
* Three.js keeps fragments with a non-negative distance from the plane, hence the sign flip for stretch 0.
*/
/** Mitre plane for one stretch as a list, or undefined on a straight axis. */
export function planesOf(m: PierModel, k: number): THREE.Plane[] | undefined {
const plane = mitrePlane(m, k);
return plane ? [plane] : undefined;
}
/** Straight-frame matrix (stretch 0). */
export function frameMatrix(m: PierModel): THREE.Matrix4 {
return stretchMatrix(m, 0);
@@ -102,19 +108,19 @@ export function buildPierScene(m: PierModel): PierScene {
for (const f of m.footings) {
const g = new THREE.BoxGeometry(f.length, f.top - f.bottom, f.width);
g.translate(f.s, (f.top + f.bottom) / 2, 0);
add('footings', g);
add('footings', g, 1, f.k, planesOf(m, f.k));
}
for (const b of m.blindings) {
const g = new THREE.BoxGeometry(b.length, b.thickness, b.width);
g.translate(b.s, b.top - b.thickness / 2, 0);
add('blinding', g);
add('blinding', g, 1, b.k, planesOf(m, b.k));
}
for (const p of m.piles) {
const g = new THREE.CylinderGeometry(p.diameter / 2, p.diameter / 2, p.top - p.bottom, 20);
g.translate(p.s, (p.top + p.bottom) / 2, p.n);
add('piles', g, 1, p.k);
add('piles', g, 1, p.k, planesOf(m, p.k));
}
for (const b of m.blocks) {