Fix
This commit is contained in:
@@ -84,7 +84,15 @@ const createConcaveFilletShape = (radius: number): THREE.Shape => {
|
||||
};
|
||||
|
||||
// New Helper: Create Perforated Plate (Vertical Wall)
|
||||
const createPerforatedPlate = (width: number, height: number, thickness: number, perf: PerforationConfig): THREE.BufferGeometry => {
|
||||
const createPerforatedPlate = (
|
||||
width: number,
|
||||
height: number,
|
||||
thickness: number,
|
||||
perf: PerforationConfig,
|
||||
marginLeft: number = 0,
|
||||
marginRight: number = 0,
|
||||
exclusions: { start: number, end: number, yMax?: number }[] = []
|
||||
): THREE.BufferGeometry => {
|
||||
const shape = new THREE.Shape();
|
||||
shape.moveTo(0, 0);
|
||||
shape.lineTo(width, 0);
|
||||
@@ -96,9 +104,10 @@ const createPerforatedPlate = (width: number, height: number, thickness: number,
|
||||
if (perf && perf.enabled && width > perf.size && height > perf.size) {
|
||||
const { shape: shapeType, size, gap } = perf;
|
||||
const step = size + gap;
|
||||
const startX = gap; // Margin
|
||||
const startY = gap; // Margin
|
||||
const endX = width - gap; // Margin
|
||||
// Margins: ensure holes don't cut into the solid edge zones
|
||||
const startX = Math.max(gap, marginLeft + gap);
|
||||
const startY = gap;
|
||||
const endX = width - Math.max(gap, marginRight + gap);
|
||||
const endY = height - gap;
|
||||
|
||||
// Rows
|
||||
@@ -111,8 +120,22 @@ const createPerforatedPlate = (width: number, height: number, thickness: number,
|
||||
const hole = new THREE.Path();
|
||||
const r = size / 2;
|
||||
|
||||
// Boundary check (approximate center check)
|
||||
if (x - r < 0 || x + r > width || y - r < 0 || y + r > height) continue;
|
||||
// Boundary check
|
||||
if (x - r < marginLeft || x + r > width - marginRight || y - r < 0 || y + r > height) continue;
|
||||
|
||||
// Exclusion Zone Check
|
||||
// Zone active if hole X is within [start, end] AND hole Y is below yMax (if specified).
|
||||
// If y > yMax, the exclusion doesn't apply (it's above the intersecting wall).
|
||||
// Note: y is measured from bottom (0) to top (height).
|
||||
// yMax is the height of the intersecting partition.
|
||||
|
||||
const inExclusion = exclusions.some(zone => {
|
||||
if (x + r <= zone.start || x - r >= zone.end) return false; // X-axis check
|
||||
if (zone.yMax !== undefined && y - r > zone.yMax) return false; // Y-axis check (hole above wall)
|
||||
return true;
|
||||
});
|
||||
|
||||
if (inExclusion) continue;
|
||||
|
||||
if (shapeType === 'circle') {
|
||||
hole.absarc(x, y, r, 0, Math.PI * 2, true);
|
||||
@@ -143,7 +166,7 @@ const createPerforatedPlate = (width: number, height: number, thickness: number,
|
||||
}
|
||||
|
||||
const geo = new THREE.ExtrudeGeometry(shape, { depth: thickness, bevelEnabled: false });
|
||||
// Extruded along Z. Wall is flat on XY.
|
||||
// Extruded along Z. Wall is flat on XY.
|
||||
// We want "thickness" to be Z depth.
|
||||
return geo;
|
||||
};
|
||||
@@ -152,23 +175,29 @@ const createPerforatedPlate = (width: number, height: number, thickness: number,
|
||||
const createCornerProfile = (radius: number, thickness: number, height: number): THREE.BufferGeometry => {
|
||||
if (radius <= 0) return new THREE.BufferGeometry();
|
||||
const shape = new THREE.Shape();
|
||||
// External Arc (from X-axis to Y-axis)
|
||||
|
||||
// Create a Ring Segment (Hollow Corner) as a single loop.
|
||||
// Center at (0,0).
|
||||
const innerRadius = Math.max(0.01, radius - thickness); // Ensure slightly > 0 to maintain shape integrity
|
||||
|
||||
// 1. Start at Outer Start
|
||||
shape.moveTo(radius, 0);
|
||||
|
||||
// 2. Outer Arc (CCW) -> To (0, radius)
|
||||
shape.absarc(0, 0, radius, 0, Math.PI / 2, false);
|
||||
// Line to inner
|
||||
shape.lineTo(0, radius - thickness); // Assuming innerRadius = radius - thickness
|
||||
// Inner Arc (backwards)
|
||||
const innerRadius = Math.max(0.1, radius - thickness);
|
||||
|
||||
// 3. Line to Inner End (0, innerRadius)
|
||||
shape.lineTo(0, innerRadius);
|
||||
|
||||
// 4. Inner Arc (CW) -> To (innerRadius, 0)
|
||||
shape.absarc(0, 0, innerRadius, Math.PI / 2, 0, true);
|
||||
// Close
|
||||
|
||||
// 5. Close loop
|
||||
shape.lineTo(radius, 0);
|
||||
|
||||
// Extrude vertically (Height is Z for now, usually Extrude goes Z)
|
||||
const geo = new THREE.ExtrudeGeometry(shape, { depth: height, bevelEnabled: false, curveSegments: 16 });
|
||||
// Rotate so height is along Y? No, Extrude defaults to Z depth.
|
||||
// We want the Profile on XZ plane extruded up Y?
|
||||
// Shape is on XY. Extrude is Z.
|
||||
// If shape is on XY (top view of corner), Extrude Z creates Height.
|
||||
// This matches standard logic if we rotate whole object later.
|
||||
// Extrude
|
||||
// curveSegments 32 for smoothness
|
||||
const geo = new THREE.ExtrudeGeometry(shape, { depth: height, bevelEnabled: false, curveSegments: 32 });
|
||||
return geo;
|
||||
};
|
||||
|
||||
@@ -223,83 +252,193 @@ export const createBinGeometry = (
|
||||
// 1. Stand Up: Extrusion Z -> Y. Shape moves to X(+)/Z(+).
|
||||
cornerGeoBase.rotateX(-Math.PI / 2);
|
||||
|
||||
// Base Corner Shape (after rotateX) is Q4 (+X, -Z).
|
||||
// Rotation Logic: -90 degrees per Quadrant (Standard Three.js Y-Rot).
|
||||
// Q4 (0) -> Q1 (-90) -> Q2 (-180/180) -> Q3 (-270/+90).
|
||||
|
||||
const positions = [
|
||||
{ x: width / 2 - effRadius, z: depth / 2 - effRadius, rot: -Math.PI / 2 }, // Front Right (X+, Z+) -> Needs (X+, Z+). Base is (X+, Z-). Rot -90 -> (Z+, X+)
|
||||
{ x: -(width / 2 - effRadius), z: depth / 2 - effRadius, rot: Math.PI }, // Front Left (X-, Z+) -> Needs (X-, Z+). Rot 180 -> (X-, Z+)
|
||||
{ x: -(width / 2 - effRadius), z: -(depth / 2 - effRadius), rot: Math.PI / 2 }, // Back Left (X-, Z-) -> Needs (X-, Z-). Rot 90 -> (Z-, X-) which is X-, Z-? No wait.
|
||||
// Rot 90 on (X+, Z-): X->Z, Z->-X. (X+, Z-) -> (-Z, -X) = (X-, Z-). Correct.
|
||||
{ x: width / 2 - effRadius, z: -(depth / 2 - effRadius), rot: 0 } // Back Right (X+, Z-) -> Matches Base.
|
||||
// Back Right (+X, +Z). Q1.
|
||||
// Rot -90 (-PI/2).
|
||||
{ x: width / 2 - effRadius, z: depth / 2 - effRadius, rot: -Math.PI / 2 },
|
||||
|
||||
// Back Left (-X, +Z). Q2.
|
||||
// Rot 180 (PI).
|
||||
{ x: -(width / 2 - effRadius), z: depth / 2 - effRadius, rot: Math.PI },
|
||||
|
||||
// Front Left (-X, -Z). Q3.
|
||||
// Rot 90 (PI/2). (Equivalent to -270).
|
||||
{ x: -(width / 2 - effRadius), z: -(depth / 2 - effRadius), rot: Math.PI / 2 },
|
||||
|
||||
// Front Right (+X, -Z). Q4.
|
||||
// Rot 0.
|
||||
{ x: width / 2 - effRadius, z: -(depth / 2 - effRadius), rot: 0 }
|
||||
];
|
||||
|
||||
positions.forEach(pos => {
|
||||
const c = cornerGeoBase.clone();
|
||||
c.rotateY(pos.rot);
|
||||
c.translate(pos.x, thickness, pos.z);
|
||||
geometries.push(c);
|
||||
const corner = cornerGeoBase.clone();
|
||||
corner.rotateY(pos.rot);
|
||||
corner.translate(pos.x, 0, pos.z); // Start at Y=0
|
||||
corner.translate(0, thickness, 0); // Move on top of floor
|
||||
geometries.push(corner);
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Straight Walls (4 pcs) - Centered on edges
|
||||
|
||||
// REWRITE EXCLUSION COLLECTION LOGIC TO BE WALL-SPECIFIC
|
||||
const exclusionsBack: { start: number, end: number, yMax: number }[] = [];
|
||||
const exclusionsFront: { start: number, end: number, yMax: number }[] = [];
|
||||
const exclusionsLeft: { start: number, end: number, yMax: number }[] = [];
|
||||
const exclusionsRight: { start: number, end: number, yMax: number }[] = [];
|
||||
|
||||
// Inner Dimensions
|
||||
const effectiveInnerW = width - 2 * thickness;
|
||||
const effectiveInnerD = depth - 2 * thickness;
|
||||
|
||||
partitions.forEach(p => {
|
||||
const hEff = Math.max(0.1, p.height - thickness); // Exclude only up to partition height
|
||||
|
||||
if (p.axis === 'x') {
|
||||
// Runs Depth-wise (Y axis in Layout).
|
||||
// Intersects Front and Back walls (which are Width-wise plates).
|
||||
|
||||
// X pos on Front/Back walls:
|
||||
// Partition X global: (-effectiveInnerW / 2) + (effectiveInnerW * p.offset)
|
||||
// Wall plate local X: 0 to straightW.
|
||||
// Wall Global X range: [-straightW/2, straightW/2].
|
||||
// Map partition global X to wall local X:
|
||||
// localX = partGlobalX - (-straightW/2) = partGlobalX + straightW/2.
|
||||
|
||||
// Note: straightW = width - 2*effRadius.
|
||||
// effectiveInnerW = width - 2*thickness.
|
||||
// These coordinate spaces are slightly different if radius > thickness.
|
||||
// We should use the ACTUAL spatial intersection.
|
||||
|
||||
const partGlobalX = (-effectiveInnerW / 2) + (effectiveInnerW * p.offset);
|
||||
const sW = width - 2 * effRadius;
|
||||
const localXOnWall = partGlobalX + sW / 2;
|
||||
|
||||
// Check if partition intersects the wall's X range
|
||||
if (localXOnWall + thickness / 2 > 0 && localXOnWall - thickness / 2 < sW) {
|
||||
// Check if it touches Back (min approx 0)
|
||||
// Mapping check:
|
||||
// If p.min (0) is at -Depth/2. And p.max (1) is at +Depth/2.
|
||||
// Wall 1 is at +Depth/2. So Wall 1 contacts p.max.
|
||||
// Wall 2 is at -Depth/2. So Wall 2 contacts p.min.
|
||||
|
||||
// Let's store EXCLUSIONS per contact point.
|
||||
// p.min touches Wall 2. So add to 'exclusionsWall2'.
|
||||
// p.max touches Wall 1. So add to 'exclusionsWall1'.
|
||||
|
||||
// I used names 'exclusionsBack' and 'exclusionsFront'.
|
||||
// Let's adhere to names:
|
||||
// 'Back' typically means +Z (User side) or -Z?
|
||||
// In 3D graphics: Camera at +Z looking -Z.
|
||||
// Objects at +Z are "Front" (Near). Objects at -Z are "Background" (Far).
|
||||
// So Wall 1 (+Z) is Front. Wall 2 (-Z) is Back.
|
||||
|
||||
// 'p.min' (0) -> -Z -> Back/Far Wall (Wall 2).
|
||||
// 'p.max' (1) -> +Z -> Front/Near Wall (Wall 1).
|
||||
|
||||
// So:
|
||||
// p.min contacts Wall 2 (Back).
|
||||
// p.max contacts Wall 1 (Front).
|
||||
|
||||
// Array 'exclusionsBack' should store contacts for Wall 2.
|
||||
// Array 'exclusionsFront' should store contacts for Wall 1.
|
||||
|
||||
if ((p.min ?? 0) < 0.01) {
|
||||
exclusionsBack.push({ start: localXOnWall - thickness / 2, end: localXOnWall + thickness / 2, yMax: hEff });
|
||||
}
|
||||
// Check if it touches Front (max approx 1)
|
||||
if ((p.max ?? 1) > 0.99) {
|
||||
exclusionsFront.push({ start: localXOnWall - thickness / 2, end: localXOnWall + thickness / 2, yMax: hEff });
|
||||
}
|
||||
}
|
||||
|
||||
} else { // p.axis === 'y'
|
||||
// Runs Width-wise (X axis in Layout).
|
||||
// Intersects Left and Right walls (Length-wise plates).
|
||||
|
||||
const partGlobalZ = (-effectiveInnerD / 2) + (effectiveInnerD * p.offset);
|
||||
const sD = depth - 2 * effRadius;
|
||||
const localXOnWall = partGlobalZ + sD / 2;
|
||||
|
||||
// Check if partition intersects the wall's X range (which maps to depth)
|
||||
if (localXOnWall + thickness / 2 > 0 && localXOnWall - thickness / 2 < sD) {
|
||||
// Check if it touches Left (min approx 0)
|
||||
if ((p.min ?? 0) < 0.01) {
|
||||
exclusionsLeft.push({ start: localXOnWall - thickness / 2, end: localXOnWall + thickness / 2, yMax: hEff });
|
||||
}
|
||||
// Check if it touches Right (max approx 1)
|
||||
if ((p.max ?? 1) > 0.99) {
|
||||
exclusionsRight.push({ start: localXOnWall - thickness / 2, end: localXOnWall + thickness / 2, yMax: hEff });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Front/Back
|
||||
if (straightW > 0.1) {
|
||||
const wGeo = createPerforatedPlate(straightW, wallHeight, thickness, perforation);
|
||||
// Plate: 0..W in X, 0..H in Y, 0..Th in Z.
|
||||
// Center Horizontally:
|
||||
wGeo.translate(-straightW / 2, 0, 0);
|
||||
|
||||
// Wall 1 (Back / Top? +Z):
|
||||
// Needs to be at Z = Depth/2.
|
||||
// Plate thickness is along Z (positive).
|
||||
// If we put it at Z = D/2 - thickness, it occupies [D/2 - th, D/2].
|
||||
// Inner face at D/2 - th. Outer face at D/2. Correct.
|
||||
const w1 = wGeo.clone();
|
||||
// Wall 1 (at +Z). This is "Front" (Near). Contacts p.max.
|
||||
// Uses exclusionsFront.
|
||||
const wGeoFront = createPerforatedPlate(straightW, wallHeight, thickness, perforation, 0, 0, exclusionsFront);
|
||||
wGeoFront.translate(-straightW / 2, 0, 0);
|
||||
const w1 = wGeoFront.clone();
|
||||
w1.translate(0, thickness, depth / 2 - thickness);
|
||||
geometries.push(w1);
|
||||
|
||||
// Wall 2 (Front / Bottom? -Z):
|
||||
// Needs to be at Z = -Depth/2.
|
||||
// Occupies [-D/2, -D/2 + th].
|
||||
// RotateY(180)?
|
||||
// Plate (X, Z-thick). Rot180 -> (-X, -Z-thick).
|
||||
// If original in [-W/2, W/2]x[0,th].
|
||||
// Rot180 -> [W/2, -W/2]x[0,-th].
|
||||
// Translate to Z = -(Depth/2 - thickness). -> [-th - (D/2 - th)] = -D/2.
|
||||
// Wait. [-th - D/2 + th] = -D/2. Correct?
|
||||
// Let's just translate manually without rotation for robustness, assuming pattern symmetric or acceptable.
|
||||
// Wall 2 (at -Z). This is "Back" (Far). Contacts p.min.
|
||||
// Uses exclusionsBack.
|
||||
// Needs checking mapping (Rot 180).
|
||||
// p.offset increases X. Wall rotated 180 means X is inverted.
|
||||
// So we map exclusionsBack.
|
||||
const exclusionsBackMapped = exclusionsBack.map(e => ({
|
||||
start: straightW - e.end,
|
||||
end: straightW - e.start,
|
||||
yMax: e.yMax
|
||||
}));
|
||||
|
||||
const w2 = wGeo.clone();
|
||||
// Rotate to face out?
|
||||
const wGeoBack = createPerforatedPlate(straightW, wallHeight, thickness, perforation, 0, 0, exclusionsBackMapped);
|
||||
wGeoBack.translate(-straightW / 2, 0, 0);
|
||||
const w2 = wGeoBack.clone();
|
||||
w2.rotateY(Math.PI);
|
||||
// After RotY(180): Z becomes negative. Range [-th, 0].
|
||||
// We want range [-D/2, -D/2 + th].
|
||||
// So translate Z by -D/2 + th.
|
||||
w2.translate(0, thickness, -(depth / 2 - thickness));
|
||||
geometries.push(w2);
|
||||
}
|
||||
|
||||
// Left/Right
|
||||
if (straightD > 0.1) {
|
||||
const dGeo = createPerforatedPlate(straightD, wallHeight, thickness, perforation);
|
||||
dGeo.translate(-straightD / 2, 0, 0);
|
||||
|
||||
// Wall 3 (Right? +X).
|
||||
// RotateY(-90). X -> Z, Z -> -X.
|
||||
// Plate Z[0, th] -> X[-th, 0].
|
||||
// We want X [W/2 - th, W/2].
|
||||
// So Translate X by W/2.
|
||||
const w3 = dGeo.clone();
|
||||
w3.rotateY(-Math.PI / 2);
|
||||
w3.translate(width / 2, thickness, 0);
|
||||
// Plate is 0..straightD in X, 0..wallHeight in Y. Thickness along Z.
|
||||
// We want it to be at X = width/2.
|
||||
// It needs to be rotated -PI/2 around Y to align its X-axis with World Z-axis.
|
||||
// After rotateY(-PI/2): Plate X (0..straightD) becomes World Z (0..straightD).
|
||||
// Plate Z (thickness) becomes World -X (towards Left).
|
||||
// So if we place it at X=width/2, it extrudes to width/2 - thickness. Correct for Right Wall.
|
||||
const wGeoRight = createPerforatedPlate(straightD, wallHeight, thickness, perforation, 0, 0, exclusionsRight);
|
||||
wGeoRight.translate(-straightD / 2, 0, 0); // Center X of plate
|
||||
const w3 = wGeoRight.clone();
|
||||
w3.rotateY(-Math.PI / 2); // Rotate to align with Z-axis
|
||||
w3.translate(width / 2, thickness, 0); // Position at X=width/2
|
||||
geometries.push(w3);
|
||||
|
||||
// Wall 4 (Left? -X).
|
||||
// RotateY(90). X -> -Z, Z -> X.
|
||||
// Plate Z[0, th] -> X[0, th].
|
||||
// We want X [-W/2, -W/2 + th].
|
||||
// Translate X by -W/2.
|
||||
const w4 = dGeo.clone();
|
||||
// This wall is also rotated PI/2.
|
||||
// Plate Z (thickness) becomes World X (towards Right).
|
||||
// We want it at X=-width/2.
|
||||
// It will extrude to -width/2 + thickness. Correct for Left Wall.
|
||||
const exclusionsLeftMapped = exclusionsLeft.map(e => ({
|
||||
start: straightD - e.end,
|
||||
end: straightD - e.start,
|
||||
yMax: e.yMax
|
||||
}));
|
||||
|
||||
const wGeoLeft = createPerforatedPlate(straightD, wallHeight, thickness, perforation, 0, 0, exclusionsLeftMapped);
|
||||
wGeoLeft.translate(-straightD / 2, 0, 0); // Center X of plate
|
||||
const w4 = wGeoLeft.clone();
|
||||
w4.rotateY(Math.PI / 2);
|
||||
w4.translate(-(width / 2), thickness, 0);
|
||||
w4.translate(-width / 2, thickness, 0); // Position at X=-width/2
|
||||
geometries.push(w4);
|
||||
}
|
||||
}
|
||||
@@ -336,8 +475,52 @@ export const createBinGeometry = (
|
||||
pX = (-innerWidth / 2) + (innerWidth * p.offset);
|
||||
pY = (-innerDepth / 2) + (innerDepth * midRatio); // Center of partition
|
||||
|
||||
// Create Plate (Length, Height)
|
||||
const plate = createPerforatedPlate(pLen, effectiveHeight, thickness, perforation!);
|
||||
// Calculate Exclusions for Internal Partition
|
||||
const partExclusions: { start: number, end: number, yMax?: number }[] = [];
|
||||
// This partition is 'p' (Axis X, runs along Depth).
|
||||
// Intersected by partitions 'n' (Axis Y, runs along Width).
|
||||
// p global Y range: pY - pLen/2 to pY + pLen/2.
|
||||
// n global Y pos: (-innerDepth/2) + (innerDepth * n.offset).
|
||||
|
||||
partitions.forEach(n => {
|
||||
if (n.axis !== 'y') return; // Only orthogonal partitions intersect
|
||||
// Check if n intersects p
|
||||
// Intersection Y location:
|
||||
const nY = (-innerDepth / 2) + (innerDepth * n.offset);
|
||||
|
||||
// Does nY (which is global Y of the intersecting partition) match p's position?
|
||||
// p is Axis X, runs along DEPTH (Global Y).
|
||||
// p is centered at pX (Width) and covers pLen in Depth (Y).
|
||||
// Wait. p (Axis X) runs along Y?
|
||||
// p.axis='x' -> "Runs along Y (Depth)". Correct.
|
||||
// So p covers Y range [pY - pLen/2, pY + pLen/2].
|
||||
// n is Axis Y, runs along X (Width).
|
||||
// n is centered at nY (Depth).
|
||||
// So intersection happens if nY is within p's Y range.
|
||||
|
||||
const pStartGlobal = pY - pLen / 2;
|
||||
const pEndGlobal = pY + pLen / 2;
|
||||
|
||||
// And check if n covers p's X location.
|
||||
// n runs along X from nMin to nMax.
|
||||
const nXStart = (-innerWidth / 2) + (innerWidth * (n.min ?? 0));
|
||||
const nXEnd = (-innerWidth / 2) + (innerWidth * (n.max ?? 1));
|
||||
const pXLoc = pX;
|
||||
|
||||
if (nY >= pStartGlobal && nY <= pEndGlobal && pXLoc >= nXStart && pXLoc <= nXEnd) {
|
||||
// Intersection confirmed.
|
||||
// Calculate local coord on p's plate.
|
||||
// p runs along Y. Plate local X maps to Global Y.
|
||||
// local = global - pY + pLen/2.
|
||||
const nHeight = Math.max(0.1, n.height - thickness);
|
||||
const localX = nY - pY + pLen / 2;
|
||||
partExclusions.push({ start: localX - thickness / 2, end: localX + thickness / 2, yMax: nHeight });
|
||||
}
|
||||
});
|
||||
|
||||
// Add margins (solid ends)
|
||||
const margin = thickness;
|
||||
const plate = createPerforatedPlate(pLen, effectiveHeight, thickness, perforation!, margin, margin, partExclusions);
|
||||
plate.translate(-pLen / 2, 0, 0); // Center X
|
||||
|
||||
// Rotate to align with Depth (along Z)
|
||||
@@ -355,7 +538,33 @@ export const createBinGeometry = (
|
||||
pX = (-innerWidth / 2) + (innerWidth * midRatio);
|
||||
pY = (-innerDepth / 2) + (innerDepth * p.offset);
|
||||
|
||||
const plate = createPerforatedPlate(pLen, effectiveHeight, thickness, perforation!);
|
||||
// Calculate Exclusions
|
||||
const partExclusions: { start: number, end: number, yMax?: number }[] = [];
|
||||
// This partition is 'p' (Axis Y, runs along Width).
|
||||
// Intersected by partitions 'n' (Axis X, runs along Depth).
|
||||
|
||||
partitions.forEach(n => {
|
||||
if (n.axis !== 'x') return;
|
||||
const nX = (-innerWidth / 2) + (innerWidth * n.offset);
|
||||
|
||||
const pStartGlobal = pX - pLen / 2; // X range of p
|
||||
const pEndGlobal = pX + pLen / 2;
|
||||
|
||||
const nYStart = (-innerDepth / 2) + (innerDepth * (n.min ?? 0));
|
||||
const nYEnd = (-innerDepth / 2) + (innerDepth * (n.max ?? 1));
|
||||
const pYLoc = pY;
|
||||
|
||||
if (nX >= pStartGlobal && nX <= pEndGlobal && pYLoc >= nYStart && pYLoc <= nYEnd) {
|
||||
// Intersection confirmed
|
||||
// local = global - pX + pLen/2
|
||||
const nHeight = Math.max(0.1, n.height - thickness); // INTERSECTING PARTITION HEIGHT
|
||||
const localX = nX - pX + pLen / 2;
|
||||
partExclusions.push({ start: localX - thickness / 2, end: localX + thickness / 2, yMax: nHeight });
|
||||
}
|
||||
});
|
||||
|
||||
const margin = thickness;
|
||||
const plate = createPerforatedPlate(pLen, effectiveHeight, thickness, perforation!, margin, margin, partExclusions);
|
||||
plate.translate(-pLen / 2, 0, 0); // Center X
|
||||
|
||||
// Already aligned with X. Thickness along Z.
|
||||
|
||||
Reference in New Issue
Block a user