Fender_Scale_mm = 648; // Actually 25.5inch = 647.7mm Classical_Normal_Scale_mm = 650; // about 25.59inch Classical_Short_Scale_mm = 635; // = 25inch Gibson_Scale_mm = 630; // 24.75inch = 628.65mm Guitar_Scale_Length_mm = Fender_Scale_mm; ln2 = ln(2); function log2(x) = ln(x)/ln2; function fret_scale_length(n) = Guitar_Scale_Length_mm * 2^(-n/12); function mm_to_fret_number(mm) = -log2(mm/Guitar_Scale_Length_mm)*12; function lerp(start, end, amount) = start + (end-start)*amount; function clamp(minimum, value, maximum) = min(max(minimum, value), maximum); function flatten(l) = [ for (a = l) for (b = a) b]; function tri_circumcenter(pts) = let( v0 = pts[1] - pts[0], v1 = pts[2] - pts[1], d0 = (pts[1] + pts[0])/2 * v0, d1 = (pts[2] + pts[1])/2 * v1, det = -cross(v0, v1) ) [cross([d1, d0], [v1.y, v0.y]), cross([d0, d1], [v0.x, v1.x])] / det; // Create a circle containing all 3 points, then plot the arc between the first two points function arc_points(tri_points, fragments_per_mm=5) = let( cc = tri_circumcenter(tri_points), r = norm(tri_points[0] - cc), steps = ceil((norm(tri_points[2] - tri_points[0]) + norm(tri_points[2] - tri_points[1]))*fragments_per_mm), normalized0 = (tri_points[0] - cc)/r, normalized1 = (tri_points[1] - cc)/r, a_start = atan2(normalized0[1], normalized0[0]), a_end = atan2(normalized1[1], normalized1[0]), a_sweep = a_end - a_start, a_step = a_sweep/steps ) [for (i = [0:steps]) r*[cos(a_start+i*a_step), sin(a_start+i*a_step)] + cc]; function list_has(list, value) = len(search(value, list)) > 0; module round_cube(size, r) { translate([r, r, r]) minkowski() { cube(size-[r*2,r*2,r*2]); sphere(r=r, $fn=72); } } module rotate_around(angles, pt) { translate(pt) rotate(angles) translate(-pt) children(); } module screw_hole_lobe(ID, OD, lobes=3, fn=90) { difference() { circle(d=OD, $fn=fn); for (a=[0:360/lobes:360]) translate((OD/2)*[cos(a), sin(a)]) circle(d=OD-ID, $fn=fn); } } module cylinder_beak(d, h, beak=0.75) { // A cylinder with a beak to take seams. This helps improve tolerances as seams often expand a little bit and ruin the fit. cylinder(d=d, h=h); // beak notch for seams translate([0, d/2-beak*0.25, h/2]) rotate([0,0,45]) cube([beak, beak, h], center=true); } // We can't use Droid Sans Japanese because the rendering library is really dumb and will pick the wrong Droid Sans. CJK fonts must be singular files. JP_Serif_Font = "New Tegomin"; JP_Sans_Font = "Yuji Boku"; JP_Fat_Sans_Font = ["Potta One", "Yusei Magic"]; JP_Light_Sans_Fonts = ["Hachi Maru Pop", "MotoyaLMaru", "Rounded MPlus 1c"];