diff --git a/T-riple.scad b/T-riple.scad index 2ced996..a06351e 100644 --- a/T-riple.scad +++ b/T-riple.scad @@ -6,7 +6,8 @@ octave_strings = ["", "˙", "¨", "¯"]; octave_scales = [1.1, 1, 0.9, 0.8]; z_resolution = $preview ? 0.5 : 0.1; -profile_arc_steps = $preview ? 10 : 180; +profile_arc_steps_backside = $preview ? 8 : 180; +profile_arc_steps_topside = $preview ? 8 : 20; // $fn = $preview ? 32 : 512; // mink_fn = $preview ? 12 : 128; // mink_fn_2d = $preview ? 32 : 256; @@ -20,13 +21,22 @@ zero_fret_extra_height = 1.2; fret_angle = 60; //Fret angle of 45° is normal, anything over 60 will not work correctly tube_radius = Cap_Spine + T_circumcenter[0]; standard_profile_center_x = T_circumcenter[0]; +x_min = standard_profile_center_x - tube_radius; +standard_y_width = 26.4517; module tube(from_fret, to_fret, scale_offset = 0, fingerboard_min_thick = 2.5, fingerboard_max_thick = 5) { - function fsl(fret_number) = fret_scale_length(fret_number + scale_offset); - // z_min = (fsl(to_fret) + fsl(to_fret+1))/2; - // z_max = (fsl(from_fret) + fsl(from_fret-1))/2; + z0 = fsl(0); + function get_desired_width_scale(z) = 2.0-(z/z0); + function get_desired_profile_radius(ws) = + let ( + x = fingerboard_max_thick, + y = standard_y_width*0.5*ws, + cc = tri_circumcenter([[x, -y], [x, y], [x_min, 0]]) + ) + cc[0]-x_min; + z_min = fsl(to_fret) - fret_width/2; z_max = fsl(from_fret) + zero_fret_width/2; z_offset = z_min; @@ -42,28 +52,28 @@ module tube(from_fret, to_fret, scale_offset = 0, fingerboard_min_thick = 2.5, f nearest_fret_mm = fsl(nearest_fret) ) z; - module outline_xy(profile_radius_scale = 1.0, x_max = fingerboard_max_thick, rounding_radius = 1.5) { - profile_radius = profile_radius_scale * tube_radius; + module outline_xy(width_scale = 1.0, x_max = fingerboard_max_thick, rounding_radius = 1.5, backside = true, topside = true) { + profile_radius = get_desired_profile_radius(width_scale); + profile_radius_scale = profile_radius / tube_radius; profile_center_x = (profile_radius_scale-1.0)*tube_radius + standard_profile_center_x; - // minkowski method does exactly what we want, but it is slow (sweep a circle around the outline) - // minkowski($fn = mink_fn_2d) { - // circle(r = rounding_radius); - // difference() { - // translate([profile_center_x, 0, 0]) circle(r = tube_radius*profile_radius_scale - rounding_radius); - // translate([fingerboard_max_thick - rounding_radius, -50]) square([100,100]); - // } - // } - // make a circle and chop the top off (no edge rounding) - // difference() { - // translate([profile_center_x, 0, 0]) circle(r = profile_radius); - // translate([x_max, -50]) square([100,100]); - // } - a_start = acos((x_max-profile_center_x)/profile_radius); - a_end = 360 - a_start; - a_step = (a_end - a_start)/profile_arc_steps; - echo(str("profile_radius_scale is ", profile_radius_scale, " profile_center_x is ", profile_center_x, " a_start is ", a_start, " a_end is ", a_end)); + + // Backside should join up relatively straight across the whole mesh + a_backside_start = acos((-2-profile_center_x)/profile_radius); + a_backside_end = 360 - a_backside_start; + a_backside_step = (a_backside_end - a_backside_start)/profile_arc_steps_backside; + // Frontside should have very detailed topology + a_topside_start = acos((x_max-profile_center_x)/profile_radius); + a_topside_end = 360 - a_topside_start; + a_topside_step = (a_backside_start - a_topside_start)/profile_arc_steps_topside; + function pt(a) = [profile_center_x + profile_radius*cos(a), profile_radius*sin(a)]; - polygon(points = [for (i = [0:profile_arc_steps]) pt(a_start + i*a_step)]); + backside_points = backside ? [for (i = [0:profile_arc_steps_backside]) pt(a_backside_start + i*a_backside_step)] : []; + topside_points_1 = topside ? [for (i = [0:profile_arc_steps_topside]) pt(a_topside_start + i*a_topside_step)] : []; + topside_points_2 = topside ? [for (i = [0:profile_arc_steps_topside]) pt(a_backside_end + i*a_topside_step)] : []; + polygon(points = concat(topside_points_1, backside_points, topside_points_2)); + + top_width = pt(a_topside_start)[1] * 2; + echo(str("WScale=", width_scale, " PScale=", profile_radius_scale, " r=", profile_radius, " has top width of ", top_width, " divides to ", top_width/width_scale, " (goal is 26.4517)")); } module fret_bumps(w=100) { translate([fingerboard_max_thick - fret_width/2, w/2, -z_offset + fsl(from_fret)]) @@ -98,8 +108,8 @@ module tube(from_fret, to_fret, scale_offset = 0, fingerboard_min_thick = 2.5, f module basic_fretboard() { intersection() { hull() { - translate([0,0,Cap_Length]) linear_extrude(0.001) outline_xy(1.0); - translate([0,0,0]) linear_extrude(0.001) outline_xy(1.75); + translate([0,0,Cap_Length]) linear_extrude(0.001) outline_xy(get_desired_width_scale(z_max), topside=true); + translate([0,0,0]) linear_extrude(0.001) outline_xy(get_desired_width_scale(z_min), topside=true); } union() { color("black") fret_bumps(); @@ -119,25 +129,37 @@ module tube(from_fret, to_fret, scale_offset = 0, fingerboard_min_thick = 2.5, f // color("red") scallops(); } + module fret_number_markers(engrave_depth=1) { + color("purple") + // for (fret = [from_fret:to_fret]) + for (fret = [from_fret+1:to_fret]) { + zn = fsl(fret); + pr = get_desired_profile_radius(get_desired_width_scale(zn)); + octave = floor(fret/12); + semitone = fret%12; + octave_scale = octave_scales[octave]; + // translate([-3,-16,zn-z_offset]) rotate([90,25,16]) linear_extrude(100) { + // translate([-3,-16,zn-z_offset]) rotate([90,25,-16+16*(zn/z0)]) linear_extrude(100) { + p_x0 = pr+x_min; + translate([p_x0, 0, zn-z_offset]) rotate([90,25,-asin((p_x0+2)/pr)]) translate([0, 0, pr-engrave_depth]) linear_extrude(engrave_depth+1) { + text(semitone_strings[semitone], size=4*octave_scale, halign="center", valign="center", font="Noto Sans"); + text(octave_strings[octave], size=6*octave_scale, halign="center", valign="center", font="Noto Sans"); + } + translate([p_x0, 0, zn-z_offset]) rotate([90,-25,180+asin((p_x0+2)/pr)]) translate([0, 0, pr-engrave_depth]) linear_extrude(engrave_depth+1) { + text(semitone_strings[semitone], size=4*octave_scale, halign="center", valign="center", font="Noto Sans"); + text(octave_strings[octave], size=6*octave_scale, halign="center", valign="center", font="Noto Sans"); + } + } + } + difference() { solid_tube(1.5); linear_extrude(Cap_Length) T_hole(); + fret_number_markers(); tapered_T_hole(z0 = 0, z1 = 3); tapered_T_hole(z0 = Cap_Length-3, z1 = Cap_Length+0.0001, o0 = 0, o1 = 1); // Version number translate([-10,10,Cap_Length-0.5]) linear_extrude(1) text("06", size=5, halign="center", valign="center", font="Noto Sans"); - // Fret number markers - color("black") - // for (fret = [from_fret:to_fret]) - for (fret = [from_fret+1:to_fret]) - translate([-3,-16,fsl(fret)-z_offset]) rotate([90,25,16]) linear_extrude(40) { - octave = floor(fret/12); - semitone = fret%12; - octave_scale = octave_scales[octave]; - - text(semitone_strings[semitone], size=4*octave_scale, halign="center", valign="center", font="Noto Sans"); - text(octave_strings[octave], size=6*octave_scale, halign="center", valign="center", font="Noto Sans"); - } } }