feat(view): round bar bends at the centre-line radius; bend factors as inputs on ③
Bars drawn through several points are one tube each, with every bend rounded by R·tan(φ/2) at the centre-line radius (inner factor × d + d/2). The inside-radius factors (D16 and below, D19–D25, D29–D35, D38 and above) are inputs in 공통 설정, with KDS-based defaults 2 / 3 / 4 / 5. The size-class limits sit in one place (SIZE_CLASS), which also fixes D25 (25.4) being read as the D29–D35 class in hookLength. The helper bendDeduction gives the centre-line deduction for the length option, which is not yet applied to the 철근표 lengths. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
03bb1f9929
commit
30e5e75c22
7 files changed
+146
-21
No files matched your search
+49
-5
@@ -5,7 +5,7 @@ import { bottomPiece, MAIN, widthLayout } from '../core/rebar/coping-main';
|
||||
import { C14_INSET, c14Bars, CAP, COPING_REBAR, SHEAR_LOOP_STEP, shearBars, shearBarsMulti, shearUHeight, copingSideBars, SIDE_HOOK_LEG, stairBars, undersideAt } from '../core/rebar/coping';
|
||||
import { columnRebar, COLUMN_P1 } from '../core/rebar/column';
|
||||
import { barsAcross, BLOCK_REBAR } from '../core/rebar/bearing-block';
|
||||
import { DEFAULT_MATERIAL, FckByMember, hookLength, Material, materialFor, NOMINAL_DIAMETER } from '../core/rebar/common';
|
||||
import { bendRadius, DEFAULT_MATERIAL, FckByMember, hookLength, Material, materialFor, NOMINAL_DIAMETER } from '../core/rebar/common';
|
||||
import { diameterGroupIndex, DIAMETER_GROUPS, memberOfBar, type RebarMemberKey } from '../core/rebar/color';
|
||||
import { stretchMatrix } from './scene';
|
||||
|
||||
@@ -62,6 +62,50 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
||||
const B = m.copingB;
|
||||
const straight = m.kink === null;
|
||||
|
||||
/**
|
||||
* A bar through several points as one tube, each bend rounded to its centre-line radius (수정 2026-10-23).
|
||||
* A bend of deflection φ is cut back by t = R·tan(φ/2) on both sides and joined by a quadratic curve through the corner.
|
||||
*/
|
||||
const addPath = (name: string, k: number, pts: [number, number, number][], dMm: number, color: number) => {
|
||||
if (pts.length < 2) return;
|
||||
const R = mm(bendRadius(dMm, common.bend));
|
||||
const pv = pts.map((p) => new THREE.Vector3(p[0], p[1], p[2]));
|
||||
const path = new THREE.CurvePath<THREE.Vector3>();
|
||||
let cur = pv[0].clone();
|
||||
for (let i = 1; i < pv.length - 1; i++) {
|
||||
const prev = pv[i - 1];
|
||||
const corner = pv[i];
|
||||
const next = pv[i + 1];
|
||||
const u = corner.clone().sub(prev);
|
||||
const v = next.clone().sub(corner);
|
||||
const lenIn = u.length();
|
||||
const lenOut = v.length();
|
||||
if (lenIn < 1e-9 || lenOut < 1e-9) continue;
|
||||
u.normalize();
|
||||
v.normalize();
|
||||
const phi = Math.acos(Math.min(1, Math.max(-1, u.dot(v))));
|
||||
// Cut back by the tangent length, never more than half of either adjacent piece.
|
||||
const t = Math.min(R * Math.tan(phi / 2), lenIn / 2, lenOut / 2);
|
||||
const a = corner.clone().addScaledVector(u, -t);
|
||||
const b = corner.clone().addScaledVector(v, t);
|
||||
if (a.distanceTo(cur) > 1e-9) path.add(new THREE.LineCurve3(cur, a));
|
||||
path.add(new THREE.QuadraticBezierCurve3(a, corner, b));
|
||||
cur = b;
|
||||
}
|
||||
const last = pv[pv.length - 1];
|
||||
if (last.distanceTo(cur) > 1e-9) path.add(new THREE.LineCurve3(cur, last));
|
||||
const segments = Math.min(400, Math.max(12, Math.round(path.getLength() * 100)));
|
||||
const geo = new THREE.TubeGeometry(path, segments, mm(dMm) / 2, 6, false);
|
||||
geo.applyMatrix4(Ms[k]);
|
||||
const mat = new THREE.MeshStandardMaterial({ color: rebarColor(color), roughness: 0.45, metalness: 0.1 });
|
||||
const mesh = new THREE.Mesh(geo, mat);
|
||||
mesh.userData = { name, roleColor: color, dMm, member: memberOfBar(name) };
|
||||
group.add(mesh);
|
||||
const list = byName.get(name) ?? [];
|
||||
list.push(mesh);
|
||||
byName.set(name, list);
|
||||
};
|
||||
|
||||
const addBar = (name: string, k: number, a: [number, number, number], b: [number, number, number], dMm: number, color: number) => {
|
||||
const dir = new THREE.Vector3(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
||||
const len = dir.length();
|
||||
@@ -100,7 +144,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
||||
[L - xk, z, n],
|
||||
[L - xk, z - hookTop, n],
|
||||
];
|
||||
for (let s = 0; s + 1 < pts.length; s++) addBar(name, 0, pts[s], pts[s + 1], NOMINAL_DIAMETER.H29, COLOR.coping);
|
||||
addPath(name, 0, pts, NOMINAL_DIAMETER.H29, COLOR.coping);
|
||||
});
|
||||
}
|
||||
// Bottom bars C7 / C8 (코핑철근.md §5.2–5.3): they follow the sloped underside, 127 above it, with a vertical leg up
|
||||
@@ -119,7 +163,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
||||
const right = left.map(([x, y, zz]): [number, number, number] => [L - x, y, zz]);
|
||||
const name = j % 2 === 1 ? 'C7' : 'C8';
|
||||
for (const pts of [left, right]) {
|
||||
for (let k = 0; k + 1 < pts.length; k++) addBar(name, 0, pts[k], pts[k + 1], NOMINAL_DIAMETER.H29, COLOR.coping);
|
||||
addPath(name, 0, pts, NOMINAL_DIAMETER.H29, COLOR.coping);
|
||||
}
|
||||
});
|
||||
// Shear loops C9 / C10 / C11 and the gaps between columns: a closed U at each position.
|
||||
@@ -323,7 +367,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
||||
const off = legOffsets();
|
||||
// One name, several cylinders: each segment of the path is one bar piece.
|
||||
const path = (name: string, pts: [number, number, number][], dMm: number) => {
|
||||
for (let k = 0; k + 1 < pts.length; k++) addBar(name, 0, pts[k], pts[k + 1], dMm, COLOR.footing);
|
||||
addPath(name, 0, pts, dMm, COLOR.footing);
|
||||
};
|
||||
// B1–B4: along s, at W position n. legTo (absolute EL, m) is where both ends turn up or down (§5.1); undefined = straight.
|
||||
const along = (name: string, n: number, y: number, legTo: number | undefined, dMm: number) => {
|
||||
@@ -375,7 +419,7 @@ export function buildRebar3D(m: PierModel, common: Material = DEFAULT_MATERIAL,
|
||||
|
||||
// B10-1 / B10-2 (§7) at each B10 level, B11 / B12 (§8) between them. Ends turn 90° inward (B10) or down (B11, B12).
|
||||
const polyline = (name: string, pts: [number, number, number][], dMm: number) => {
|
||||
for (let k = 0; k + 1 < pts.length; k++) addBar(name, 0, pts[k], pts[k + 1], dMm, COLOR.footing);
|
||||
addPath(name, 0, pts, dMm, COLOR.footing);
|
||||
};
|
||||
const hookB10 = mm(hookLength('main90', NOMINAL_DIAMETER.S19)); // 296
|
||||
const hookAsm = mm(Math.round(hookLength('main90', NOMINAL_DIAMETER.S16))); // 246
|
||||
|
||||
Reference in new issue
Block a user