diff --git a/global_defs.scad b/global_defs.scad index 1d015fd..1922091 100644 --- a/global_defs.scad +++ b/global_defs.scad @@ -39,6 +39,7 @@ pp2_colour = is_undef($pp2_colour) ? "red" : $pp2_colour; // pri pp3_colour = is_undef($pp3_colour) ? "blue" : $pp3_colour; // printed part colour 3 pp4_colour = is_undef($pp4_colour) ? "darkorange" : $pp4_colour;// printed part colour 4 show_rays = is_undef($show_rays) ? false : $show_rays; // show camera sight lines and light direction +show_threads = is_undef($show_threads) ? false : $show_threads; // show screw threads // Minimum wall is about two filaments wide but we extrude it closer to get better bonding squeezed_wall = $preview ? 2 * extrusion_width - layer_height * (1 - PI / 4) @@ -59,7 +60,8 @@ grey60 = [0.6, 0.6, 0.6]; grey70 = [0.7, 0.7, 0.7]; grey80 = [0.8, 0.8, 0.8]; grey90 = [0.9, 0.9, 0.9]; -brass = "gold"; +brass = [255/255, 215/255, 0/255]; +silver = [0.75, 0.75, 0.75]; /* * Enums diff --git a/lib.scad b/lib.scad index 26faf3c..6c0dda5 100644 --- a/lib.scad +++ b/lib.scad @@ -90,3 +90,4 @@ use use use use +use diff --git a/scripts/views.py b/scripts/views.py index ab2d8c7..ec0f1aa 100755 --- a/scripts/views.py +++ b/scripts/views.py @@ -154,7 +154,7 @@ def views(target, do_assemblies = None): f.write("use <%s/%s>\n" % (dir, filename)) f.write("%s();\n" % module); # - # Run openscad on th created file + # Run openscad on the created file # dname = deps_name(deps_dir, filename) for explode in [0, 1]: @@ -167,7 +167,7 @@ def views(target, do_assemblies = None): if changed: print(changed) t = time.time() - openscad.run("-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, png_maker_name); + openscad.run("-D$show_threads=1", "-D$pose=1", "-D$explode=%d" % explode, colour_scheme, "--projection=p", "--imgsize=4096,4096", "--autocenter", "--viewall", "-d", dname, "-o", tmp_name, png_maker_name); times.add_time(png_name, t) do_cmd(["magick", tmp_name, "-trim", "-resize", "1004x1004", "-bordercolor", background, "-border", "10", tmp_name]) update_image(tmp_name, png_name) diff --git a/tests/d_connectors.scad b/tests/d_connectors.scad index 3398208..f2d0016 100644 --- a/tests/d_connectors.scad +++ b/tests/d_connectors.scad @@ -35,4 +35,5 @@ module d_connectors() } if($preview) - d_connectors(); + let($show_threads = true) + d_connectors(); diff --git a/tests/pillars.scad b/tests/pillars.scad index 828efee..d3c51a9 100644 --- a/tests/pillars.scad +++ b/tests/pillars.scad @@ -26,4 +26,5 @@ module pillars() pillar(pillars[$i]); if($preview) - pillars(); + let($show_threads = true) + pillars(); diff --git a/tests/png/d_connectors.png b/tests/png/d_connectors.png index f58e1c2..9f9a617 100644 Binary files a/tests/png/d_connectors.png and b/tests/png/d_connectors.png differ diff --git a/tests/png/pillars.png b/tests/png/pillars.png index 730b429..055f34f 100644 Binary files a/tests/png/pillars.png and b/tests/png/pillars.png differ diff --git a/tests/png/rod.png b/tests/png/rod.png index 8bfea67..bd416ed 100644 Binary files a/tests/png/rod.png and b/tests/png/rod.png differ diff --git a/tests/png/screws.png b/tests/png/screws.png index 2cc53c4..1eac829 100644 Binary files a/tests/png/screws.png and b/tests/png/screws.png differ diff --git a/tests/rod.scad b/tests/rod.scad index 0e25577..c84287f 100644 --- a/tests/rod.scad +++ b/tests/rod.scad @@ -33,4 +33,5 @@ module rods() } if($preview) - rods(); + let($show_threads = true) + rods(); diff --git a/tests/screws.scad b/tests/screws.scad index 37b22be..744e8fb 100644 --- a/tests/screws.scad +++ b/tests/screws.scad @@ -34,4 +34,5 @@ for(y = [0 : len(screw_lists) -1]) } if($preview) - screws(); + let($show_threads = true) + screws(); diff --git a/utils/core/global.scad b/utils/core/global.scad index 7b58412..e74b037 100644 --- a/utils/core/global.scad +++ b/utils/core/global.scad @@ -43,7 +43,7 @@ module ellipse(xr, yr) scale([1, yr / xr]) circle4n(xr); module extrude_if(h, center = true) //! Extrudes 2D object to 3D when ```h``` is nonzero, otherwise leaves it 2D if(h) - linear_extrude(height = h, center = center) // 3D + linear_extrude(height = h, center = center, convexity = 2) // 3D children(); else children(); // 2D diff --git a/utils/thread.scad b/utils/thread.scad new file mode 100644 index 0000000..25b2eaa --- /dev/null +++ b/utils/thread.scad @@ -0,0 +1,114 @@ +// +// NopSCADlib Copyright Chris Palmer 2019 +// nop.head@gmail.com +// hydraraptor.blogspot.com +// +// This file is part of NopSCADlib. +// +// NopSCADlib is free software: you can redistribute it and/or modify it under the terms of the +// GNU General Public License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// NopSCADlib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with NopSCADlib. +// If not, see . +// + +// +//! A utilities for making threads with sweep. +// +include <../core.scad> +use +use + +function thread_profile(h, crest, angle) = //! Create thread profile path + let(base = crest + 2 * h * tan(angle / 2)) + [[-base / 2, 0, 0], [-crest / 2, h, 0], [crest / 2, h, 0], [base / 2, 0, 0]]; + +module male_thread(pitch, minor_d, length, profile, taper_top = true, center = true, solid = true) { //! Create male thread + turns = length / pitch + (taper_top ? 0 : 1); + r = minor_d / 2; + sides = r2sides(r); + h = max([for(p = profile) p.y]); + final = (turns - 1) * sides; + path = [for(i = [0 : sides * turns], + R = i < sides ? r - h + h * i / sides + : i > final && taper_top ? r - h * (i - final) / sides : r, + a = i * 360 / sides) + [R * sin(-a), R * cos(-a), pitch * a / 360]]; + t = atan(pitch / sides / (r * cos(225 / sides))); + translate_z(center ? -length / 2 : 0) { + render() intersection() { + sweep(path, profile, twist = t * sides * turns); + cylinder(d = minor_d + 5, h = length); + } + if(solid) + rotate(90) + cylinder(d = minor_d + eps, h = length); + } +} + +module female_thread(pitch, outer_d, length, profile, taper_top = true, center = true) { //! Create female thread + turns = length / pitch + (taper_top ? 0 : 1); + r = outer_d / 2; + sides = r2sides(r); + h = max([for(p = profile) p.y]); + final = (turns - 1) * sides; + path = [for(i = [0 : sides * turns], + R = i < sides ? r + h - h * i / sides + : i > final && taper_top ? r + h * (i - final) / sides : r, + a = i * 360 / sides) + [R * sin(-a), R * cos(-a), pitch * a / 360]]; + t = atan(pitch / sides / (r * cos(225 / sides))); + translate_z(center ? -length / 2 : 0) { + render() intersection() { + sweep(path, reverse([for(p = profile) [p.x, -p.y, 0]]), twist = t * sides * turns); + cylinder(d = outer_d + 5, h = length); + } + } +} + +module male_metric_thread(d, pitch, length, taper_top = true, center = true) { //! Create male thread with metric profile + h = sqrt(3) / 2 * pitch; + minor_d = d - 5 * h / 4; + male_thread(pitch, minor_d, length, thread_profile((d - minor_d) / 2, pitch / 8, 60), taper_top, center); +} + +module female_metric_thread(d, pitch, length, taper_top = true, center = true) { //! Create male thread with metric profile + h = sqrt(3) / 2 * pitch; + outer_d = d + 5 * h / 4; + male_thread(pitch, outer_d, length, thread_profile((outer_d - d) / 2, pitch / 8, 60), taper_top, center); +} + +function metric_coarse_pitch(d) //! Convert metric diameter to pitch + = d == 1.6 ? 0.35 // M1.6 + : [0.4, // M2 + 0.45,// M2.5 + 0.5, // M3 + 0.6, // M3.5 + 0.7, // M4 + 0, + 0.8, // M5 + 0, + 1.0, // M6 + 0, + 0, + 0, + 1.25, // M8 + 0, + 0, + 0, + 1.5, // M10 + 0, + 0, + 0, + 1.75, // M12 + ][d * 2 - 4]; + +male_metric_thread(3, 0.5, 25); + +translate([10, 0]) +male_metric_thread(8, 1.25, 30); diff --git a/vitamins/d_connector.scad b/vitamins/d_connector.scad index 655c736..bae6e17 100644 --- a/vitamins/d_connector.scad +++ b/vitamins/d_connector.scad @@ -21,6 +21,7 @@ //! D-connectors. Can be any number of ways, male or female, solder buckets, PCB mount or IDC, with or without pillars. // include <../core.scad> +use <../utils/thread.scad> d_pillar_color = grey90; d_plug_shell_color = grey80; @@ -51,16 +52,21 @@ module d_pillar() { //! Draw a pillar for a D-connector height = 4.5; screw = 2.5; screw_length = 8; - color(d_pillar_color) { - translate_z(-screw_length) - cylinder(d = screw, h = screw_length + 1); + translate_z(-screw_length) + if(show_threads) + color(d_pillar_color * 0.7) + male_metric_thread(screw, metric_coarse_pitch(screw), screw_length, false, false); + else + color(d_pillar_color) + cylinder(d = screw, h = screw_length + 1); + + color(d_pillar_color) linear_extrude(height = height) difference() { circle(r = rad, $fn = 6); circle(d = screw); } - } } module d_plug(type, socket = false, pcb = false, idc = false) { //! Draw specified D plug, which can be IDC, PCB or plain solder bucket diff --git a/vitamins/pillar.scad b/vitamins/pillar.scad index 3eb72b5..9ac3e00 100644 --- a/vitamins/pillar.scad +++ b/vitamins/pillar.scad @@ -21,6 +21,7 @@ //! Threaded pillars. Each end can be male or female. // include <../core.scad> +use <../utils/thread.scad> function pillar_name(type) = type[1]; //! Name of part function pillar_thread(type) = type[2]; //! Thread diameter @@ -41,30 +42,43 @@ module pillar(type) { //! Draw specified pillar sex = str(sex(pillar_bot_thread(type)),"/", sex(pillar_top_thread(type))); height = pillar_height(type); thread_d = pillar_thread(type); + bot_thread_l = pillar_bot_thread(type); + top_thread_l = pillar_top_thread(type); + thread_colour = pillar_i_colour(type) * (show_threads ? 0.7 : 1); vitamin(str("pillar(", type[0], "): Pillar ", pillar_name(type), " ", sex, " M", thread_d, "x", height)); + color(thread_colour) { + if(bot_thread_l > 0) + translate_z(-bot_thread_l + eps) + if(show_threads) + male_metric_thread(thread_d, metric_coarse_pitch(thread_d), bot_thread_l, false, false); + else + cylinder(h = bot_thread_l, d = thread_d); + + if(top_thread_l > 0) + translate_z(height + top_thread_l - eps) + if(show_threads) + vflip() + male_metric_thread(thread_d, metric_coarse_pitch(thread_d), top_thread_l, false, false); + else + cylinder(h = top_thread_l, d = thread_d); + } + color(pillar_i_colour(type)) { - if(pillar_bot_thread(type) > 0) - translate_z(-pillar_bot_thread(type)) - cylinder(h = pillar_bot_thread(type) + eps, d = pillar_thread(type)); - - if(pillar_top_thread(type) > 0) - translate_z(height - eps) - cylinder(h = pillar_top_thread(type) + eps, d = pillar_thread(type)); - linear_extrude(height = height) difference() { circle(d = pillar_id(type), $fn = fn(pillar_ifn(type))); - circle(d = pillar_thread(type)); + circle(d = thread_d); } - top = height + min(pillar_top_thread(type), 0); - bot = -min(pillar_bot_thread(type), 0); + top = height + min(top_thread_l, 0); + bot = -min(bot_thread_l, 0); translate_z(bot) - cylinder(h = top - bot, d = pillar_thread(type) + eps); + cylinder(h = top - bot, d = thread_d + eps); } + if(pillar_od(type) > pillar_id(type)) color(pillar_o_colour(type)) linear_extrude(height = height) difference() { diff --git a/vitamins/pillars.scad b/vitamins/pillars.scad index 46edf8f..1a3dbf3 100644 --- a/vitamins/pillars.scad +++ b/vitamins/pillars.scad @@ -30,8 +30,8 @@ // d r r d d // M2x16_brass_pillar = ["M2x16_brass_pillar", "nurled", 2, 16, 3.17, 3.17, 0, 0, brass, brass, 3,-3]; -M3x13_hex_pillar = ["M3x13_hex_pillar", "hex", 3, 13, 5/cos(30), 5/cos(30), 6, 6, "silver", "silver", -6, 6]; -M3x20_hex_pillar = ["M3x20_hex_pillar", "hex", 3, 20, 5/cos(30), 5/cos(30), 6, 6, "silver", "silver", -8, 8]; +M3x13_hex_pillar = ["M3x13_hex_pillar", "hex", 3, 13, 5/cos(30), 5/cos(30), 6, 6, "silver", silver, -6, 6]; +M3x20_hex_pillar = ["M3x20_hex_pillar", "hex", 3, 20, 5/cos(30), 5/cos(30), 6, 6, "silver", silver, -8, 8]; M3x20_nylon_pillar = ["M3x20_nylon_pillar", "nylon", 3, 20, 8, 5/cos(30), 0, 6, "white", brass, -6, 6]; M4x17_nylon_pillar = ["M4x17_nylon_pillar", "nylon", 4, 20, 8, 5/cos(30), 0, 6, "white", brass, -6, 6]; M3x20_nylon_hex_pillar = ["M3x20_nylon_hex_pillar", "hex nylon", 3, 20, 8/cos(30), 8/cos(30), 6, 6, grey20, grey20, -6, 6]; diff --git a/vitamins/rod.scad b/vitamins/rod.scad index ffaed1f..f9e0a5e 100644 --- a/vitamins/rod.scad +++ b/vitamins/rod.scad @@ -21,6 +21,7 @@ //! Steel rods and studding with chamfered ends. // include <../core.scad> +use <../utils/thread.scad> rod_colour = grey80; studding_colour = grey70; @@ -41,10 +42,14 @@ module studding(d , l) { //! Draw a threaded rod with specified length and diame vitamin(str("studding(", d, ", ", l,"): Threaded rod M", d, " x ", l, "mm")); chamfer = d / 20; + pitch = metric_coarse_pitch(d); color(studding_colour) - hull() { - cylinder(d = d, h = l - 2 * chamfer, center = true); + if(show_threads && pitch) + male_metric_thread(d, pitch, l); + else + hull() { + cylinder(d = d, h = l - 2 * chamfer, center = true); - cylinder(d = d - 2 * chamfer, h = l, center = true); - } + cylinder(d = d - 2 * chamfer, h = l, center = true); + } } diff --git a/vitamins/screw.scad b/vitamins/screw.scad index 1ddc206..1aeea76 100644 --- a/vitamins/screw.scad +++ b/vitamins/screw.scad @@ -24,6 +24,7 @@ include <../core.scad> use use <../utils/rounded_cylinder.scad> +use <../utils/thread.scad> function screw_head_type(type) = type[2]; //! Head style hs_cap, hs_pan, hs_cs, hs_hex, hs_grub, hs_cs_cap, hs_dome function screw_radius(type) = type[3] / 2; //! Nominal radius @@ -69,24 +70,33 @@ module screw(type, length, hob_point = 0, nylon = false) { //! Draw specified sc socket_depth= screw_socket_depth(type); socket_rad = socket_af / cos(30) / 2; max_thread = screw_max_thread(type); - thread = max_thread ? min(length, max_thread) : length; + thread = max_thread ? length >= max_thread + 5 ? max_thread + : length + : length; shank = length - thread; colour = nylon || head_type == hs_grub ? grey40 : grey80; - module shaft(headless = 0) { point = screw_nut(type) ? 0 : 3 * rad; - color(colour * 0.9 ) - rotate_extrude() { - translate([0, -length + point]) - square([rad, length - headless - point]); + d = 2 * screw_radius(type); + pitch = metric_coarse_pitch(d); + l = length - shank; + if(show_threads && !point && pitch) + translate_z(-l - shank) + color(colour * 0.7) + male_metric_thread(d, pitch, l, !!headless, false); + else + color(colour * 0.9) + rotate_extrude() { + translate([0, -length + point]) + square([rad, length - headless - point]); - if(point) - polygon([ - [0, -length], [0, point - length], [rad - 0.1, point - length] - ]); - } - if(shank >= 5) + if(point) + polygon([ + [0, -length], [0, point - length], [rad - 0.1, point - length] + ]); + } + if(shank - headless > 0) color(colour) translate_z(-shank) cylinder(r = rad + eps, h = shank - headless); @@ -102,6 +112,7 @@ module screw(type, length, hob_point = 0, nylon = false) { //! Draw specified sc linear_extrude(height = socket_depth) difference() { circle(head_rad); + circle(socket_rad, $fn = 6); } @@ -110,14 +121,23 @@ module screw(type, length, hob_point = 0, nylon = false) { //! Draw specified sc } if(head_type == hs_grub) { color(colour) { - translate_z(-socket_depth) - linear_extrude(height = socket_depth) - difference() { - circle(r = rad); - circle(socket_rad, $fn = 6); - } + if(!show_threads) { + translate_z(-socket_depth) + linear_extrude(height = socket_depth) + difference() { + circle(r = rad); - shaft(socket_depth); + circle(socket_rad, $fn = 6); + } + + shaft(socket_depth); + } + else + render() difference() { + shaft(socket_depth); + + cylinder(r = socket_rad, $fn = 6, h = 2 * socket_depth, center = true); + } } } if(head_type == hs_hex) {