@@ -999,7 +999,7 @@ module snap_pin_socket(size, r, radius, l,length, d,diameter,nub_depth, snap, fi
999999// Topics: Joiners, Parts
10001000// See Also: snap_pin(), joiner(), dovetail(), snap_pin(), rabbit_clip()
10011001// Usage:
1002- // rabbit_clip(type, length, width, snap, thickness, depth, [compression=], [clearance=], [lock=], [half_lock=], [double_single_lock=], [double_flip_half_lock=], [ lock_clearance=], [splineteps=], [anchor=], [orient=], [spin=]) [ATTACHMENTS];
1002+ // rabbit_clip(type, length, width, snap, thickness, depth, [compression=], [clearance=], [lock=], [lock_clearance=], [splineteps=], [anchor=], [orient=], [spin=]) [ATTACHMENTS];
10031003// Description:
10041004// Creates a clip with two flexible ears to lock into a mating socket, or create a mask to produce the appropriate
10051005// mating socket. The clip can be made to insert and release easily, or to hold much better, or it can be
@@ -1024,9 +1024,8 @@ module snap_pin_socket(size, r, radius, l,length, d,diameter,nub_depth, snap, fi
10241024// .
10251025// The first figure shows the dimensions of the rabbit clip. The second figure shows the clip in red overlayed on
10261026// its socket in yellow. The left clip has a nonzero clearance, so its socket is bigger than the clip all around.
1027- // The center locking clip has no clearance, but it has a lock clearance, which provides some space behind
1027+ // The right hand locking clip has no clearance, but it has a lock clearance, which provides some space behind
10281028// the lock to allow the clip to fit. (Note that depending on your printer, this can be set to zero.)
1029- // The right clip is half-locking that uses the same clearances as the center clip.
10301029// Figure(2DMed,NoAxes):
10311030// snap=1.5;
10321031// comp=0.75;
@@ -1058,13 +1057,6 @@ module snap_pin_socket(size, r, radius, l,length, d,diameter,nub_depth, snap, fi
10581057// Figure(2DMed,NoAxes):
10591058// snap=1.5;
10601059// comp=0;
1061- // translate([49,3]){
1062- // back_half()
1063- // rabbit_clip("socket", width=12, length=18, depth=1, thickness = 1, compression=comp, snap=snap, orient=BACK,half_lock=true);
1064- // color("red")back_half()
1065- // rabbit_clip("pin",width=12, length=18, depth=1, thickness = 1, compression=comp, snap=snap,
1066- // orient=BACK,half_lock=true,lock_clearance=1);
1067- // }
10681060// translate([29,3]){
10691061// back_half()
10701062// rabbit_clip("socket", width=12, length=18, depth=1, thickness = 1, compression=comp, snap=snap, orient=BACK,lock=true);
@@ -1090,10 +1082,7 @@ module snap_pin_socket(size, r, radius, l,length, d,diameter,nub_depth, snap, fi
10901082// ---
10911083// compression = excess width at the "ears" to lock more tightly. Default: 0.1
10921084// clearance = extra space in the socket for easier insertion. Default: 0.1
1093- // lock = set to true to make a locking clip that may be irreversible. Default: false
1094- // half_lock = set to true to make a clip where only the RIGHT side locks. Default: false
1095- // double_single_lock = for "double" type, set to true to enable lock or half_lock for one pin. Default: false
1096- // double_flip_half_lock = for "double", set to true to make TOP_RIGHT and BOTTOM_LEFT sides lock. Default: false
1085+ // lock = set to true to make a locking clip that may be irreversible. LEFT or RIGHT may be specified for all types to add a locking latch to just that side. For "double" type, TOP or BOTTOM is valid as well as a single corner (e.g. TOP+LEFT) or an array of corners or sides (e.g. [TOP, BOTTOM+RIGHT]). Default: false
10971086// lock_clearance = give clearance for the lock. Default: 0
10981087// splinesteps = number of samples in the curves of the clip. Default: 8
10991088// anchor = anchor point for clip
@@ -1142,53 +1131,64 @@ module snap_pin_socket(size, r, radius, l,length, d,diameter,nub_depth, snap, fi
11421131// tag("remove")zcyl(l=20,r=13.5, $fn=64);
11431132// }
11441133
1145- function rabbit_clip(type, length, width, snap, thickness, depth, compression= 0.1 , clearance= .1 , lock= false , half_lock = false , double_single_lock = false , double_flip_half_lock = false , lock_clearance= 0 ,
1134+ function rabbit_clip(type, length, width, snap, thickness, depth, compression= 0.1 , clearance= .1 , lock= false , lock_clearance= 0 ,
11461135 splinesteps= 8 , anchor, orient, spin= 0 ) = no_function("rabbit_clip" );
11471136
1148- module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1, clearance=.1, lock=false, half_lock=false, double_single_lock=false, double_flip_half_lock=false, lock_clearance=0,
1137+ module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1, clearance=.1, lock=false, lock_clearance=0,
11491138 splinesteps= 8 , anchor, orient, spin= 0 )
11501139{
11511140 legal_types = ["pin" ,"socket" ,"male" ,"female" ,"double" ];
1141+
1142+ // TOP, BOTTOM, LEFT, RIGHT, or any corner thereof
1143+ function valid_edge_or_corner(v) = same_shape(v, TOP) && v[1 ] == 0 && (abs (v[0 ]) == 1 || abs (v[2 ]) == 1 );
1144+ function valid_edge_or_corner_vector(v) = is_consistent(v, TOP) && all( [for (i = v) valid_edge_or_corner(i)] );
1145+ function valid_double_lock() = valid_edge_or_corner(lock) || valid_edge_or_corner_vector(lock);
1146+ function valid_lock() = is_bool(lock) || lock == LEFT || lock == RIGHT || (type == "double" && valid_double_lock());
11521147 check =
11531148 assert(is_num(width) && width> 0 ,"Width must be a positive value" )
11541149 assert(is_num(length) && length> 0 , "Length must be a positive value" )
11551150 assert(is_num(thickness) && thickness> 0 , "Thickness must be a positive value" )
11561151 assert(is_num(snap) && snap>= 0 , "Snap must be a non-negative value" )
11571152 assert(is_num(depth) && depth> 0 , "Depth must be a positive value" )
11581153 assert(is_num(compression) && compression >= 0 , "Compression must be a nonnegative value" )
1159- assert(is_bool(lock))
1160- assert(is_bool(half_lock))
1161- assert(! (lock && half_lock), "Only one of lock and half_lock can be set" )
1162- assert(is_bool(double_single_lock))
1163- assert(is_bool(double_flip_half_lock))
1164- assert(! (double_single_lock && double_flip_half_lock), "Only one of double_single_lock and double_flip_half_lock can be set" )
1165- assert(! (lock && double_flip_half_lock), "double_flip_half_lock can not be used with lock" )
11661154 assert(is_num(lock_clearance))
1155+ assert(valid_lock(), "Invalid lock value" )
11671156 assert(in_list(type,legal_types),str ("type must be one of " ,legal_types));
1168- assert(! double_single_lock || type == "double" , "double_single_lock can only be used with double" );
1169- assert(! double_flip_half_lock || type == "double" , "double_single_lock can only be used with double" );
1170- module double_lock() {
1171- if ( half_lock )
1157+
1158+ module apply_lock() {
1159+ if ( lock == RIGHT )
11721160 children();
1173- else
1174- xflip_copy ()
1161+ else if ( lock == LEFT )
1162+ xflip ()
11751163 children();
1176- }
1177- module double_pin() {
1178- if ( half_lock && ! double_flip_half_lock )
1179- zrot(180 )
1164+ else if ( lock )
1165+ xflip_copy()
11801166 children();
1181- else
1182- children();
1167+ // ignore children otherwise
11831168 }
1169+
1170+ function is_edge_or_corner(v, e1, e2) = v == e1 || v == e2 || v == e1 + e2;
1171+ function relative_lock_vector_value(edge) = let(left = len([for (v = lock) if (is_edge_or_corner(v, LEFT, edge)) v]) > 0 ,
1172+ right = len([for (v = lock) if (is_edge_or_corner(v, RIGHT, edge)) v]) > 0 )
1173+ left && right ? true :
1174+ left ? LEFT :
1175+ right ? RIGHT :
1176+ false ;
1177+ function relative_lock_value(edge) = is_bool(lock) ? lock :
1178+ lock == TOP || lock == BOTTOM ? lock == edge :
1179+ lock == LEFT || lock == RIGHT ? lock :
1180+ same_shape(lock, TOP) && lock * edge == 1 ? lock - edge :
1181+ relative_lock_vector_value(edge);
1182+
11841183 if (type== "double" ) {
11851184 attachable(size= [width+ 2 * compression, depth, 2 * length], anchor= default(anchor,BACK), spin= spin, orient= default(orient,BACK)){
11861185 union (){
11871186 rabbit_clip("pin" , length= length, width= width, snap= snap, thickness= thickness, depth= depth, compression= compression,
1188- lock= lock || double_single_lock, half_lock= half_lock || double_flip_half_lock, lock_clearance= lock_clearance, anchor= BOTTOM, orient= UP);
1189- double_pin()
1187+ lock= relative_lock_value(TOP), lock_clearance= lock_clearance, anchor= BOTTOM, orient= UP);
1188+ bottom_lock = relative_lock_value(BOTTOM);
1189+ // the bottom pin is rotated when it is attached, so it needs to be flipped when applying LEFT or RIGHT
11901190 rabbit_clip("pin" , length= length, width= width, snap= snap, thickness= thickness, depth= depth, compression= compression,
1191- lock= lock && ! double_single_lock, half_lock = half_lock || double_flip_half_lock , lock_clearance= lock_clearance, anchor= BOTTOM, orient= DOWN);
1191+ lock= is_bool(bottom_lock) ? bottom_lock : xflip(bottom_lock) , lock_clearance= lock_clearance, anchor= BOTTOM, orient= DOWN);
11921192 cuboid([width- thickness, depth, thickness]);
11931193 }
11941194 children();
@@ -1257,8 +1257,7 @@ module rabbit_clip(type, length, width, snap, thickness, depth, compression=0.1
12571257 xrot(90 )
12581258 translate ([0 ,- (bounds[1 ].y- bounds[0 ].y)/2 + default_overlap,- depth/2 ])
12591259 linear_extrude(height= depth, convexity= 10 ) {
1260- if (lock || half_lock)
1261- double_lock()
1260+ apply_lock()
12621261 right(clearance)
12631262 polygon([sidepath[1 ]+ [- thickness/10 ,lock_clearance],
12641263 sidepath[2 ]- [thickness* .75 ,0 ],
0 commit comments