/// Ported from https://github.com/Zergie/gridfinity-UltraLight, not all features are supported use std::ops::*; use std::geo3d::*; use std::geo2d::*; use std::debug::assert; const MagnetDiameter = 6.15mm; const MagnetDepth = 2.2mm; const WallThickness = 1.0mm; const OffsetXY = 0.25mm; pub const BasicUnitXY = 42.0mm; pub const BasicUnitZ = 7.0mm; const BasicRadius1 = 4.0mm; const BasicRadius2 = 8.0mm; const TopClearanceOffset = 0.6mm; const StackingLipWidth = 2.6mm; const LabelHeight = 1.0mm; const MagnetRadius = 0.5 * MagnetDiameter; /// Like std::geo3d::Cube, but not centered part CornerCube(width: Length, height: Length, depth: Length) { Rect(width, height, x = 0mm, y = 0mm).extrude(z = depth) } part BinClean(gridsX: Scalar, gridsY: Scalar, gridsZ: Scalar, magents: Bool) { baseCleans = BinBaseCleanSingle(startX = [0..gridsX - 1] * BasicUnitXY, startY = [0..gridsY - 1] * BasicUnitXY, magents); xCorners = [BasicRadius1, (gridsX * BasicUnitXY) - BasicRadius1]; yCorners = [BasicRadius1, (gridsY * BasicUnitXY) - BasicRadius1]; radius0 = BasicRadius1 - OffsetXY; height0 = 4.40mm; around = CornerCube(width = gridsX * BasicUnitXY, height = gridsY * BasicUnitXY, depth = gridsZ * BasicUnitZ) - Cylinder(height = gridsZ * BasicUnitZ, radius = radius0, offset = 0mm).translate(x = xCorners, y = yCorners).hull(); bellowHeight = 12.0mm; bellow = CornerCube(width = gridsX * BasicUnitXY, height = gridsY * BasicUnitXY, depth = bellowHeight).translate(z = -bellowHeight); around | baseCleans | bellow } part BinBaseCleanSingle(startX: Length = 0.0mm, startY: Length = 0.0mm, widthX = 1.0, widthY = 1.0, magents: Bool) { radius0 = 1.05mm - OffsetXY; radius1 = 1.85mm - OffsetXY; radius2 = BasicRadius1 - OffsetXY; height0 = 0.80mm; height1 = 1.80mm; height2 = 2.15mm; base = CornerCube(width = widthX * BasicUnitXY, height = widthY * BasicUnitXY, depth = height0 + height1 + height2) .translate(x = startX, y = startY); corners = ( x = [startX + BasicRadius1, startX + (widthX * BasicUnitXY) - BasicRadius1], y = [startY + BasicRadius1, startY + (widthY * BasicUnitXY) - BasicRadius1] ); cutout = HullStack(corners, heights = [height0, height1, height2], radii = [ radius0, radius1, radius1, radius2 ]); if (magents & (widthX == 1.0) & (widthY == 1.0)) { (base - cutout) | MagnetHoles(startX, startY) } else { base - cutout } } part MagnetHoles(startX: Length = 0.0mm, startY: Length = 0.0mm) { xCorners = [startX + BasicRadius2, startX + BasicUnitXY - BasicRadius2]; yCorners = [startY + BasicRadius2, startY + BasicUnitXY - BasicRadius2]; Cylinder(height = MagnetDepth, radius = MagnetRadius, offset = 0mm).translate(x = xCorners, y = yCorners) } part BinBody(gridsX: Scalar, gridsY: Scalar, gridsZ: Scalar, hollow: Bool) { radius0 = BasicRadius1 - OffsetXY; height0 = 4.75mm; height1 = 7.0mm - height0; height2 = (gridsZ - 1) * BasicUnitZ; corners = ( x = [BasicRadius1, gridsX * BasicUnitXY - BasicRadius1], y = [BasicRadius1, gridsY * BasicUnitXY - BasicRadius1] ); base = Cylinder(height = height1 + height2, radius = radius0, offset = 0mm) .translate(x = corners.x, y = corners.y, height0) .hull(); cutout = Cylinder(height = height1 + height2, radius = radius0 - WallThickness, offset = 0mm) .translate(x = corners.x, y = corners.y, height0) .hull(); if hollow { base - cutout } else { base } } part BinBaseSingle(startX: Length = 0.0mm, startY: Length = 0.0mm, widthX = 1.0, widthY = 1.0, magents: Bool, ultraLight: Bool) { radius0 = 1.05mm - OffsetXY; radius1 = 1.85mm - OffsetXY; radius2 = BasicRadius1 - OffsetXY; height0 = 0.80mm; height1 = 1.80mm; height2 = 2.15mm; corners = ( x = [startX + BasicRadius1, startX + widthX * BasicUnitXY - BasicRadius1], y = [startY + BasicRadius1, startY + widthY * BasicUnitXY - BasicRadius1] ); outside = CornerCube(width = widthX * BasicUnitXY, height = widthY * BasicUnitXY, depth = height0 + height1 + height2 + WallThickness) .translate(x = startX, y = startY); ultraLightCutout = HullStack( corners, heights = [ height0 - 0.5858 * WallThickness, height1, height2, 1.4142 * WallThickness ], radii = [ radius0 - 0.4142 * WallThickness, radius1 - WallThickness, radius1 - WallThickness, radius2 - WallThickness, radius2 ], offset = WallThickness ); showMagnets = magents & (widthX == 1.0) & (widthY == 1.0); magnetCutout = MagnetHoles(startX, startY); magnetXCorners = [startX + BasicRadius2, startX + widthX * BasicUnitXY - BasicRadius2]; magnetYCorners = [startY + BasicRadius2, startY + widthY * BasicUnitXY - BasicRadius2]; magnetOutside = Cylinder(height = MagnetDepth + WallThickness, radius = MagnetRadius + WallThickness, offset = 0mm).translate(x = magnetXCorners, y = magnetYCorners) - magnetCutout; if (ultraLight & showMagnets) { (outside - ultraLightCutout - magnetCutout) | magnetOutside; } else if (ultraLight) { outside - ultraLightCutout; } else if (showMagnets) { (outside | magnetOutside) - magnetCutout; } else { outside } } part BinBase(gridsX: Scalar, gridsY: Scalar, gridsZ: Scalar, magents: Bool, ultraLight: Bool) { BinBaseSingle(startX = [0..gridsX - 1] * BasicUnitXY, startY = [0..gridsY - 1] * BasicUnitXY, magents, ultraLight); } part BinStacklip(gridsX: Scalar, gridsY: Scalar, gridsZ: Scalar) { radius0 = 1.15mm; radius1 = 1.85mm; radius2 = BasicRadius1 - OffsetXY; height0 = StackingLipWidth - WallThickness; height1 = 0.60mm; height2 = 0.70mm; height3 = 1.80mm; height4 = 1.90mm; height5 = 0.75mm; heightStart = (gridsZ * BasicUnitZ) - (height0 + height1); xCorners = [BasicRadius1, gridsX * BasicUnitXY - BasicRadius1]; yCorners = [BasicRadius1, gridsY * BasicUnitXY - BasicRadius1]; outer = Cylinder(height = height0 + height1 + height2 + height3 + height4 + height5, radius = radius2, offset = 0mm).translate(x = xCorners, y = yCorners, z = heightStart).hull(); cutouts = HullStack((x = xCorners, y= yCorners), heights = [height0, height1, height2, height3, height4, height5], radii = [ radius2 - WallThickness, radius0, radius0, radius1, radius1, radius2, radius2 ], offset = heightStart); outer - cutouts } part HullStack(corners: (x: [Length], y: [Length]), heights: [Length], radii: [Length], offset: Length = 0mm) { assert(heights.count() == radii.count() - 1, "radii must be an array with one more elements that heights"); self = Cylinder(height = heights.head(), radius_bottom = radii.head(), radius_top = radii.tail().head(), offset) .translate(x = corners.x, y = corners.y).hull(); if heights.count() > 1 { self | HullStack(corners, heights = heights.tail(), radii = radii.tail(), offset = offset + heights.head()) } else { self } } // A basic bin pub part Bin(gridsX = 1, gridsY = 1, gridsZ = 1, magents: Bool = false, ultraLight: Bool = false, center: Bool = true) { bin = BinBody(gridsX, gridsY, gridsZ, hollow = true) | BinBase(gridsX, gridsY, gridsZ, magents, ultraLight) | BinStacklip(gridsX, gridsY, gridsZ) - BinClean(gridsX, gridsY, gridsZ, magents); if center { bin.translate(x = -gridsX * BasicUnitXY / 2, y = -gridsY * BasicUnitXY / 2) } else { bin } } part Box_(gridsX = 1, gridsY = 1, gridsZ = 1, magents: Bool = false, lip: Bool = true, center: Bool = true) { if lip { BinBody(gridsX, gridsY, gridsZ, hollow = false) | BinBase(gridsX, gridsY, gridsZ, magents, ultraLight = false) | BinStacklip(gridsX, gridsY, gridsZ) - BinClean(gridsX, gridsY, gridsZ, magents) } else { BinBody(gridsX, gridsY, gridsZ, hollow = false) | BinBase(gridsX, gridsY, gridsZ, magents, ultraLight = false) - BinClean(gridsX, gridsY, gridsZ, magents) } } /// A solid box, intended as the base for custom cutouts pub part Box(gridsX = 1, gridsY = 1, gridsZ = 1, magents: Bool = false, lip: Bool = true, center: Bool = true) { box = Box_(gridsX, gridsY, gridsZ, magents, lip, center); if center { box.translate(x = -gridsX * BasicUnitXY / 2, y = -gridsY * BasicUnitXY / 2) } else { box } } Box(gridsX = 2)