Make the back face a full-size flat rectangle flush against the wall, while keeping rounded edges on all four sides of the front face.
150 lines
5.5 KiB
OpenSCAD
150 lines
5.5 KiB
OpenSCAD
// ============================================
|
|
// Parametrizable Wall Hook
|
|
// ============================================
|
|
// A simple wall hook with a rectangular base plate
|
|
// and a cylindrical peg extending outward.
|
|
// Designed for 3D printing.
|
|
|
|
// ============================================
|
|
// CUSTOMIZABLE PARAMETERS
|
|
// ============================================
|
|
|
|
// Length of the hook cylinder (how far it extends from the wall)
|
|
hook_cylinder_length = 20; // [10:1:100]
|
|
|
|
// Upward angle of the hook cylinder in degrees
|
|
hook_angle = 0; // [0:1:45]
|
|
|
|
// Overall scale multiplier (1.0 = default size)
|
|
overall_scale = 1.0; // [0.25:0.05:3.0]
|
|
|
|
// Enable a retaining dent near the tip of the hook (prevents items from sliding off at 0° angle)
|
|
hook_dent_enabled = true; // [true, false]
|
|
|
|
// Width of the retaining dent in mm
|
|
hook_dent_width = 10; // [1:0.5:10]
|
|
|
|
// ============================================
|
|
// BASE PARAMETERS
|
|
// ============================================
|
|
|
|
// Base plate dimensions
|
|
base_width = 20; // Width (vertical dimension when mounted)
|
|
base_height = 40; // Height (vertical dimension when mounted)
|
|
base_depth = 3; // Thickness/depth of base plate
|
|
|
|
// Hook cylinder properties
|
|
hook_diameter = 5; // Diameter of the hook cylinder
|
|
fillet_radius = 2; // Radius for smooth junction between hook and base
|
|
|
|
// Rendering quality
|
|
cylinder_resolution = 50; // Number of facets for cylinders
|
|
|
|
// ============================================
|
|
// PARAMETER VALIDATION
|
|
// ============================================
|
|
|
|
assert(hook_cylinder_length > 0, "Hook cylinder length must be positive");
|
|
assert(hook_angle >= 0 && hook_angle <= 45, "Hook angle should be between 0 and 45 degrees");
|
|
assert(overall_scale > 0, "Overall scale must be positive");
|
|
assert(base_depth >= 3, "Base depth should be at least 3mm for strength");
|
|
assert(hook_diameter >= 4, "Hook diameter should be at least 4mm for printability");
|
|
assert(hook_dent_width > 0, "Hook dent width must be positive");
|
|
|
|
// ============================================
|
|
// MAIN ASSEMBLY
|
|
// ============================================
|
|
|
|
scale([overall_scale, overall_scale, overall_scale]) {
|
|
difference() {
|
|
union() {
|
|
base_plate();
|
|
hook_cylinder();
|
|
}
|
|
// Cut away anything extending behind the base
|
|
translate([-100, -50, -50])
|
|
cube([100, 100, 200]);
|
|
}
|
|
}
|
|
|
|
// ============================================
|
|
// COMPONENT MODULES
|
|
// ============================================
|
|
|
|
// Rectangular base plate, flat back (wall side), rounded front edges on all four sides
|
|
module base_plate() {
|
|
corner_radius = 2;
|
|
|
|
hull() {
|
|
// Back - full flat rectangle (wall side, sharp edges)
|
|
translate([0, -base_width/2, 0])
|
|
cube([1, base_width, base_height]);
|
|
|
|
// Front four corner spheres (create rounded edges on all sides)
|
|
translate([base_depth, -base_width/2 + corner_radius, corner_radius])
|
|
sphere(r=corner_radius, $fn=cylinder_resolution);
|
|
|
|
translate([base_depth, base_width/2 - corner_radius, corner_radius])
|
|
sphere(r=corner_radius, $fn=cylinder_resolution);
|
|
|
|
translate([base_depth, -base_width/2 + corner_radius, base_height - corner_radius])
|
|
sphere(r=corner_radius, $fn=cylinder_resolution);
|
|
|
|
translate([base_depth, base_width/2 - corner_radius, base_height - corner_radius])
|
|
sphere(r=corner_radius, $fn=cylinder_resolution);
|
|
}
|
|
}
|
|
|
|
// Hook cylinder extending from base with upward angle
|
|
module hook_cylinder() {
|
|
translate([0, 0, base_height/5])
|
|
rotate([0, 90 + hook_angle*-1, 0]) {
|
|
difference() {
|
|
union() {
|
|
// Main cylinder body
|
|
cylinder(h=hook_cylinder_length, d=hook_diameter, $fn=cylinder_resolution);
|
|
|
|
// Rounded cap at the end
|
|
translate([0, 0, hook_cylinder_length])
|
|
sphere(d=hook_diameter, $fn=cylinder_resolution);
|
|
}
|
|
|
|
// Pill-shaped retaining dent on top of the cylinder near the tip
|
|
if (hook_dent_enabled) {
|
|
dent_position = hook_cylinder_length - hook_diameter/2 - hook_dent_width/2;
|
|
translate([0, 0, dent_position])
|
|
retaining_dent(hook_dent_width, hook_diameter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Pill-shaped dent cut into the top of the hook cylinder
|
|
// Creates a \__/ profile when viewed from the side
|
|
module retaining_dent(width, diameter) {
|
|
pill_r = diameter/2;
|
|
half_spread = max(0, width/2 - pill_r);
|
|
|
|
// -X in local frame = "up" in world frame (after the 90° Y rotation)
|
|
translate([-diameter/2, 0, 0])
|
|
hull() {
|
|
translate([0, 0, -half_spread])
|
|
sphere(r=pill_r, $fn=cylinder_resolution);
|
|
translate([0, 0, half_spread])
|
|
sphere(r=pill_r, $fn=cylinder_resolution);
|
|
}
|
|
}
|
|
|
|
// Fillet at the junction between hook and base for strength
|
|
module fillet_junction() {
|
|
translate([base_depth - 1, 0, base_height/3])
|
|
rotate([0, 90 + hook_angle*-1, 0])
|
|
hull() {
|
|
// Cylinder at the start position
|
|
cylinder(h=0.1, d=hook_diameter, $fn=cylinder_resolution);
|
|
|
|
// Larger cylinder slightly behind to create smooth blend with base
|
|
translate([0, 0, -fillet_radius])
|
|
cylinder(h=0.1, d=hook_diameter + fillet_radius*2, $fn=cylinder_resolution);
|
|
}
|
|
}
|