Skip to content

Instantly share code, notes, and snippets.

@spydmobile
Created August 6, 2023 22:27
Show Gist options
  • Save spydmobile/64caa99f82cc7d4358ac681f2013dd39 to your computer and use it in GitHub Desktop.
Save spydmobile/64caa99f82cc7d4358ac681f2013dd39 to your computer and use it in GitHub Desktop.
let requestedWidth = Slider("Width", 100, 10, 300, true, 1, 0)
let requestedDepth = Slider("Depth", 50, 5, 300, true, 1, 0)
let requestedHeight = Slider("Height", 20, 11, 100, true, 1, 0)
let rows = Slider("Rows", 2, 1, 20, true, 1, 0)
let columns = Slider("Columns", 5, 1, 20, true, 1, 0)
let outsideRadius = Slider("Radius", 10, 2, 40, true, 1, 0)
let latches = Slider("Latches", 1, 1, 3, true, 1, 0)
let hingeStyle = Dropdown("Hinge type", "pin", {Pin: "pin", Detent: "cone"}, true)
let latchStyle = Dropdown("Latch type", "pin", {Pin: "pin", Detent: "cone"}, true)
let leftHanded = Checkbox("Left handed?", true)
let lidAngle = Slider("Lid open angle", 0, 0, 90, true, 1, 0)
let showLid = Checkbox("Show lid?", true)
let showBase = Checkbox("Show base?", true)
let showLabels = Checkbox("Show labels?", false)
let insideLabels = TextInput("Inside labels", "")
let outsideLabel = TextInput("Outside label", "")
let multiMaterial = Checkbox("Multimaterial?", false)
let printOrientation = Checkbox("Print orientation?", false)
const coneHinge = hingeStyle === 'cone'
const coneLatch = latchStyle === 'cone'
insideLabels = insideLabels.trim().split(/,/).map(label => label.trim())
const dividerThick = 1.4
const wallThick = 2.5
const floorThick = 2.5
const lidThick = floorThick
const lidClearance = 0.2
const lipHeight = 3
const hingeSupportWidth = 7
const hingeRadius = 3
const hingeOffset = 1
const hingeClearance = 0.3
const totalHingeWidth = hingeSupportWidth * 4;
const hingeConeDepth = 1.2
const lidHingeWidth = hingeSupportWidth * 2 - hingeClearance * 2
const claspDepth = 6
const claspHeight = 4
const claspWidth = 26
const claspRadius = 2
const claspConeDepth = 0.8
const coneClaspClearance = 0.2
const coneClaspWidth = (claspWidth - coneClaspClearance) / 2
const claspOffset = 0.5
// horizontal hole sizes
const holeTight = 1.96
const holeLoose = 2
// vertical hole sizes
const holeLooseVertical = 2.05
const minWidth = Math.max(latches * claspWidth, totalHingeWidth, columns * 8) + 0.5 + outsideRadius * 2;
const boxWidth = Math.max(requestedWidth, minWidth)
const boxDepth = Math.max(requestedDepth, wallThick * 2 + Math.max(outsideRadius * 2, rows * 8))
const boxHeight = Math.max(requestedHeight, coneLatch ? 11 : 14)
const hinges = boxWidth < outsideRadius * 2 + totalHingeWidth * 2 + 1 ? 1 : 2
const sectionWidth = (boxWidth - wallThick * 2 - (columns - 1) * dividerThick) / columns
const sectionDepth = (boxDepth - wallThick * 2 - (rows - 1) * dividerThick) / rows
const sectionHeight = boxHeight - floorThick - lidThick - lidClearance
const claspBumpHeight = 0.8
const claspBumpWidth = claspBumpHeight * 2.5
const claspCenter = boxWidth / 2
const claspTop = boxHeight - lipHeight
const claspPositions = {
center: claspCenter - claspWidth / 2,
left: outsideRadius,
right: boxWidth - outsideRadius - claspWidth,
leftThird: boxWidth * 0.33 - claspWidth / 2,
rightThird: boxWidth * 0.66 - claspWidth / 2,
}
const claspConfigurations = {
1: [claspPositions.center],
2: [claspPositions.left, claspPositions.right],
3: [claspPositions.left, claspPositions.center, claspPositions.right]
}
const currentClaspConfig = claspConfigurations[latches]
const hingeConfigurations = {
1: [boxWidth / 2 - totalHingeWidth / 2],
2: [outsideRadius, boxWidth - outsideRadius - totalHingeWidth]
}
const currentHingeConfig = hingeConfigurations[hinges]
const lidLipThick = wallThick / 2 - lidClearance
const lidZ = boxHeight - lipHeight + lidClearance
const lidHeight = lidThick + lipHeight
const boxTop = lidZ + lidHeight
const lidText = []
const claspsToMirror = []
// reverse last latch
if (latches > 1) {
claspsToMirror.push(latches - 1)
}
// reverse center or only latch
if (latches != 2 && !leftHanded) {
claspsToMirror.push(Math.floor(latches / 2))
}
class ChainShape {
reference
constructor(reference) {
this.reference = reference
}
static dereference(shapes) {
return shapes.map(o => {
return o instanceof ChainShape ? o.reference : o
})
}
clone(keepOriginal, callback) {
const reference = callback()
if (keepOriginal) {
return new ChainShape(reference)
}
this.reference = reference
return this
}
translate(offset, keepOriginal = false) {
return this.clone(keepOriginal, () => {
return Translate(offset, this.reference, keepOriginal)
})
}
rotate(axis, degrees, keepOriginal = false) {
return this.clone(keepOriginal, () => {
return Rotate(axis, degrees, this.reference, keepOriginal)
})
}
rotateAbout(absPosition, axis, degrees, keepOriginal = false) {
return this.clone(keepOriginal, () => {
return rotateAround(absPosition, axis, degrees, this.reference, keepOriginal)
})
}
mirror(absPosition, axes, keepOriginal = false) {
return this.clone(keepOriginal, () => {
const [x, y, z] = absPosition
return Translate(absPosition, Mirror(axes, Translate([-x, -y, -z], this.reference, keepOriginal)))
})
}
chamfer(distance, edgeList, keepOriginal = false) {
return this.clone(keepOriginal, () => {
return ChamferEdges(this.reference, distance, edgeList, keepOriginal)
})
}
fillet(radius, edgeList, keepOriginal = false) {
return this.clone(keepOriginal, () => {
return FilletEdges(this.reference, radius, edgeList, keepOriginal)
})
}
difference(objectsToSubtract, keepObjects = false, fuzzValue = null, keepEdges = true) {
this.reference = Difference(this.reference, this.constructor.dereference(objectsToSubtract), keepObjects, fuzzValue, keepEdges)
return this
}
union(objectsToJoin, keepObjects = false, fuzzValue = null, keepEdges = false) {
return this.clone(keepObjects, () => {
return Union([this.reference, ...(this.constructor.dereference(objectsToJoin))], keepObjects, fuzzValue, keepEdges)
})
}
intersect(objectsToIntersect, keepObjects = false, fuzzValue = null, keepEdges = false) {
return this.clone(keepObjects, () => {
return Intersection([this.reference, ...(this.constructor.dereference(objectsToIntersect))], keepObjects, fuzzValue, keepEdges)
})
}
unevenChamfer(dist1, dist2, edgeList, face, keepOriginal = false) {
return this.clone(keepOriginal, () => {
return UnevenChamferEdges(this.reference, dist1, dist2, edgeList, face, keepOriginal)
})
}
extrude(direction, keepFace = false) {
return this.clone(keepFace, () => {
return Extrude(this.reference, direction, keepFace)
})
}
copy() {
return this.translate([0, 0, 0], true)
}
}
function UnevenChamferEdges(shape, dist1, dist2, edgeList, face, keepOriginal) {
let curChamfer = CacheOp(arguments, () => {
let mkChamfer = new oc.BRepFilletAPI_MakeChamfer(shape)
let foundEdges = 0
ForEachEdge(shape, (index, edge) => {
if (edgeList.includes(index)) {
mkChamfer.Add(dist1, dist2, edge, face)
foundEdges++
}
})
if (foundEdges == 0) {
console.error("Chamfer Edges Not Found! Make sure you are looking at the object _before_ the Chamfer is applied!")
return new oc.TopoDS_Solid(shape)
}
return new oc.TopoDS_Solid(mkChamfer.Shape())
})
sceneShapes.push(curChamfer)
if (!keepOriginal) { sceneShapes = Remove(sceneShapes, shape) }
return curChamfer
}
function hinge(r, holeDiameter, angle, vOffset, hOffset, connectionHeight, t) {
let a = Math.PI * angle * 0.5
hOffset = hOffset || 0
vOffset = vOffset || 0
let p0 = [0, -r]
let p1 = [-r, 0]
let p2 = [r * Math.sin(a), r * Math.cos(a)]
let oppositeHeight = Math.tan(Math.PI * 0.5 - a) * (p2[1] + r + hOffset)
let p3 = [oppositeHeight + p2[0], p0[1] - hOffset]
let p4 = [p0[0] + vOffset, p3[1]]
let sketch = new Sketch(p0)
.ArcTo(p1, p2)
.LineTo(p3)
.LineTo(p4)
.LineTo(p0)
.End(true)
let extruded = Extrude(sketch.Face(true), [0, 0, t], false)
if (connectionHeight) {
const cutterHeight = (p3[0] - p0[0]) - connectionHeight
let cutter = Box(cutterHeight, r * 2 + hOffset, t)
cutter = Translate([vOffset + connectionHeight, -hOffset - r, 0], cutter)
extruded = Difference(extruded, [cutter], false)
}
if (holeDiameter) {
const hole = Rotate([0, 1, 0], -90, smallHole(holeDiameter, t))
extruded = Difference(extruded, [hole])
}
return extruded
}
function rotateAround(coords, axes, degrees, object, keepObjects = false) {
const [x, y, z] = coords
return Translate(coords, Rotate(axes, degrees, Translate([-x, -y, -z], object, keepObjects)))
}
function smallHole(diameter, length) {
const r = diameter / 2
const a = Math.PI * 0.3
let p0 = [r * Math.sin(-a), r * Math.cos(-a)]
let p2 = [r * Math.sin(a), r * Math.cos(a)]
let s = new Sketch(p0)
.ArcTo([0, -r], p2)
.LineTo([r * 0.5, r])
.LineTo([-r * 0.5, r])
.End(true)
.Face()
return Rotate([0, 0, 1], 90,
Rotate([1, 0, 0], 90,
Extrude(s, [0, 0, length])
)
)
}
function halfSphere(radius) {
const quarterCircle = new Sketch([0, 0])
.LineTo([0, radius])
.ArcTo([radius * Math.sin(0.2), radius * Math.cos(0.2)], [radius, 0])
.LineTo([0, 0])
.End()
.Face(true)
return new ChainShape(Revolve(quarterCircle, 360, [1, 0, 0], false))
.rotate([0, 1, 0], 180)
}
if (showBase) {
const base = new ChainShape(Box(boxWidth, boxDepth, boxHeight - lipHeight))
.fillet(outsideRadius, [0, 2, 4, 6])
.chamfer(1, [3])
const lipRadius = outsideRadius - wallThick / 2
const baseInteriorRadius = outsideRadius - wallThick
const baseLip = new ChainShape(Box(boxWidth - wallThick, boxDepth - wallThick, boxHeight))
.fillet(Math.max(0.1, lipRadius), [0, 2, 4, 6])
.translate([wallThick / 2, wallThick / 2, 0])
base.union([baseLip])
const interior = new ChainShape(Box(boxWidth - wallThick * 2, boxDepth - wallThick * 2, boxHeight - floorThick))
.translate([wallThick, wallThick, floorThick])
.fillet(Math.max(baseInteriorRadius, 0.1), [0, 2, 4, 6])
.fillet(1, [3])
base.difference([interior])
.chamfer(0.5, [48])
const hDividers = [...Array(columns - 1)].map((_n, i) => {
return Translate([wallThick + (i + 1) * sectionWidth + i * dividerThick, wallThick, floorThick], Box(dividerThick, boxDepth - wallThick * 2, boxHeight - floorThick))
})
const vDividers = [...Array(rows - 1)].map((_n, i) => {
return Translate([wallThick, wallThick + (i + 1) * sectionDepth + i * dividerThick, floorThick], Box(boxWidth - wallThick * 2, dividerThick, boxHeight - floorThick))
})
if (columns > 1 || rows > 1) {
const dividers = new ChainShape(Union([...hDividers, ...vDividers]))
dividers.intersect([interior])
base.union([dividers])
}
const holeSize = coneHinge ? 0 : holeTight
const hingeY = boxDepth + hingeRadius + hingeOffset
const hingeZ = boxHeight - lipHeight
const chamferEdge = coneHinge ? 5 : 8
const leftHinge = new ChainShape(hinge(hingeRadius, holeSize, 0.6, 0, hingeOffset, null, hingeSupportWidth))
.rotate([0, 1, 0], 90)
.translate([currentHingeConfig[0], hingeY, hingeZ])
.chamfer(0.8, [chamferEdge])
if (coneHinge) {
const leftCone = new ChainShape(Cone(hingeRadius - 0.5, 0.8, hingeConeDepth))
.chamfer(0.5, [0])
.rotate([0, 1, 0], -90)
.translate([currentHingeConfig[0] + hingeSupportWidth + hingeClearance/2, hingeY, hingeZ])
leftHinge.difference([leftCone])
}
const rightHinge = leftHinge.mirror([currentHingeConfig[0] + totalHingeWidth/2, 0, 0], [1, 0, 0], true)
const hingeParts = [leftHinge, rightHinge]
currentHingeConfig.slice(1).forEach(xPos => {
const xTranslation = boxWidth - outsideRadius - totalHingeWidth - currentHingeConfig[0]
const part1 = leftHinge.translate([xTranslation, 0, 0], true)
const part2 = rightHinge.translate([xTranslation, 0, 0], true)
hingeParts.push(part1, part2)
})
let baseClasp
const baseClaspX = currentClaspConfig[0]
if (coneLatch) {
baseClasp = new ChainShape(hinge(claspRadius, 0, 0.65, lidClearance, claspOffset, 0, coneClaspWidth))
.rotate([0, 1, 0], 90)
.rotate([0, 0, 1], 180)
.translate([baseClaspX + coneClaspWidth, -claspRadius - claspOffset, claspTop])
// const outsideBump = new ChainShape(Sphere(hingeRadius))
// .translate([baseClaspX + lidHingeWidth * 2 + hingeClearance, -hingeRadius - claspOffset, claspTop])
const claspDepression = new ChainShape(Cone(claspRadius - 0.5, 0.5, claspConeDepth))
.rotate([0, 1, 0], -90)
.fillet(0.5, [0])
.translate([baseClaspX + coneClaspWidth + 0.01, -claspRadius - claspOffset, claspTop])
const sphere = halfSphere(claspRadius)
.translate([baseClaspX, -claspRadius - claspOffset, claspTop])
baseClasp.difference([claspDepression]).union([sphere])
} else {
baseClasp = new ChainShape(Box(26, claspDepth, claspHeight))
.translate([currentClaspConfig[0], -claspDepth, claspTop - claspHeight])
// const claspBump = new ChainShape(Box(claspWidth, claspBumpWidth, claspBumpHeight))
// .translate([claspCenter - claspWidth/2, -claspDepth + 1, claspTop - claspHeight - claspBumpHeight])
// .unevenChamfer(claspBumpHeight - 0.01, claspBumpWidth * 0.5 - 0.15, [8, 10], 4)
// baseClasp.union([claspBump])
const claspFace = new Sketch([0, 0])
.LineTo([claspDepth, 0])
.LineTo([0, 6])
.LineTo([0, 0])
.End(true)
.Face(false)
const claspSupport = new ChainShape(claspFace)
.extrude([0, 0, 5])
.rotate([1, 0, 0], -90)
.rotate([0, 0, 1], -90)
.translate([currentClaspConfig[0], 0, claspTop - claspHeight])
const claspSupport2 = claspSupport.translate([claspWidth - 5, 0, 0], true)
baseClasp.union([claspSupport, claspSupport2])
.chamfer(0.5, [5])
.fillet(1, [1, 6])
.chamfer(1, [3, 7])
}
const clasps = [baseClasp]
const additionalClasps = currentClaspConfig.slice(1).map(xPos => {
return baseClasp.translate([xPos - currentClaspConfig[0], 0, 0], true)
})
clasps.push(...additionalClasps)
if (coneLatch) {
claspsToMirror.forEach(i => {
clasps[i].mirror([currentClaspConfig[i] + claspWidth / 2, 0, 0], [1, 0, 0])
})
}
base.union([...hingeParts, ...clasps])
if (printOrientation) {
base.rotate([1, 0, 0], 90)
}
}
if (showLid) {
const interiorRadius = outsideRadius - lidLipThick
const lid = new ChainShape(Box(boxWidth, boxDepth, lidHeight))
.translate([0, 0, lidZ])
.fillet(outsideRadius, [0, 2, 4, 6])
const lidInterior = new ChainShape(Box(boxWidth - lidLipThick * 2, boxDepth - lidLipThick * 2, lipHeight))
.translate([lidLipThick, lidLipThick, lidZ])
.fillet(Math.max(0.1, interiorRadius), [0, 2, 4, 6])
lid.difference([lidInterior])
const lidHingeX = currentHingeConfig[0] + totalHingeWidth - hingeSupportWidth - hingeClearance
const lidHingeY = boxDepth + hingeOffset + hingeRadius
const lidHingeZ = boxHeight - lipHeight
const holeSize = coneHinge ? 0 : holeLoose
const lidHinge = new ChainShape(hinge(hingeRadius, holeSize, 0.65, lidClearance, hingeOffset + 1, lidHeight, lidHingeWidth))
.rotate([0, 1, 0], -90)
.translate([lidHingeX, lidHingeY, lidHingeZ])
if (coneHinge) {
const leftCone = new ChainShape(Cone(hingeRadius - 0.5, 1, hingeConeDepth))
.rotate([0, 1, 0], 90)
.translate([lidHingeX, lidHingeY, lidHingeZ])
.fillet(0.99, [0])
const rightCone = leftCone.rotateAbout([lidHingeX - lidHingeWidth / 2, 0, lidHingeZ], [0, 1, 0], 180, true)
lidHinge.union([leftCone, rightCone])
}
const lidHinges = [lidHinge]
currentHingeConfig.slice(1).forEach(xPos => {
const hinge = lidHinge.translate([xPos - currentHingeConfig[0], 0, 0], true)
lidHinges.push(hinge)
})
let lidClasp
const lidClaspX = currentClaspConfig[0]
const lidClaspZ = boxHeight - lipHeight + lidClearance
if (coneLatch) {
lidClasp = new ChainShape(hinge(claspRadius, 0, 0.65, lidClearance, claspOffset, lidHeight, coneClaspWidth))
.rotate([0, 1, 0], -90)
.rotate([0, 0, 1], 180)
.translate([lidClaspX + coneClaspWidth + coneClaspClearance, -claspRadius - claspOffset, lidClaspZ - lidClearance])
const sphere = halfSphere(claspRadius)
.rotate([0, 0, 1], 180)
.translate([lidClaspX + coneClaspWidth * 2 + coneClaspClearance, -claspRadius - claspOffset, lidClaspZ - lidClearance])
const claspCatch = new ChainShape(Cone(claspRadius - 0.5, 0.5, claspConeDepth))
.rotate([0, 1, 0], -90)
.fillet(0.5, [0])
.translate([lidClaspX + coneClaspWidth + coneClaspClearance + 0.005, -claspRadius - claspOffset, lidClaspZ - lidClearance])
lidClasp
.union([sphere])
.union([claspCatch])
} else {
lidClasp = new ChainShape(Box(5, claspDepth + 1 , lidHeight))
.translate([lidClaspX, - claspDepth, boxHeight - lipHeight + lidClearance])
const lidClaspHole = new ChainShape(smallHole(holeTight, claspWidth))
.rotate([1, 0, 0], 180)
.translate([lidClaspX, -claspDepth / 2, boxHeight - lipHeight + lidClearance + lidHeight / 2])
lidClasp.difference([lidClaspHole])
const lidClasp2 = lidClasp.translate([claspWidth - 5, 0, 0], true)
lidClasp.chamfer(1, [0, 10])
lidClasp2.chamfer(1, [9, 10])
lidClasp.union([lidClasp2])
}
const allClasps = [lidClasp]
const additionalClasps = currentClaspConfig.slice(1).map(xPos => {
return lidClasp.translate([xPos - currentClaspConfig[0], 0, 0], true)
})
allClasps.push(...additionalClasps)
if (coneLatch) {
claspsToMirror.forEach(i => {
allClasps[i].mirror([currentClaspConfig[i] + claspWidth / 2, 0, 0], [1, 0, 0])
})
}
lid.chamfer(1, [0])
lid.union([lidClasp, ...additionalClasps, ...lidHinges])
if (showLabels) {
const fontHeight = 7
const fontSize = fontHeight * 1.2
const fontThickness = 0.6
if (insideLabels.some(Boolean)) {
const labelFaces = insideLabels.slice(0, rows * columns).map((label, i) => {
const xPos = i % columns
const yPos = Math.floor(i / columns)
const roughWidth = label.length * fontSize * 0.7
return new ChainShape(Text3D(label, fontSize, 0))
.translate([
wallThick + (dividerThick + sectionWidth) * xPos + sectionWidth / 2 - roughWidth / 2,
wallThick + (sectionDepth + dividerThick) * yPos + fontHeight + sectionDepth / 2 - fontHeight / 2,
0
])
.reference
})
const combinedLabelFaces = new ChainShape(Union(labelFaces))
const embossedLabels = combinedLabelFaces.extrude([0, 0, fontThickness * 2], multiMaterial)
.translate([0, 0, boxTop - lidThick - fontThickness])
if (multiMaterial) {
lid.difference([embossedLabels])
lidText.push(
combinedLabelFaces.extrude([0, 0, fontThickness])
.translate([0, 0, boxTop - lidThick])
)
} else {
lid.union([embossedLabels])
}
}
if (outsideLabel) {
const labelOffset = 0.293 * (outsideRadius - wallThick) + 4
const topFontSize = Math.min(14, (boxDepth - labelOffset * 2) * 0.8 - 2)
const engraveExtrude = 2 / topFontSize
const label = new ChainShape(Text3D(outsideLabel, topFontSize, engraveExtrude))
.rotate([1, 0, 0], -90)
.translate([
labelOffset,
labelOffset + 2,
boxTop + 1.4
])
lid.difference([label])
if (multiMaterial) {
lidText.push(new ChainShape(Text3D(outsideLabel, topFontSize, 0.6 / topFontSize))
.rotate([1, 0, 0], -90)
.translate([
labelOffset,
labelOffset + 2,
boxTop
]))
}
}
}
const handleDepth = claspDepth + 2.5
const handleHeight = claspHeight * 2 + 5
const handleClearance = 0.4
const handleLipHeight = 3
let handleWidth = claspWidth - 10 - handleClearance * 2
const handleX = currentClaspConfig[0] + 5 + handleClearance
const bumpCatchClearance = 0.3
const handles = []
if (!coneLatch) {
const handle = new ChainShape(Box(handleWidth, handleDepth, handleHeight))
.translate([handleX, -handleDepth - 0.4, boxTop - handleHeight])
const handleSubtract = new ChainShape(Box(handleWidth, claspDepth, claspHeight + 0.9))
.translate([handleX, -claspDepth - 0.4, boxHeight - lipHeight - claspHeight - 0.2])
.chamfer(1, [8, 9])
handle.difference([handleSubtract])
.fillet(1.7, [10, 14])
.fillet(3, [13])
const handleLip = new ChainShape(Box(handleWidth, 2.5, handleLipHeight))
.rotateAbout([0, 2.5, handleLipHeight], [1, 0, 0], -12)
.translate([handleX, -handleDepth - 0.4, boxTop - handleHeight - handleLipHeight + 0.5])
.fillet(2, [3, 7])
const bumpCatch = new ChainShape(Box(claspWidth, claspBumpWidth + bumpCatchClearance, claspBumpHeight + bumpCatchClearance))
.translate([currentClaspConfig[0], -claspDepth + 1 - bumpCatchClearance * 0.5, claspTop - claspHeight - claspBumpHeight - bumpCatchClearance])
.unevenChamfer(claspBumpHeight - 0.01, claspBumpWidth * 0.5 - 0.15, [8, 10], 4)
handle.difference([bumpCatch])
.fillet(1.3, [42, 45])
const handleClaspHole = new ChainShape(Cylinder(holeLooseVertical / 2, claspWidth))
.rotate([0, 1, 0], 90)
.translate([handleX, -claspDepth / 2, boxHeight - lipHeight + lidClearance + lidHeight / 2])
handle.difference([handleClaspHole])
.union([handleLip])
const extraHandles = currentClaspConfig.slice(1).map(xPos => {
return handle.translate([xPos - currentClaspConfig[0], 0, 0], true)
})
handles.push(handle, ...extraHandles)
}
if (lidAngle && !printOrientation) {
[lid, ...handles, ...lidText].forEach(el => {
el.rotateAbout([0, boxDepth + hingeOffset + hingeRadius, boxHeight - lipHeight], [1, 0, 0], -lidAngle)
})
}
if (printOrientation) {
[lid, ...lidText].forEach(el => {
el.rotateAbout([0, 0, lidZ], [1, 0, 0], -90)
.translate([20, -lidHeight, -20])
.rotate([0, 1, 0], 180)
})
handles.forEach((h, i) => {
h.translate([-currentClaspConfig[i] - 5 - handleClearance, claspDepth, -boxTop])
.rotate([0, 0, 1], -90)
.rotate([0, 1, 0], 180)
.translate([-claspDepth - 5, 0, 20 * i])
})
}
}
if (!showLid && !showBase) {
Text3D("Nothing here", 10, 0.1)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment