feat/blind-cap #1
|
|
@ -4,6 +4,8 @@ A collection of parametric OpenSCAD models for 3D printing.
|
|||
|
||||
| Preview | Name | Description |
|
||||
|---------|------|-------------|
|
||||
| <img src="blind-cap/preview.png" width="200"> | [Blind Cap](blind-cap/) | A blank cover plate for a flush-mounted electrical wall box, with internal screw bosses on the vertical centerline. |
|
||||
| <img src="filament-spool-cover/preview.png" width="200"> | [Filament Spool Cover](filament-spool-cover/) | A circular dust cover that clips onto the outer rim of a filament spool. |
|
||||
| <img src="gridfinity-bin-label/preview.png" width="200"> | [Gridfinity Bin Label](gridfinity-bin-label/) | A swappable Cullenect-style bin label with two text slots and two screw-head icon slots. |
|
||||
| <img src="shower-phone-holder/preview.png" width="200"> | [Shower Phone Holder](shower-phone-holder/) | Hangs from an aluminum shower rail via two hooks at the top, with a pocket/tray at the bottom to hold a phone. |
|
||||
| <img src="simple-hook/preview.png" width="200"> | [Parametrizable Wall Hook](simple-hook/) | A simple wall hook with a rectangular base plate and a cylindrical peg extending outward. |
|
||||
|
|
|
|||
61
blind-cap/README.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Blind Cap
|
||||
|
||||

