diff --git a/bottlecaps.scad b/bottlecaps.scad index a3cb99e2..e3de5372 100644 --- a/bottlecaps.scad +++ b/bottlecaps.scad @@ -467,7 +467,6 @@ module generic_bottle_neck( roundover = 0.58 * diamMagMult; lip_roundover_r = (roundover > (neck_d - inner_d) / 2) ? 0 : roundover; h = height + support_width; - echo(h=h); threadbase_d = neck_d - 0.8 * diamMagMult; $fn = segs(33 / 2); @@ -693,14 +692,12 @@ module bottle_adapter_neck_to_cap( : neck_support_od; cap_neck_id = default(cap_neck_id,neck_id); wall = default(wall, neck_support_od + neck_d + cap_od + neck_id - 2*tolerance); - echo(wall=wall); $fn = segs(33 / 2); wallt1 = min(wall, (max(neck_support_od, neck_d) - neck_id) / 2); wallt2 = min(wall, (cap_od + 2 * cap_wall - cap_neck_id) / 2); top_h = neck_h + max(1,neck_h/17)*sign(neck_support_od); - echo(top_h=top_h); bot_h = cap_h + cap_wall; attachable(anchor=anchor,orient=orient,spin=spin, r=max([neck_id/2+wallt1, cap_neck_id/2+wallt2, neck_support_od/2]), h=top_h+bot_h+d) { zmove((bot_h-top_h)/2) @@ -1298,7 +1295,6 @@ module sp_cap(diam,type,wall,style="L",top_adj=0, bot_adj=0, texture="none", anc twist = struct_val(_sp_twist, type); - echo(top_adj=top_adj,bot_adj=bot_adj); dum3=assert(top_adj0 && mask_angle<180) assert(is_finite(inset)||is_vector(inset,2)) assert(is_bool(quarter_round)) let(flat_top=default(flat_top, quarter_round)) assert(is_bool(flat_top)) + assert(is_undef(clip_angle) || (is_finite(clip_angle) && clip_angle<=90 && clip_angle>(quarter_round?90:mask_angle)-90), + str("\nclip_angle must be between ",(quarter_round?90:mask_angle)-90," and 90")) let( inset = is_list(inset)? inset : [inset,inset], r = get_radius(r=r,d=d,dflt=undef), dummy2=assert(is_def(r) || !quarter_round,"Must give r / d when quarter_round is true"), - h = u_add(one_defined([h,height],"h,hight",dflt=undef),flat_top || mask_angle>=90?0:-inset.x*cos(mask_angle)), + h = u_add(one_defined([h,height],"h,hight",dflt=undef),flat_top || mask_angle>=90?0:-inset.x*cos(mask_angle)), // compute [joint length, radius] for different types of input - jr = is_def(h) ? assert(all_positive([h]), "height / h must be larger than y inset") - h/sin(mask_angle)*[1,tan(mask_angle/2)] - : is_def(r) ? assert(all_positive([r]), "r / d must be a positive value") - [r/tan(mask_angle/2), r] - : is_def(joint) ? assert(all_positive([joint]), "joint must be a positive value") - joint*[1, tan(mask_angle/2)] - : assert(all_positive([cut]),"cut must be a positive value") - let(circ_radius=cut/(1/sin(mask_angle/2)-1)) - [circ_radius/tan(mask_angle/2), circ_radius], - dist=jr[0], - radius=jr[1], + rcalc = is_def(r) ? assert(all_positive([r]), "r / d must be a positive value") r + : is_def(joint) ? assert(all_positive([joint]), "joint must be a positive value") joint*tan(mask_angle/2) + : is_def(cut) ? assert(all_positive([cut]),"cut must be a positive value") cut/(1/sin(mask_angle/2)-1) + : undef, + jra = is_def(clip_angle)? + assert(num_defined([rcalc,h])==1, "When clip_angle is given must give exactly one of r, joint, h/height, or cut") + let( r = is_def(rcalc) ? rcalc + : h/(sin(mask_angle)/tan(mask_angle/2)-1+sin(clip_angle)) + ) + [r/tan(mask_angle/2), r, clip_angle] + : num_defined([rcalc,h])==2 ? let( a=-sin(mask_angle)/tan(mask_angle/2)+1) + assert(h/rcalc + a <= 1,str("\nheight cannot be larger than ", rcalc*(1-a))) + [rcalc/tan(mask_angle/2) ,rcalc, asin(h/rcalc + a)] + : is_def(rcalc) ? [rcalc/tan(mask_angle/2), rcalc, 90] + : [ each h/sin(mask_angle)*[1,tan(mask_angle/2)], 90], + dist=jra[0], + radius=jra[1], + clip_angle = jra[2], + + clipshift = clip_angle==90 ? [0,0] + : let( v=1-cos(90-clip_angle)) + radius*[v/tan(mask_angle),v], quarter_round_top = approx(mask_angle,90) ? 0 - : radius/tan(mask_angle), + : radius/tan(mask_angle), extra = radius/20, // Exact solution is tangent, which will make bad geometry, so insert an offset factor quarter_round_shift = !quarter_round || mask_angle<=90 ? 0 - : radius/sin(180-mask_angle)-radius+extra, + : radius/sin(180-mask_angle)-radius+extra, outside_corner = _inset_corner( quarter_round ? [ @@ -188,18 +215,26 @@ function mask2d_roundover(r, inset=0, mask_angle=90, excess=0.01, flat_top, quar outside_corner[1][2] ], dummy=assert(last(cornerpath).x>=0,str("inset.y is too large to fit roundover at angle ",mask_angle)), - path = deduplicate([ - each outside_corner[0], - outside_corner[1][0], - each arc(corner=cornerpath, r=radius), - outside_corner[1][2] + arcpath = let (basic = arc(corner=cornerpath, r=radius)) + clip_angle==90 ? basic + : + let( + cutind = [for(i=idx(basic)) if (basic[i].y-inset.y < clipshift.y) i], + ipt = line_intersection([basic[cutind[0]-1],basic[cutind[0]]], [[0,clipshift.y+inset.y],[1,clipshift.y+inset.y]]) + ) + move(-clipshift, [ each select(basic, 0,cutind[0]), ipt]), + path = deduplicate([ + [last(arcpath).x,-excess], + outside_corner[0][1], + move(-clipshift, outside_corner[0][2]), + each arcpath, + [last(arcpath).x,inset.y] ] ,closed=true) ) reorient(anchor,spin, two_d=true, path=path, extent=false, p=path); - // Function&Module: mask2d_teardrop() // Synopsis: Creates a 2D teardrop shape with specified max angle from vertical. // SynTags: Geom, Path @@ -615,7 +650,7 @@ function mask2d_chamfer(edge, angle, inset=0, excess=0.01, mask_angle=90, flat_t : is_def(x) ? assert(num_defined([y,edge,angle])<=1, "Conflicting values of x, y, height, edge and angle given") ( is_def(y) ? [x,y] - : is_def(edge) ? let(yopt=quadratic_roots(1,-2*x*cos(mask_angle), x^2-edge^2,real=true),fff=echo(yopt)) + : is_def(edge) ? let(yopt=quadratic_roots(1,-2*x*cos(mask_angle), x^2-edge^2,real=true)) assert(yopt!=[] && max(yopt)>0, "edge too short for x value") [x,max(yopt)] : let(angle=default(angle,mask_angle/2))