diff --git a/joiners.scad b/joiners.scad index a3cc636..3e18ae0 100644 --- a/joiners.scad +++ b/joiners.scad @@ -419,7 +419,7 @@ module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=unde // Module: dovetail() // // Usage: -// dovetail(l|length, h|height, w|width, slope|angle, taper|back_width, [chamfer], [r|radius], [round], [$slop]) +// dovetail(gender, l|length, h|height, w|width, [slope|angle], [taper|back_width], [chamfer], [r|radius], [round], [$slop]) // // Description: // Produces a possibly tapered dovetail joint shape to attach to or subtract from two parts you wish to join together. @@ -427,11 +427,13 @@ module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=unde // it is fully closed, and then wedges tightly. You can chamfer or round the corners of the dovetail shape for better // printing and assembly, or choose a fully rounded joint that looks more like a puzzle piece. The dovetail appears // parallel to the Y axis and projecting upwards, so in its default orientation it will slide together with a translation -// in the positive Y direction. The default anchor for dovetails is BOTTOM; the default orientation depends on the gender, -// with male dovetails oriented UP and female ones DOWN. +// in the positive Y direction. The gender determines whether the shape is meant to be added to your model or +// differenced, and it also changes the anchor and orientation. The default anchor for dovetails is BOTTOM; +// the default orientation depends on the gender, with male dovetails oriented UP and female ones DOWN. // // Arguments: -// gender = A string, "male" or "female", to specify the gender of the dovetail. +// gender = A string, "male" or "female", to specify the gender of the dovetail. +// --- // l / length = Length of the dovetail (amount the joint slides during assembly) // h / height = Height of the dovetail // w / width = Width (at the wider, top end) of the dovetail before tapering @@ -487,9 +489,9 @@ module joiner_quad(spacing1=undef, spacing2=undef, xspacing=undef, yspacing=unde // diff("remove") // cuboid([50,30,10]) // attach(TOP) dovetail("female", length=50, width=18, height=4, back_width=15, spin=90,$tags="remove"); -// Example: A series of dovtails +// Example: A series of dovtails forming a tail board, with the inside of the joint up. A standard wood joint would have a zero taper. // cuboid([50,30,10]) -// attach(BACK) xcopies(10,5) dovetail("male", length=10, width=7, height=4); +// attach(BACK) xcopies(10,5) dovetail("male", length=10, width=7, taper=4, height=4); // Example: Mating pin board for a right angle joint. Note that the anchor method and use of `spin` ensures that the joint works even with a taper. // diff("remove") // cuboid([50,30,10]) @@ -765,8 +767,7 @@ module snap_pin_socket(size, r, radius, l,length, d,diameter,nub_depth, snap, fi { down(lPin/2) intersection() { - if (fixed) - cube([3 * (radius + snap), radius * sqrt(2), 3 * lPin + 3 * radius], center = true); + cube([3 * (radius + snap), fixed ? radius * sqrt(2) : 3*(radius+snap), 3 * lPin + 3 * radius], center = true); union() { _pin_shaft(radius,lStraight,snap,1,1,nub_depth,pointed); if (fins) diff --git a/regions.scad b/regions.scad index 7c4d773..f2e97e0 100644 --- a/regions.scad +++ b/regions.scad @@ -533,7 +533,7 @@ function _offset_region( difference(_acc, [ offset( paths[_i].y, - r=-r, delta=-delta, chamfer=chamfer, closed=closed, + r=u_mul(-1,r), delta=u_mul(-1,delta), chamfer=chamfer, closed=closed, maxstep=maxstep, check_valid=check_valid, quality=quality, return_faces=return_faces, firstface_index=firstface_index, flip_faces=flip_faces @@ -547,11 +547,14 @@ function _offset_region( // Function: offset() -// +// Usage: +// offsetpath = offset(path, [r|delta], [chamfer], [closed], [check_valid], [quality]) +// path_faces = offset(path, return_faces=true, [r|delta], [chamfer], [closed], [check_valid], [quality], [firstface_index], [flip_faces]) // Description: // Takes an input path and returns a path offset by the specified amount. As with the built-in // offset() module, you can use `r` to specify rounded offset and `delta` to specify offset with -// corners. Positive offsets shift the path to the left (relative to the direction of the path). +// corners. If you used `delta` you can set `chamfer` to true to get chamfers. +// Positive offsets shift the path to the left (relative to the direction of the path). // . // When offsets shrink the path, segments cross and become invalid. By default `offset()` checks // for this situation. To test validity the code checks that segments have distance larger than (r @@ -570,6 +573,7 @@ function _offset_region( // value is a list: [offset_path, face_list]. // Arguments: // path = the path to process. A list of 2d points. +// --- // r = offset radius. Distance to offset. Will round over corners. // delta = offset distance. Distance to offset with pointed corners. // chamfer = chamfer corners when you specify `delta`. Default: false @@ -643,7 +647,7 @@ function offset( maxstep=0.1, closed=false, check_valid=true, quality=1, return_faces=false, firstface_index=0, flip_faces=false -) = +) = echo(path=path) is_region(path)? ( assert(!return_faces, "return_faces not supported for regions.") let( @@ -687,23 +691,19 @@ function offset( (len(sharpcorners)==2 && !closed) || all_defined(select(sharpcorners,closed?0:1,-1)) ) - assert(parallelcheck, "Path turns back on itself (180 deg turn)") + assert(parallelcheck, "Path contains sequential parallel segments (either 180 deg turn or 0 deg turn") let( // This is a boolean array that indicates whether a corner is an outside or inside corner // For outside corners, the newcorner is an extension (angle 0), for inside corners, it turns backward // If either side turns back it is an inside corner---must check both. // Outside corners can get rounded (if r is specified and there is space to round them) - outsidecorner = [ - for(i=[0:len(goodsegs)-1]) let( - prevseg=select(goodsegs,i-1) - ) ( - (goodsegs[i][1]-goodsegs[i][0]) * - (goodsegs[i][0]-sharpcorners[i]) > 0 - ) && ( - (prevseg[1]-prevseg[0]) * - (sharpcorners[i]-prevseg[1]) > 0 - ) - ], + outsidecorner = len(sharpcorners)==2 ? [false,false] + : + [for(i=[0:len(goodsegs)-1]) + let(prevseg=select(goodsegs,i-1)) + (goodsegs[i][1]-goodsegs[i][0]) * (goodsegs[i][0]-sharpcorners[i]) > 0 + && (prevseg[1]-prevseg[0]) * (sharpcorners[i]-prevseg[1]) > 0 + ], steps = is_def(delta) ? [] : [ for(i=[0:len(goodsegs)-1]) r==0 ? 0 :