Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 107 additions & 1 deletion hooks.scad
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//////////////////////////////////////////////////////////////////////
// LibFile: hooks.scad
// Functions and modules for creating hooks and hook like parts.
// At the moment only one part is supported, a ring hook.
// Includes:
// include <BOSL2/std.scad>
// include <BOSL2/hooks.scad>
Expand Down Expand Up @@ -298,3 +297,110 @@ module ring_hook(base_size, hole_z, or, ir, od, id, wall, hole="circle",
}


// Module: s_hook()
// Synopsis: Creates an S-shaped hook
// SynTags: Geom
// Topics: Parts, Hooks
// See Also: ring_hook()
// Usage:
// s_hook(or, [sides], [l_shaft=], [r_loop1=], [angle1=], [r_loop2=], [angle2=], ...) [ATTACHMENTS];
// Description:
// Creates an S-shaped hook by sweeping a cross-section profile along a turtle-graphics path.
// The hook consists of a central shaft with configurable loops on each end. Each loop can
// have an optional straight stem extension and a reverse curl. The cross-section can be a
// regular polygon (controlled by `sides`) or a circle (when `sides` < 3).
// .
// The hook is oriented along the Y axis, centered at the origin. The +Y end has loop1 and
// the -Y end has loop2. By default both loops curve 180 degrees creating a classic S shape.
// .
// End caps are generated using rotate_sweep to close the ends of the swept shape cleanly.
// Arguments:
// or = outside radius of the cross-section shape. Default: 2
// sides = number of sides for the cross-section polygon. Values less than 3 produce a circle. Default: 6
// ---
// l_shaft = length of the straight central shaft. Default: 25
// r_loop1 = radius of the loop at the +Y end. Default: 5
// angle1 = arc angle in degrees for loop1. Default: 180
// l_stem1 = length of straight segment after loop1. Default: 0
// r_curl1 = radius of the reverse curl at the +Y end. Default: 0
// angle_curl1 = arc angle in degrees for curl1. Default: 0
// r_loop2 = radius of the loop at the -Y end. Default: 5
// angle2 = arc angle in degrees for loop2. Default: 180
// l_stem2 = length of straight segment after loop2. Default: 0
// r_curl2 = radius of the reverse curl at the -Y end. Default: 0
// angle_curl2 = arc angle in degrees for curl2. Default: 0
// anchor = Translate so anchor point is at origin (0,0,0). See [anchor](attachments.scad#subsection-anchor). Default: CENTER
// spin = Rotate this many degrees around the Z axis. See [spin](attachments.scad#subsection-spin). Default: 0
// orient = Vector to rotate top towards. See [orient](attachments.scad#subsection-orient). Default: UP
// Example(3D): Default S-hook with hexagonal cross-section
// s_hook();
// Example(3D): Circular cross-section
// s_hook(sides=0);
// Example(3D): Longer shaft
// s_hook(l_shaft=50);
// Example(3D): Larger loop on +Y end
// s_hook(r_loop1=12);
// Example(3D): Added stem on +Y end
// s_hook(l_stem1=5);
// Example(3D): Stem and curl on -Y end
// s_hook(l_stem2=4, r_curl2=5, angle_curl2=70);
// Example(3D): Extended arc with curl
// s_hook(sides=0, angle1=230, l_stem1=3, r_curl1=3, angle_curl1=90);
// Example(3D): Asymmetric hook
// s_hook(or=3, r_loop1=10, angle1=220, r_loop2=6, angle2=160, l_shaft=30);

function s_hook(or=2, sides=6, l_shaft=25,
r_loop1=5, angle1=180, l_stem1=0, r_curl1=0, angle_curl1=0,
r_loop2=5, angle2=180, l_stem2=0, r_curl2=0, angle_curl2=0,
anchor=CENTER, spin=0, orient=UP) = no_function("s_hook");
module s_hook(or=2, sides=6, l_shaft=25,
r_loop1=5, angle1=180, l_stem1=0, r_curl1=0, angle_curl1=0,
r_loop2=5, angle2=180, l_stem2=0, r_curl2=0, angle_curl2=0,
anchor=CENTER, spin=0, orient=UP)
{
dummy = assert(is_finite(l_shaft) && l_shaft > 0, "l_shaft must be positive")
assert(is_int(sides), "sides must be an integer")
assert(is_finite(or) && or > 0, "or must be positive")
assert(is_finite(r_loop1) && r_loop1 >= 0, "r_loop1 must be non-negative")
assert(is_finite(r_loop2) && r_loop2 >= 0, "r_loop2 must be non-negative")
assert(is_finite(angle1) && angle1 >= 0, "angle1 must be non-negative")
assert(is_finite(angle2) && angle2 >= 0, "angle2 must be non-negative");
_stem1 = max(l_stem1, 1e-10);
_stem2 = max(l_stem2, 1e-10);
shape = sides > 2 ? regular_ngon(sides, or, align_side=FWD) : circle(or);
path1 = turtle(["setdir", 90, "ymove", l_shaft/2,
"arcleft", r_loop1, angle1,
"move", _stem1,
"arcright", r_curl1, angle_curl1]);
path2 = turtle(["setdir", -90, "ymove", -l_shaft/2,
"arcleft", r_loop2, angle2,
"move", _stem2,
"arcright", r_curl2, angle_curl2]);
all_pts = concat(path1, path2);
bnds = pointlist_bounds(all_pts);
sz = [bnds[1].x - bnds[0].x + 2*or,
bnds[1].y - bnds[0].y + 2*or,
2*or];
off = [(bnds[0].x + bnds[1].x)/2,
(bnds[0].y + bnds[1].y)/2,
0];
endcap = right_half(shape);
anchors = [
named_anchor("loop1", point3d(last(path1)), UP),
named_anchor("loop2", point3d(last(path2)), DOWN),
named_anchor("shaft_top", [0, l_shaft/2, 0], BACK),
named_anchor("shaft_bot", [0, -l_shaft/2, 0], FWD),
];
attachable(anchor, spin, orient, size=sz, offset=off, anchors=anchors) {
union() {
path_sweep(shape, path1);
path_sweep(shape, path2);
move(last(path1)) rotate_sweep(endcap);
move(last(path2)) rotate_sweep(endcap);
}
children();
}
}


// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
Loading