|
||||
|
||||
A blank cover plate (tapa ciega) for a flush-mounted electrical wall box. Square plate with rounded corners, a hollow back cavity, and two internal screw bosses on the vertical centerline. Designed for 3D printing — the front face sits on the build plate so the cavity opens upward and prints without supports.
|
||||
|
||||
## Parameters
|
||||
|
||||
### Customizable Parameters
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `outer_size` | 85 mm | Outer width and height of the cap (square) |
|
||||
| `corner_radius` | 5 mm | Radius of the rounded outer corners |
|
||||
| `total_depth` | 10 mm | Total depth of the cap (front face to back rim) |
|
||||
| `front_thickness` | 2.5 mm | Thickness of the front face |
|
||||
| `wall_thickness` | 2 mm | Thickness of the side walls |
|
||||
| `screw_hole_spacing` | 60 mm | Center-to-center distance between the two screw holes |
|
||||
| `screw_hole_diameter` | 3.5 mm | Through-hole diameter for the screw shank |
|
||||
| `screw_countersink_diameter` | 7 mm | Countersink diameter on the front face |
|
||||
| `screw_countersink_depth` | 1.2 mm | Countersink depth on the front face |
|
||||
| `boss_diameter` | 9 mm | Diameter of the internal screw bosses |
|
||||
| `front_edge_round` | 0.8 mm | Slight rounding applied to the visible front edge |
|
||||
| `back_edge_round` | 1 mm | Slight rounding applied to the rear outer edge |
|
||||
|
||||
### Keystone Jack Cradle
|
||||
|
||||
Optional internal cradle that snap-locks a standard keystone module (RJ45, HDMI, USB, etc.) centered in the front face. Every dimension is configurable, so the cradle can be tuned to whatever keystone you have on hand.
|
||||
|
||||
How it works:
|
||||
|
||||
- A separate front-face cutout (sized to the *visible* portion of the keystone face) frames the module from outside the cap.
|
||||
- A larger cradle slot behind the cutout captures the keystone body. The cap's front face material around the smaller cutout stops the face flange and hides any gap.
|
||||
- A latch-catch shelf protrudes inward from one long-axis wall at the back of the cradle. The cantilever latch hook compresses past this shelf during insertion, then springs out behind it and locks the keystone in place. (The shelf and slot proportions follow WALLY's `keystone_solid` receiver from thenewhobbyist/OpenSCAD.)
|
||||
- The cradle protrudes from the back of the front face into the cap's cavity and on into the wall box behind it. The external front face of the cap is unchanged.
|
||||
|
||||
To install: push the keystone face-first into the cavity-side opening of the slot until the face flange seats against the back of the front face.
|
||||
|
||||
If your keystone doesn't fit, increase `keystone_slot_width` / `keystone_slot_length` / `keystone_clearance`. If the latch ends up on the wrong side, flip `keystone_latch_side`. If the latch doesn't lock, increase `keystone_latch_shelf_protrusion` (or its thickness).
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `keystone_enabled` | `true` | Add the keystone cradle behind the front-face cutout |
|
||||
| `keystone_face_width` | 14.5 mm | Front-face cutout width (visible face — short axis) |
|
||||
| `keystone_face_length` | 16.0 mm | Front-face cutout length (visible face — long latch-fulcrum axis) |
|
||||
| `keystone_face_offset_y` | 2.5 mm | Offset of the front-face cutout along Y, away from the latch shelf, so the cradle keeps material above the cutout for the latch to flex into |
|
||||
| `keystone_slot_width` | 15.6 mm | Cradle slot width (body cross-section, with hooks) |
|
||||
| `keystone_slot_length` | 23.5 mm | Cradle slot length (body cross-section, with hooks) |
|
||||
| `keystone_cradle_depth` | 10 mm | How far the cradle extends behind the front face |
|
||||
| `keystone_latch_shelf_protrusion` | 1.5 mm | How far the latch shelf protrudes into the slot |
|
||||
| `keystone_latch_shelf_thickness` | 3 mm | Thickness of the latch shelf in z |
|
||||
| `keystone_latch_side` | -1 | Which long-axis end has the shelf (-1 = -Y, 1 = +Y) |
|
||||
| `keystone_rotation` | 0 | Rotation of the keystone about the cap's Z axis, in 90° steps (0/90/180/270) |
|
||||
| `keystone_position_x` | 0 mm | Translate the keystone along X relative to the cap centre |
|
||||
| `keystone_position_y` | 0 mm | Translate the keystone along Y relative to the cap centre |
|
||||
| `keystone_clearance` | 0.2 mm | Print-tolerance clearance on each side of every cutout |
|
||||
| `keystone_cradle_wall` | 1.6 mm | Wall thickness around the slot |
|
||||
|
||||
### Defaults
|
||||
|
||||
The default values target a common 85×85 mm Spanish flush-box cover with a 60 mm vertical screw spacing. Adjust `outer_size` and `screw_hole_spacing` to match your specific wall box.
|
||||
360
blind-cap/cap.scad
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
// ============================================
|
||||
// Blind Cap (Tapa Ciega)
|
||||
// ============================================
|
||||
// A blank cover plate for a flush-mounted electrical wall box.
|
||||
// Square plate with rounded corners, hollow back, and two
|
||||
// internal screw bosses on the vertical centerline.
|
||||
|
||||
// ============================================
|
||||
// CUSTOMIZABLE PARAMETERS
|
||||
// ============================================
|
||||
|
||||
// Outer width and height of the cap (square)
|
||||
outer_size = 80; // [50:1:120]
|
||||
|
||||
// Radius of the rounded outer corners
|
||||
corner_radius = 5; // [1:0.5:15]
|
||||
|
||||
// Total depth of the cap (front face to back rim)
|
||||
total_depth = 3; // [5:0.5:20]
|
||||
|
||||
// Thickness of the front face
|
||||
front_thickness = 2; // [1:0.1:5]
|
||||
|
||||
// Thickness of the side walls (the rim around the cavity)
|
||||
wall_thickness = 1; // [1:0.1:5]
|
||||
|
||||
// Center-to-center distance between the two screw holes
|
||||
screw_hole_spacing = 60; // [30:1:100]
|
||||
|
||||
// Through-hole diameter for the mounting screw shank
|
||||
screw_hole_diameter = 3; // [2:0.1:6]
|
||||
|
||||
// Countersink diameter on the front face for the screw head
|
||||
screw_countersink_diameter = 5.5; // [4:0.1:12]
|
||||
|
||||
// Countersink depth on the front face
|
||||
screw_countersink_depth = 1.2; // [0:0.1:3]
|
||||
|
||||
// Diameter of the internal screw bosses
|
||||
boss_diameter = 9; // [5:0.5:15]
|
||||
|
||||
// Front-face edge rounding (slight chamfer on the visible front edge)
|
||||
front_edge_round = 1.5; // [0:0.1:3]
|
||||
|
||||
// Back-rim edge rounding (slight chamfer on the rear outer edge)
|
||||
back_edge_round = 0; // [0:0.1:3]
|
||||
|
||||
// ============================================
|
||||
// KEYSTONE JACK CRADLE
|
||||
// ============================================
|
||||
// Snap-in keystone modules (RJ45, HDMI, USB, etc.) lock into a panel
|
||||
// using a flexible cantilever latch on one long-axis end of the body.
|
||||
// We give it something real to lock against by building a cradle on
|
||||
// the back of the front face: a rectangular slot that captures the
|
||||
// keystone body, with a latch-catch shelf and angled insertion ramp
|
||||
// at the back of the slot — the latch hook compresses past the ramp
|
||||
// during insertion, then springs out behind the shelf and locks the
|
||||
// module in place. The shelf and ramp shapes are taken from the WALLY
|
||||
// wall-plate customizer's `keystone_solid` receiver (thenewhobbyist/
|
||||
// OpenSCAD).
|
||||
//
|
||||
// The cap's front face has a separate, smaller cutout sized to the
|
||||
// visible portion of the keystone face. The keystone is loaded from
|
||||
// behind: push it face-first into the cavity-side opening of the
|
||||
// cradle until the face flange stops against the back of the front
|
||||
// face. From the outside, only the keystone face is visible through
|
||||
// the cutout — the wider slot behind it is hidden.
|
||||
//
|
||||
// Every slot/shelf dimension is configurable so you can tune it to
|
||||
// the specific keystone you have. If your keystone is too tight to
|
||||
// insert, increase keystone_slot_width / keystone_slot_length /
|
||||
// keystone_clearance. If the latch doesn't engage, adjust
|
||||
// keystone_latch_shelf_protrusion / keystone_latch_shelf_thickness.
|
||||
|
||||
// Add a centered keystone cradle behind the front-face cutout
|
||||
keystone_enabled = true; // [false, true]
|
||||
|
||||
// Front-face cutout — sized to the visible portion of the keystone face.
|
||||
// Make this match what you actually want to see through the cap.
|
||||
keystone_face_width = 14.5; // [10:0.1:25]
|
||||
keystone_face_length = 16.0; // [10:0.1:25]
|
||||
|
||||
// Offset of the front-face cutout along Y, *relative to the cradle
|
||||
// centre*. Most keystones have the visible face sitting on the lower
|
||||
// portion of the body with the latch occupying the upper portion, so
|
||||
// the cutout needs to sit a few mm off-centre toward the non-latch
|
||||
// side. Negative values shift the cutout toward -Y; positive toward +Y.
|
||||
// The default biases the cutout away from the latch shelf.
|
||||
keystone_face_offset_y = 1; // [-6:0.1:6]
|
||||
|
||||
// Cradle slot — sized to the keystone body cross-section (with hooks).
|
||||
// Larger than the front-face cutout so the face flange seats against
|
||||
// the back of the front face and hides any gap.
|
||||
keystone_slot_width = 15.6; // [10:0.1:30]
|
||||
keystone_slot_length = 23.5; // [10:0.1:35]
|
||||
|
||||
// How far the cradle extends behind the front face (into the cavity
|
||||
// and beyond into the wall box). The latch shelf sits at this depth.
|
||||
keystone_cradle_depth = 10; // [4:0.5:25]
|
||||
|
||||
// Latch-catch shelf — protrudes inward from one long-axis wall at the
|
||||
// back of the slot. The cantilever latch hook locks behind it.
|
||||
keystone_latch_shelf_protrusion = 1.5; // [0:0.1:6]
|
||||
keystone_latch_shelf_thickness = 3; // [1:0.1:6]
|
||||
|
||||
// Which long-axis end has the latch-catch shelf, so it lines up with
|
||||
// the cantilever-latch side of *your* keystone. Change this if the
|
||||
// shelf ends up on the wrong side after a print.
|
||||
// 1 = shelf on +Y end of the slot
|
||||
// -1 = shelf on -Y end of the slot
|
||||
keystone_latch_side = -1; // [-1, 1]
|
||||
|
||||
// Rotation of the keystone (cradle + cutout) about the cap's Z axis,
|
||||
// in 90° steps. 0° puts the long axis along Y; 90° puts it along X.
|
||||
keystone_rotation = 270; // [0, 90, 180, 270]
|
||||
|
||||
// Translate the whole keystone (cradle + cutout) away from the cap's
|
||||
// centre. Useful when the keystone shouldn't sit dead-centre.
|
||||
keystone_position_x = 15; // [-40:0.5:40]
|
||||
keystone_position_y = 0; // [-40:0.5:40]
|
||||
|
||||
// Print-tolerance clearance added on each side of every cutout
|
||||
keystone_clearance = 0.2; // [0:0.05:1]
|
||||
|
||||
// Cradle wall thickness around the slot
|
||||
keystone_cradle_wall = 1.6; // [1:0.1:4]
|
||||
|
||||
// ============================================
|
||||
// RENDERING QUALITY
|
||||
// ============================================
|
||||
|
||||
$fn = 64;
|
||||
|
||||
// ============================================
|
||||
// PARAMETER VALIDATION
|
||||
// ============================================
|
||||
|
||||
assert(outer_size > 2 * corner_radius, "Outer size must be larger than twice the corner radius");
|
||||
assert(total_depth > front_thickness, "Total depth must be greater than front thickness");
|
||||
assert(boss_diameter > screw_hole_diameter, "Boss diameter must exceed screw hole diameter");
|
||||
assert(screw_countersink_diameter >= screw_hole_diameter, "Countersink must be at least as wide as the screw hole");
|
||||
assert(screw_hole_spacing + boss_diameter < outer_size - 2 * wall_thickness, "Screw bosses must fit inside the cavity");
|
||||
assert(front_edge_round < front_thickness, "Front edge round must be smaller than front thickness");
|
||||
assert(back_edge_round < total_depth - front_thickness, "Back edge round must be smaller than the cavity depth");
|
||||
assert(front_edge_round + back_edge_round < total_depth, "Combined edge rounds must not exceed total depth");
|
||||
|
||||
// Keystone-specific validation. Bounding box dimensions take rotation
|
||||
// into account: at 90°/270° the cradle's local X and Y are swapped in
|
||||
// the cap frame, which changes which screw boss it might hit.
|
||||
KS_OUTER_X = keystone_slot_width + 2 * keystone_cradle_wall;
|
||||
KS_OUTER_Y = keystone_slot_length + 2 * keystone_cradle_wall;
|
||||
KS_ROT_SWAP = (keystone_rotation == 90 || keystone_rotation == 270);
|
||||
KS_EFF_X = KS_ROT_SWAP ? KS_OUTER_Y : KS_OUTER_X;
|
||||
KS_EFF_Y = KS_ROT_SWAP ? KS_OUTER_X : KS_OUTER_Y;
|
||||
|
||||
// Cradle bounding box in cap coords after rotation + translation.
|
||||
KS_X_MIN = keystone_position_x - KS_EFF_X / 2;
|
||||
KS_X_MAX = keystone_position_x + KS_EFF_X / 2;
|
||||
KS_Y_MIN = keystone_position_y - KS_EFF_Y / 2;
|
||||
KS_Y_MAX = keystone_position_y + KS_EFF_Y / 2;
|
||||
|
||||
// Helper: do AABBs [a1,a2] and [b1,b2] overlap on one axis?
|
||||
function _ks_overlap(a1, a2, b1, b2) = !(a2 < b1 || a1 > b2);
|
||||
|
||||
// Each screw boss's AABB in cap coords (square inscribing the circle).
|
||||
KS_BOSS_R = boss_diameter / 2;
|
||||
KS_TOP_Y = screw_hole_spacing / 2;
|
||||
KS_BOT_Y = -screw_hole_spacing / 2;
|
||||
|
||||
KS_HITS_TOP = _ks_overlap(KS_X_MIN, KS_X_MAX, -KS_BOSS_R, KS_BOSS_R)
|
||||
&& _ks_overlap(KS_Y_MIN, KS_Y_MAX, KS_TOP_Y - KS_BOSS_R, KS_TOP_Y + KS_BOSS_R);
|
||||
KS_HITS_BOT = _ks_overlap(KS_X_MIN, KS_X_MAX, -KS_BOSS_R, KS_BOSS_R)
|
||||
&& _ks_overlap(KS_Y_MIN, KS_Y_MAX, KS_BOT_Y - KS_BOSS_R, KS_BOT_Y + KS_BOSS_R);
|
||||
|
||||
assert(!keystone_enabled || keystone_face_width <= keystone_slot_width,
|
||||
"Keystone front-face cutout (width) must be ≤ the slot width");
|
||||
assert(!keystone_enabled || keystone_face_length <= keystone_slot_length,
|
||||
"Keystone front-face cutout (length) must be ≤ the slot length");
|
||||
assert(keystone_rotation == 0 || keystone_rotation == 90
|
||||
|| keystone_rotation == 180 || keystone_rotation == 270,
|
||||
"keystone_rotation must be 0, 90, 180, or 270");
|
||||
assert(!keystone_enabled
|
||||
|| (KS_X_MIN >= -(outer_size / 2 - wall_thickness)
|
||||
&& KS_X_MAX <= (outer_size / 2 - wall_thickness)),
|
||||
"Keystone cradle (with rotation+offset) extends beyond the cap's inner cavity along X");
|
||||
assert(!keystone_enabled
|
||||
|| (KS_Y_MIN >= -(outer_size / 2 - wall_thickness)
|
||||
&& KS_Y_MAX <= (outer_size / 2 - wall_thickness)),
|
||||
"Keystone cradle (with rotation+offset) extends beyond the cap's inner cavity along Y");
|
||||
assert(!keystone_enabled || !KS_HITS_TOP,
|
||||
"Keystone cradle (with rotation+offset) would collide with the top screw boss");
|
||||
assert(!keystone_enabled || !KS_HITS_BOT,
|
||||
"Keystone cradle (with rotation+offset) would collide with the bottom screw boss");
|
||||
assert(!keystone_enabled
|
||||
|| keystone_latch_shelf_protrusion < keystone_slot_length / 2,
|
||||
"Latch shelf protrusion must leave room for the body in the slot");
|
||||
|
||||
// ============================================
|
||||
// MAIN ASSEMBLY
|
||||
// ============================================
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
// Outer shell with the back cavity already removed
|
||||
difference() {
|
||||
outer_shell();
|
||||
|
||||
// Hollow out the back cavity
|
||||
translate([0, 0, front_thickness])
|
||||
rounded_prism(
|
||||
size = outer_size - 2 * wall_thickness,
|
||||
radius = max(corner_radius - wall_thickness, 0.5),
|
||||
height = total_depth - front_thickness + 1
|
||||
);
|
||||
}
|
||||
|
||||
// Internal screw bosses (rise from the inside of the front face)
|
||||
for (y = [-screw_hole_spacing / 2, screw_hole_spacing / 2])
|
||||
translate([0, y, front_thickness])
|
||||
cylinder(h = total_depth - front_thickness, d = boss_diameter);
|
||||
|
||||
// Keystone cradle — additive material on the back of the front face,
|
||||
// built from the WALLY keystone_solid receiver geometry. Rotated
|
||||
// and translated according to keystone_rotation / position_*.
|
||||
if (keystone_enabled)
|
||||
translate([keystone_position_x, keystone_position_y, 0])
|
||||
rotate([0, 0, keystone_rotation])
|
||||
keystone_cradle();
|
||||
}
|
||||
|
||||
// Through-holes for the mounting screws
|
||||
for (y = [-screw_hole_spacing / 2, screw_hole_spacing / 2])
|
||||
translate([0, y, -1])
|
||||
cylinder(h = total_depth + 2, d = screw_hole_diameter);
|
||||
|
||||
// Countersinks on the front face for the screw heads
|
||||
if (screw_countersink_depth > 0)
|
||||
for (y = [-screw_hole_spacing / 2, screw_hole_spacing / 2])
|
||||
translate([0, y, -0.01])
|
||||
cylinder(
|
||||
h = screw_countersink_depth + 0.01,
|
||||
d1 = screw_countersink_diameter,
|
||||
d2 = screw_hole_diameter
|
||||
);
|
||||
|
||||
// Keystone front-face cutout — sized to the visible portion of the
|
||||
// keystone face only. Smaller than the slot behind it, so the face
|
||||
// flange seats against the back of the front face material around
|
||||
// this cutout (no gaps visible from the outside). Offset along Y
|
||||
// by keystone_face_offset_y so the cutout sits below/above slot
|
||||
// centre to leave room for the latch on its side of the cradle.
|
||||
// Rotated and translated together with the cradle so they stay
|
||||
// aligned regardless of orientation/position.
|
||||
if (keystone_enabled) {
|
||||
cw = keystone_face_width + 2 * keystone_clearance;
|
||||
cl = keystone_face_length + 2 * keystone_clearance;
|
||||
translate([keystone_position_x, keystone_position_y, 0])
|
||||
rotate([0, 0, keystone_rotation])
|
||||
translate([-cw / 2, -cl / 2 + keystone_face_offset_y, -1])
|
||||
cube([cw, cl, front_thickness + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// COMPONENT MODULES
|
||||
// ============================================
|
||||
|
||||
// Outer shell with softly tapered front and back outer edges.
|
||||
// Front face sits at z = 0 (build plate), back rim at z = total_depth.
|
||||
module outer_shell() {
|
||||
if (front_edge_round > 0 || back_edge_round > 0) {
|
||||
hull() {
|
||||
// Front face (inset) — only when front edge is rounded
|
||||
if (front_edge_round > 0)
|
||||
translate([0, 0, 0])
|
||||
rounded_prism(
|
||||
size = outer_size - 2 * front_edge_round,
|
||||
radius = max(corner_radius - front_edge_round, 0.1),
|
||||
height = 0.01
|
||||
);
|
||||
|
||||
// Full-size middle section
|
||||
translate([0, 0, front_edge_round])
|
||||
rounded_prism(
|
||||
size = outer_size,
|
||||
radius = corner_radius,
|
||||
height = total_depth - front_edge_round - back_edge_round
|
||||
);
|
||||
|
||||
// Back rim (inset) — only when back edge is rounded
|
||||
if (back_edge_round > 0)
|
||||
translate([0, 0, total_depth - 0.01])
|
||||
rounded_prism(
|
||||
size = outer_size - 2 * back_edge_round,
|
||||
radius = max(corner_radius - back_edge_round, 0.1),
|
||||
height = 0.01
|
||||
);
|
||||
}
|
||||
} else {
|
||||
rounded_prism(outer_size, corner_radius, total_depth);
|
||||
}
|
||||
}
|
||||
|
||||
// Keystone cradle. Slot dimensions and the latch-catch shelf are all
|
||||
// configurable so the cradle can be tuned to the keystone in hand. The
|
||||
// shelf + insertion ramp pattern follows WALLY's `keystone_solid`
|
||||
// receiver (thenewhobbyist/OpenSCAD), but we drop WALLY's face-stop
|
||||
// shelf — in this design the cap's front face material around the
|
||||
// smaller `keystone_face_*` cutout already stops the face flange.
|
||||
module keystone_cradle() {
|
||||
sw = keystone_slot_width + 2 * keystone_clearance;
|
||||
sl = keystone_slot_length + 2 * keystone_clearance;
|
||||
cd = keystone_cradle_depth;
|
||||
ow = sw + 2 * keystone_cradle_wall;
|
||||
ol = sl + 2 * keystone_cradle_wall;
|
||||
|
||||
ls_p = keystone_latch_shelf_protrusion;
|
||||
ls_t = keystone_latch_shelf_thickness;
|
||||
ls_z = cd - ls_t;
|
||||
|
||||
// Shelf y-edge (the slot-facing edge of the shelf, where the body
|
||||
// ends and the shelf begins). For latch_side = +1 this is +sl/2;
|
||||
// for latch_side = -1 it's -sl/2.
|
||||
ls_y_outer = keystone_latch_side * sl / 2;
|
||||
// Inner edge of the shelf (further into the slot).
|
||||
ls_y_inner = ls_y_outer - keystone_latch_side * ls_p;
|
||||
|
||||
// Position cradle so its slot front (low z) butts against the back
|
||||
// of the cap's front face.
|
||||
translate([0, 0, front_thickness]) {
|
||||
difference() {
|
||||
translate([-ow / 2, -ol / 2, 0])
|
||||
cube([ow, ol, cd]);
|
||||
|
||||
// Slot through the cradle (open at both z ends; the front
|
||||
// is closed by the cap's front face material around the
|
||||
// smaller front-face cutout).
|
||||
translate([-sw / 2, -sl / 2, -1])
|
||||
cube([sw, sl, cd + 2]);
|
||||
}
|
||||
|
||||
// Latch-catch shelf — solid material protruding into the slot
|
||||
// from the latch-side wall, at the back (deep z) end of the
|
||||
// cradle. Transplanted from WALLY's `keystone_solid` 17×4×4
|
||||
// latch shelf. The keystone's own latch hook has a leading-edge
|
||||
// slope, so we don't need a printed ramp here.
|
||||
if (ls_p > 0 && ls_t > 0)
|
||||
translate([-sw / 2, min(ls_y_outer, ls_y_inner), ls_z])
|
||||
cube([sw, ls_p, ls_t]);
|
||||
}
|
||||
}
|
||||
|
||||
// Square prism with rounded corners, centered on the X/Y origin.
|
||||
module rounded_prism(size, radius, height) {
|
||||
hull()
|
||||
for (x = [-size / 2 + radius, size / 2 - radius])
|
||||
for (y = [-size / 2 + radius, size / 2 - radius])
|
||||
translate([x, y, 0])
|
||||
cylinder(h = height, r = radius);
|
||||
}
|
||||
15962
blind-cap/cap.stl
Normal file
BIN
blind-cap/preview.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
76
gridfinity-bin-label/README.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# Gridfinity Bin Label
|
||||
|
||||

|
||||
|
||||
A swappable bin label compatible with Cullenect-style label sockets, sized for Gridfinity bins. Each label has two text fields and two icon fields that can be combined freely to identify the bin contents (screw size, head type, thread pitch, etc.). Adapted from the [Cullenect Labels](https://github.com/CullenJWebb/Cullenect-Labels) source.
|
||||
|
||||
## Output
|
||||
|
||||
`Select_Output` chooses what the SCAD generates:
|
||||
|
||||
| Value | Output |
|
||||
|-------|--------|
|
||||
| `0` | The label itself (default) |
|
||||
| `10` | A socket test fit (for verifying socket dimensions on a printed receiver) |
|
||||
| `11` | The negative volume of the socket (for embedding into another model) |
|
||||
|
||||
## Label Geometry
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `label_width` | `1` | Width in Gridfinity units (`1` = 36 mm × 11 mm) |
|
||||
| `backward_compatible` | `true` | Generate V1-style latches for 1U labels (compatible with the original Cullenect socket) |
|
||||
| `label_deboss` | `false` | If `true`, text and symbols are subtracted from the label face instead of raised |
|
||||
| `gridfinity` | `true` | Use Gridfinity sizing. Set to `false` to drive size from `labelXmm`/`labelYmm`/`labelZmm` |
|
||||
| `labelXmm` | 36 mm | Custom label width when `gridfinity` is `false` |
|
||||
| `labelYmm` | 11 mm | Custom label height when `gridfinity` is `false` |
|
||||
| `labelZmm` | 1.2 mm | Custom label thickness when `gridfinity` is `false` |
|
||||
|
||||
## Text 1 / Text 2
|
||||
|
||||
Each text slot is independent. `Text2` defaults to empty so single-line labels just use `Text1`.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `Text{N}` | `"M5*8"` / `""` | Label text |
|
||||
| `Text{N}_Align` | `center` / `right` | Horizontal alignment within the label |
|
||||
| `Text{N}_Font_Size` | 4 mm | Font size |
|
||||
| `Text{N}_Font` | `Open Sans` | Font family |
|
||||
| `Text{N}_Font_Style` | `Bold` | Font weight/style |
|
||||
| `Text{N}_XY` | `[0,0]` / `[-2,0]` | Fine X/Y offset on top of the alignment anchor |
|
||||
|
||||
## Symbol 1 / Symbol 2
|
||||
|
||||
Two independent symbol slots that render alongside the text (not in place of it). Useful for showing screw head type, drive type, or material on the same label as the size text. Set `Symbol{N}` to `none` to omit a slot.
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `Symbol{N}` | `side_pan` / `hex_rounded` | Symbol shape (see catalogue below) |
|
||||
| `Symbol{N}_Align` | `left` / `right` | Horizontal alignment within the label |
|
||||
| `Symbol{N}_Size` | 7 mm | Symbol diameter (bounding box) |
|
||||
| `Symbol{N}_Stroke` | 1 mm | Stroke thickness for symbol details (cross arms, slot, star arms, etc.) |
|
||||
| `Symbol{N}_XY` | `[1,0]` / `[-2,0]` | Fine X/Y offset on top of the alignment anchor |
|
||||
|
||||
### Symbol Catalogue
|
||||
|
||||
Top-down screw head views (showing what the head looks like from above):
|
||||
|
||||
| Symbol | Value | Description |
|
||||
|:---:|---|---|
|
||||
| <img src="symbols/hex_rounded.png" width="48"> | `hex_rounded` | Hex socket cap screw (round head with hex socket) |
|
||||
| <img src="symbols/hex_flat.png" width="48"> | `hex_flat` | Hex bolt head (flat hexagonal head) |
|
||||
| <img src="symbols/phillips.png" width="48"> | `phillips` | Phillips cross drive |
|
||||
| <img src="symbols/slotted.png" width="48"> | `slotted` | Slotted (single-slot) drive |
|
||||
| <img src="symbols/torx.png" width="48"> | `torx` | Torx (six-pointed star) drive |
|
||||
| <img src="symbols/square.png" width="48"> | `square` | Square (Robertson) drive |
|
||||
| <img src="symbols/pozidriv.png" width="48"> | `pozidriv` | Pozidriv (Phillips + diagonal cross) drive |
|
||||
|
||||
Side-profile screw silhouettes (showing the screw from the side, head + threaded shaft):
|
||||
|
||||
| Symbol | Value | Description |
|
||||
|:---:|---|---|
|
||||
| <img src="symbols/side_cap.png" width="48"> | `side_cap` | Hex socket cap screw — cylindrical head |
|
||||
| <img src="symbols/side_flat.png" width="48"> | `side_flat` | Countersunk flat head |
|
||||
| <img src="symbols/side_pan.png" width="48"> | `side_pan` | Pan head (rounded dome with skirt) |
|
||||
| <img src="symbols/side_button.png" width="48"> | `side_button` | Button head (low rounded dome) |
|
||||
| <img src="symbols/side_hex.png" width="48"> | `side_hex` | Hex bolt with chamfered head |
|
||||
509
gridfinity-bin-label/label.scad
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
// Original source: https://github.com/CullenJWebb/Cullenect-Labels
|
||||
|
||||
/* [General Settings] */
|
||||
//I want to generate...
|
||||
Select_Output=0; // [0:Label, 10:Socket test fit, 11:Socket Negative Volume]
|
||||
//model = "" // ["Cullenect label","Socket test fit","Socket Negative Volume"]
|
||||
// Width in gridfinity units
|
||||
label_width = 1; // .1
|
||||
// Generate V1 Latches for 1U labels?
|
||||
backward_compatible = true;
|
||||
// Deboss Text?
|
||||
label_deboss = false;
|
||||
|
||||
/* [Label Text 1] */
|
||||
|
||||
// Label Text
|
||||
Text1 = "M5*8";
|
||||
// Text Alignment
|
||||
Text1_Align = "center"; // ["left","center","right"]
|
||||
// Font Size
|
||||
Text1_Font_Size = 4; // .1
|
||||
// Font Family
|
||||
Text1_Font = "Open Sans"; // [Open Sans, Open Sans Condensed, Ubuntu, Montserrat]
|
||||
|
||||
// Font Style
|
||||
Text1_Font_Style = "Bold"; // [Regular,Black,Bold,ExtraBol,ExtraLight,Light,Medium,SemiBold,Thin,Italic,Black Italic,Bold Italic,ExtraBold Italic,ExtraLight Italic,Light Italic,Medium Italic,SemiBold Italic,Thin Italic]
|
||||
// Adjust X and Y Position
|
||||
Text1_XY = [0,0]; // .1
|
||||
/* [Label Text 2] */
|
||||
|
||||
// Label Text
|
||||
Text2 = "";
|
||||
// Text Alignment
|
||||
Text2_Align = "right"; // ["left","center","right"]
|
||||
// Font Size
|
||||
Text2_Font_Size = 4; // .1
|
||||
// Font Family
|
||||
Text2_Font = "Open Sans"; // [Open Sans, Open Sans Condensed, Ubuntu, Montserrat]
|
||||
|
||||
// Font Style
|
||||
Text2_Font_Style = "Bold"; // [Regular,Black,Bold,ExtraBol,ExtraLight,Light,Medium,SemiBold,Thin,Italic,Black Italic,Bold Italic,ExtraBold Italic,ExtraLight Italic,Light Italic,Medium Italic,SemiBold Italic,Thin Italic]
|
||||
// Adjust X and Y Position
|
||||
Text2_XY = [-2,0]; // .1
|
||||
|
||||
/* [Symbol 1] */
|
||||
|
||||
// Symbol shape (set to "none" to omit)
|
||||
Symbol1 = "side_pan"; // [none, hex_rounded, hex_flat, phillips, slotted, torx, square, pozidriv, side_cap, side_flat, side_pan, side_button, side_hex]
|
||||
// Symbol Alignment
|
||||
Symbol1_Align = "left"; // ["left","center","right"]
|
||||
// Symbol diameter in mm
|
||||
Symbol1_Size = 7; // .1
|
||||
// Stroke thickness for symbol details (cross, slot, star arms)
|
||||
Symbol1_Stroke = 1.0; // .1
|
||||
// Adjust X and Y Position
|
||||
Symbol1_XY = [1,0]; // .1
|
||||
|
||||
/* [Symbol 2] */
|
||||
|
||||
// Symbol shape (set to "none" to omit)
|
||||
Symbol2 = "hex_rounded"; // [none, hex_rounded, hex_flat, phillips, slotted, torx, square, pozidriv, side_cap, side_flat, side_pan, side_button, side_hex]
|
||||
// Symbol Alignment
|
||||
Symbol2_Align = "right"; // ["left","center","right"]
|
||||
// Symbol diameter in mm
|
||||
Symbol2_Size = 7; // .1
|
||||
// Stroke thickness for symbol details (cross, slot, star arms)
|
||||
Symbol2_Stroke = 1.0; // .1
|
||||
// Adjust X and Y Position
|
||||
Symbol2_XY = [-2,0]; // .1
|
||||
|
||||
/* [Advanced] */
|
||||
// Increase or decrease resolution of certain details
|
||||
$fs = 0.01; // .01
|
||||
|
||||
// Use gridfinity U
|
||||
gridfinity = true;
|
||||
|
||||
// Width of label in mm
|
||||
labelXmm = 36.0; // .1
|
||||
|
||||
// Height of label in mm
|
||||
labelYmm = 11.0; // .1
|
||||
|
||||
// Thickness of label in mm
|
||||
labelZmm = 1.2; // .1
|
||||
|
||||
/* [Hidden] */
|
||||
gridfinityX = 42; // Grid size for gridfinity units.
|
||||
labelX = (gridfinity) ? (label_width * gridfinityX) - 6 : labelXmm;
|
||||
labelY = (gridfinity) ? 11 : labelYmm;
|
||||
labelZ = (gridfinity) ? 1.2 : labelZmm;
|
||||
latchX = 0.2; // Width of socket on label walls
|
||||
latchZ = 0.6; // Z-height of wall socket
|
||||
|
||||
|
||||
// Tool for rounded cubes
|
||||
module RoundedCube(size, radius) {
|
||||
offsetfix = radius * 2;
|
||||
width = size[0] - offsetfix;
|
||||
height = size[1] - offsetfix;
|
||||
depth = size[2];
|
||||
|
||||
|
||||
translate([radius, radius, 0]) linear_extrude(height = depth) offset(r = radius) square([width, height]);
|
||||
}
|
||||
|
||||
// V1 Label with new wall sockets
|
||||
// Will only generate V1 label XY with V2 label Z
|
||||
module Cullenect_Label_V1() {
|
||||
|
||||
// Variables
|
||||
labelX_v1 = 36;
|
||||
labelY_v1 = 11;
|
||||
$midX1 = 4.695;
|
||||
$midX2 = 10.18;
|
||||
$midlatchX = 1.95;
|
||||
$bottomX1 = 5.395;
|
||||
$bottomX2 = 11.18;
|
||||
$bottomlatchX = 0.95;
|
||||
|
||||
// Base below socket
|
||||
// Base #1
|
||||
color("Silver")
|
||||
RoundedCube([$bottomX1, labelY_v1, 0.2], 0.5);
|
||||
|
||||
// Base #2
|
||||
translate([$bottomX1 + $bottomlatchX,0,0])
|
||||
color("Silver")
|
||||
RoundedCube([$bottomX2, labelY_v1, 0.2], 0.5);
|
||||
// Base #3
|
||||
translate([$bottomX1 + $bottomlatchX + $bottomX2 + $bottomlatchX,0,0])
|
||||
color("Silver")
|
||||
RoundedCube([$bottomX2, labelY_v1, 0.2], 0.5);
|
||||
// Base #4
|
||||
translate([$bottomX1 + $bottomlatchX + $bottomX2 + $bottomlatchX + $bottomlatchX + $bottomX2,0,0])
|
||||
color("Silver")
|
||||
RoundedCube([$bottomX1, labelY_v1, 0.2], 0.5);
|
||||
|
||||
// Middle along socket
|
||||
// Middle #1
|
||||
translate([latchX,latchX,0.2])
|
||||
color("Gray")
|
||||
RoundedCube([$midX1, labelY_v1 - (latchX * 2), 0.6], 0.5);
|
||||
// Middle #2
|
||||
translate([latchX + $midX1 + $midlatchX,latchX,0.2])
|
||||
color("Gray")
|
||||
RoundedCube([$midX2, labelY_v1 - (latchX * 2), 0.6], 0.5);
|
||||
// Middle #3
|
||||
translate([latchX + $midX1 + $midlatchX + $midX2 + $midlatchX,latchX,0.2])
|
||||
color("Gray")
|
||||
RoundedCube([$midX2, labelY_v1 - (latchX * 2), 0.6], 0.5);
|
||||
// Middle #4
|
||||
translate([latchX + $midX1 + $midlatchX + $midX2 + $midlatchX + $midX2 + $midlatchX,latchX,0.2])
|
||||
color("Gray")
|
||||
RoundedCube([$midX1, labelY_v1 - (latchX * 2), 0.6], 0.5);
|
||||
|
||||
// Top above socket
|
||||
translate([0,0,0.8])
|
||||
color("Silver")
|
||||
RoundedCube([labelX_v1, labelY_v1, 0.4], 0.5);
|
||||
}
|
||||
|
||||
// V2 Label without backward compatibility
|
||||
module Cullenect_Label_V2() {
|
||||
// Label base below socket
|
||||
color("Silver")
|
||||
RoundedCube([labelX, labelY, 0.2], 0.5);
|
||||
|
||||
// Label middle within socket
|
||||
translate([latchX,latchX,0])
|
||||
color("Gray")
|
||||
RoundedCube([labelX - (latchX * 2), labelY - (latchX * 2), labelZ - 0.2], 0.5);
|
||||
|
||||
// Label top above socket
|
||||
translate([0,0,0.2 + latchZ])
|
||||
color("Silver")
|
||||
RoundedCube([labelX, labelY, (labelZ - 0.2) - latchZ], 0.5);
|
||||
}
|
||||
|
||||
// Module to generate the correct label type
|
||||
module Cullenect_Label() {
|
||||
if (backward_compatible && gridfinity && (label_width == 1)){
|
||||
Cullenect_Label_V1();
|
||||
} else {
|
||||
Cullenect_Label_V2();
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate Text1 Position and font
|
||||
Text1_posX = (Text1_Align == "left") ? 0 + Text1_XY.x :
|
||||
(Text1_Align == "center") ? (labelX / 2) + Text1_XY.x :
|
||||
(Text1_Align == "right") ? labelX + Text1_XY.x : 0; // Fallback to 0
|
||||
Text1_posY = (labelY / 2) + Text1_XY.y;
|
||||
Text1_posZ = labelZ - 0.2;
|
||||
Text1_pos = [Text1_posX, Text1_posY, Text1_posZ];
|
||||
|
||||
// Calculate Text2 Position and font
|
||||
Text2_posX = (Text2_Align == "left") ? 0 + Text2_XY.x :
|
||||
(Text2_Align == "center") ? (labelX / 2) + Text2_XY.x :
|
||||
(Text2_Align == "right") ? labelX + Text2_XY.x : 0; // Fallback to 0
|
||||
Text2_posY = (labelY / 2) + Text2_XY.y;
|
||||
Text2_posZ = labelZ - 0.2;
|
||||
Text2_pos = [Text2_posX, Text2_posY, Text2_posZ];
|
||||
|
||||
// Generate Label Text #1
|
||||
module label_text1() {
|
||||
translate(Text1_pos)
|
||||
linear_extrude(0.4)
|
||||
text(Text1, Text1_Font_Size, font = str(Text1_Font, ":", Text1_Font_Style), halign = Text1_Align, valign = "center");
|
||||
}
|
||||
|
||||
// Generate Label Text #2
|
||||
module label_text2() {
|
||||
translate(Text2_pos)
|
||||
linear_extrude(0.4)
|
||||
text(Text2, Text2_Font_Size, font = str(Text2_Font, ":", Text2_Font_Style), halign = Text2_Align, valign = "center");
|
||||
}
|
||||
|
||||
// Symbol positions — same alignment options as text, with the symbol's bounding box kept inside the label
|
||||
Symbol_Z = labelZ - 0.2;
|
||||
function symbol_x(align, size, dx) =
|
||||
(align == "left") ? (size / 2) + dx :
|
||||
(align == "center") ? (labelX / 2) + dx :
|
||||
(align == "right") ? labelX - (size / 2) + dx : 0;
|
||||
|
||||
Symbol1_pos = [
|
||||
symbol_x(Symbol1_Align, Symbol1_Size, Symbol1_XY.x),
|
||||
(labelY / 2) + Symbol1_XY.y,
|
||||
Symbol_Z
|
||||
];
|
||||
Symbol2_pos = [
|
||||
symbol_x(Symbol2_Align, Symbol2_Size, Symbol2_XY.x),
|
||||
(labelY / 2) + Symbol2_XY.y,
|
||||
Symbol_Z
|
||||
];
|
||||
|
||||
// 2D screw-head symbols, centered at origin, fitting within a circle of diameter d
|
||||
module sym_hex_rounded(d, stroke) {
|
||||
// Hex socket cap screw (rounded outer head with hex socket cutout)
|
||||
difference() {
|
||||
circle(d = d);
|
||||
rotate(30) circle(d = d * 0.55, $fn = 6);
|
||||
}
|
||||
}
|
||||
|
||||
module sym_hex_flat(d, stroke) {
|
||||
// Hex head bolt (flat hexagonal head with central thread hole)
|
||||
difference() {
|
||||
rotate(30) circle(d = d, $fn = 6);
|
||||
circle(d = d * 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
module sym_phillips(d, stroke) {
|
||||
difference() {
|
||||
circle(d = d);
|
||||
union() {
|
||||
square([stroke, d * 0.75], center = true);
|
||||
square([d * 0.75, stroke], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module sym_slotted(d, stroke) {
|
||||
difference() {
|
||||
circle(d = d);
|
||||
square([d * 0.85, stroke], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
module sym_torx(d, stroke) {
|
||||
difference() {
|
||||
circle(d = d);
|
||||
for (a = [0:60:300])
|
||||
rotate(a) square([stroke, d * 0.75], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
module sym_square(d, stroke) {
|
||||
difference() {
|
||||
circle(d = d);
|
||||
rotate(45) square(d * 0.45, center = true);
|
||||
}
|
||||
}
|
||||
|
||||
module sym_pozidriv(d, stroke) {
|
||||
// Phillips cross plus a smaller diagonal cross
|
||||
difference() {
|
||||
circle(d = d);
|
||||
union() {
|
||||
square([stroke, d * 0.75], center = true);
|
||||
square([d * 0.75, stroke], center = true);
|
||||
rotate(45) square([stroke * 0.7, d * 0.55], center = true);
|
||||
rotate(45) square([d * 0.55, stroke * 0.7], center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Side-profile screw silhouettes (head + threaded shaft), centered in a d×d bounding box
|
||||
module sym_side_cap(d, stroke) {
|
||||
// Hex socket cap screw: cylindrical head with a slim socket marker
|
||||
sw = d * 0.28; sh = d * 0.6;
|
||||
hw = d * 0.55; hh = d * 0.4;
|
||||
translate([0, -d / 2]) {
|
||||
translate([-sw / 2, 0]) square([sw, sh]);
|
||||
difference() {
|
||||
translate([-hw / 2, sh]) square([hw, hh]);
|
||||
translate([-hw * 0.2, sh + hh * 0.55])
|
||||
square([hw * 0.4, stroke * 0.7]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module sym_side_flat(d, stroke) {
|
||||
// Countersunk flat head: trapezoid that flares from shaft to flat top
|
||||
sw = d * 0.28; sh = d * 0.6;
|
||||
htop = d * 0.7; hbot = d * 0.32; hh = d * 0.4;
|
||||
translate([0, -d / 2]) {
|
||||
translate([-sw / 2, 0]) square([sw, sh]);
|
||||
translate([0, sh])
|
||||
polygon([
|
||||
[-hbot / 2, 0], [hbot / 2, 0],
|
||||
[htop / 2, hh], [-htop / 2, hh]
|
||||
]);
|
||||
translate([-htop * 0.4, sh + hh - stroke * 0.9])
|
||||
square([htop * 0.8, stroke * 0.6]);
|
||||
}
|
||||
}
|
||||
|
||||
module sym_side_pan(d, stroke) {
|
||||
// Pan head: rounded dome with broader skirt
|
||||
sw = d * 0.28; sh = d * 0.55;
|
||||
hw = d * 0.7; hh = d * 0.45;
|
||||
r = hh * 0.55;
|
||||
translate([0, -d / 2]) {
|
||||
translate([-sw / 2, 0]) square([sw, sh]);
|
||||
translate([0, sh])
|
||||
hull() {
|
||||
translate([-hw / 2 + r, hh - r]) circle(r = r);
|
||||
translate([hw / 2 - r, hh - r]) circle(r = r);
|
||||
translate([-hw / 2, 0]) square([hw, 0.01]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module sym_side_button(d, stroke) {
|
||||
// Button head: low rounded dome
|
||||
sw = d * 0.28; sh = d * 0.7;
|
||||
hw = d * 0.65; hh = d * 0.3;
|
||||
r = hh * 0.95;
|
||||
translate([0, -d / 2]) {
|
||||
translate([-sw / 2, 0]) square([sw, sh]);
|
||||
translate([0, sh])
|
||||
hull() {
|
||||
translate([-hw / 2 + r, 0]) circle(r = r);
|
||||
translate([hw / 2 - r, 0]) circle(r = r);
|
||||
translate([-hw / 2, 0]) square([hw, 0.01]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module sym_side_hex(d, stroke) {
|
||||
// Hex bolt: head profile shows flat top with chamfered corners
|
||||
sw = d * 0.28; sh = d * 0.55;
|
||||
hw = d * 0.7; hh = d * 0.45;
|
||||
cf = hh * 0.3;
|
||||
translate([0, -d / 2]) {
|
||||
translate([-sw / 2, 0]) square([sw, sh]);
|
||||
translate([0, sh])
|
||||
polygon([
|
||||
[-hw / 2, 0], [hw / 2, 0],
|
||||
[hw / 2, hh - cf], [hw / 2 - cf, hh],
|
||||
[-hw / 2 + cf, hh], [-hw / 2, hh - cf]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
module symbol_shape(name, d, stroke) {
|
||||
if (name == "hex_rounded") sym_hex_rounded(d, stroke);
|
||||
else if (name == "hex_flat") sym_hex_flat(d, stroke);
|
||||
else if (name == "phillips") sym_phillips(d, stroke);
|
||||
else if (name == "slotted") sym_slotted(d, stroke);
|
||||
else if (name == "torx") sym_torx(d, stroke);
|
||||
else if (name == "square") sym_square(d, stroke);
|
||||
else if (name == "pozidriv") sym_pozidriv(d, stroke);
|
||||
else if (name == "side_cap") sym_side_cap(d, stroke);
|
||||
else if (name == "side_flat") sym_side_flat(d, stroke);
|
||||
else if (name == "side_pan") sym_side_pan(d, stroke);
|
||||
else if (name == "side_button") sym_side_button(d, stroke);
|
||||
else if (name == "side_hex") sym_side_hex(d, stroke);
|
||||
}
|
||||
|
||||
// Independent symbols — render alongside (not in place of) the text layers
|
||||
module label_symbol1() {
|
||||
if (Symbol1 != "none")
|
||||
translate(Symbol1_pos)
|
||||
linear_extrude(0.4)
|
||||
symbol_shape(Symbol1, Symbol1_Size, Symbol1_Stroke);
|
||||
}
|
||||
|
||||
module label_symbol2() {
|
||||
if (Symbol2 != "none")
|
||||
translate(Symbol2_pos)
|
||||
linear_extrude(0.4)
|
||||
symbol_shape(Symbol2, Symbol2_Size, Symbol2_Stroke);
|
||||
}
|
||||
|
||||
// Combined text + symbol overlay
|
||||
module label_decorations() {
|
||||
label_text1();
|
||||
label_text2();
|
||||
label_symbol1();
|
||||
label_symbol2();
|
||||
}
|
||||
|
||||
// Join or difference the label and decorations
|
||||
module cullenect_label_text(){
|
||||
if (label_deboss) {
|
||||
difference() {
|
||||
Cullenect_Label();
|
||||
color("Gray") label_decorations();
|
||||
}
|
||||
} else {
|
||||
union() {
|
||||
Cullenect_Label();
|
||||
color("Gray") label_decorations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*cullenect_label_text();
|
||||
|
||||
// Socket and Socket Negative Variables
|
||||
socket_offset = 0.3;
|
||||
socket_walls = 2;
|
||||
socketX = labelX + socket_offset;
|
||||
socketY = labelY + socket_offset;
|
||||
ribZ = 0.4;
|
||||
// Generate socket
|
||||
module cullenect_socket(){
|
||||
union(){
|
||||
difference(){
|
||||
translate([-socket_walls,-socket_walls,-1])
|
||||
color("Silver")
|
||||
RoundedCube([labelX + (socket_walls * 2), socketY + (socket_walls * 2), labelZ + 1], 0.2);
|
||||
|
||||
color("Gray")
|
||||
RoundedCube([socketX, socketY, labelZ + 1], 0.5);
|
||||
}
|
||||
translate([0,0,0.2])
|
||||
color("Silver")
|
||||
cube([socketX, latchX, ribZ]);
|
||||
translate([0, socketY - latchX,0.2])
|
||||
color("Silver")
|
||||
cube([socketX, latchX, ribZ]);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate negative volume of socket
|
||||
module cullenect_socket_negative(){
|
||||
|
||||
difference(){
|
||||
color("Gray")
|
||||
RoundedCube([socketX, socketY, labelZ], 0.5);
|
||||
cullenect_socket();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Vertical socket variables
|
||||
vsocketY = labelZ - latchZ - 0.2; // define starting pos and depth
|
||||
vsocketZ = socketY + 1; // Vertical height with 45 degree ceiling
|
||||
|
||||
|
||||
// Generate vertical socket
|
||||
// Unlike the h-socket and label this starts with the negative volume due to easier rounded edges
|
||||
// Rounded edges are needed for the vertical printing of the ribbing
|
||||
module cullenect_vertical_socket() {
|
||||
difference(){
|
||||
// Create base
|
||||
union(){
|
||||
cube([socketX, vsocketY / 2, vsocketZ]);// front of socket, no rounding
|
||||
RoundedCube([socketX, vsocketY, vsocketZ], 0.1);// front of socket, rounded inside around rib
|
||||
translate([0,vsocketY,0])
|
||||
cube([socketX,latchZ,vsocketZ]); // Middle of socket, to be cut away later by rounded cube for rib
|
||||
translate([-0.2,vsocketY + latchZ,0])
|
||||
RoundedCube([socketX + 0.4, vsocketY, vsocketZ], 0.1);
|
||||
}
|
||||
// Remove rounded ribs
|
||||
translate([-1,vsocketY,0])
|
||||
RoundedCube([latchX + 1, latchZ, vsocketZ], 0.1);
|
||||
translate([socketX - latchX,vsocketY,0])
|
||||
RoundedCube([latchX + 1, latchZ, vsocketZ], 0.1);
|
||||
// remove 45 degree top
|
||||
translate([-2,labelZ / 2,vsocketY])
|
||||
RoundedCube([latchX + 1, latchZ, vsocketZ], 0.1);
|
||||
|
||||
}
|
||||
}
|
||||
*cullenect_vertical_socket();
|
||||
// Vertical Socket still under development
|
||||
|
||||
// Generate Selected Model...
|
||||
module selected_model() {
|
||||
if (Select_Output == 10) {cullenect_socket();}
|
||||
else if (Select_Output == 11) {cullenect_socket_negative();}
|
||||
else {cullenect_label_text();}
|
||||
}
|
||||
selected_model();
|
||||
16074
gridfinity-bin-label/label.stl
Normal file
BIN
gridfinity-bin-label/preview.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
gridfinity-bin-label/symbols/hex_flat.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
gridfinity-bin-label/symbols/hex_rounded.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
gridfinity-bin-label/symbols/phillips.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
gridfinity-bin-label/symbols/pozidriv.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
gridfinity-bin-label/symbols/preview.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
12
gridfinity-bin-label/symbols/render.scad
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Renders a single symbol from ../label.scad as a flat top-down preview.
|
||||
// Used to generate the symbol thumbnails referenced in the README.
|
||||
// Usage: openscad -D 'symbol="hex_rounded"' --camera=0,0,100,0,0,0 --projection=ortho \
|
||||
// --imgsize=240,240 -o hex_rounded.png render.scad
|
||||
use <../label.scad>;
|
||||
|
||||
symbol = "hex_rounded";
|
||||
size = 20;
|
||||
stroke = 3;
|
||||
|
||||
linear_extrude(1)
|
||||
symbol_shape(symbol, size, stroke);
|
||||
1010
gridfinity-bin-label/symbols/render.stl
Normal file
BIN
gridfinity-bin-label/symbols/side_button.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
gridfinity-bin-label/symbols/side_cap.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
gridfinity-bin-label/symbols/side_flat.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
gridfinity-bin-label/symbols/side_hex.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
gridfinity-bin-label/symbols/side_pan.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
gridfinity-bin-label/symbols/slotted.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
gridfinity-bin-label/symbols/square.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
gridfinity-bin-label/symbols/torx.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |