| @@ -0,0 +1,8 @@ | |||
| module knoopvoet | |||
| go 1.16 | |||
| require ( | |||
| git.wtrh.nl/3D-models/objects v0.0.0-20210528131644-78f3aae2fba3 | |||
| github.com/deadsy/sdfx v0.0.0-20210428225541-69bac33c47f0 | |||
| ) | |||
| @@ -0,0 +1,21 @@ | |||
| git.wtrh.nl/3D-models/objects v0.0.0-20210528131644-78f3aae2fba3 h1:drRM0nTPLRIVUwdfxCaUrEBJFDgzIxFsIttW6gGCbr8= | |||
| git.wtrh.nl/3D-models/objects v0.0.0-20210528131644-78f3aae2fba3/go.mod h1:YYSLQ70RNqjnLBLk/rimXyxYzMORHlREwok9g2ZQv/c= | |||
| github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb h1:EVl3FJLQCzSbgBezKo/1A4ADnJ4mtJZ0RvnNzDJ44nY= | |||
| github.com/ajstarks/svgo v0.0.0-20200725142600-7a3c8b57fecb/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= | |||
| github.com/deadsy/sdfx v0.0.0-20210428225541-69bac33c47f0 h1:nCkBC+PowWnmkCMe+3cCOtxpNVw+R1TQI8hzmCmPyKI= | |||
| github.com/deadsy/sdfx v0.0.0-20210428225541-69bac33c47f0/go.mod h1:abZaCad/jNP8KcO+XMyLX6C/cZOdnwefasReJEva4cE= | |||
| github.com/go-gl/gl v0.0.0-20180407155706-68e253793080/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= | |||
| github.com/go-gl/glfw v0.0.0-20180426074136-46a8d530c326/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= | |||
| github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= | |||
| github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= | |||
| github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= | |||
| github.com/llgcode/draw2d v0.0.0-20200930101115-bfaf5d914d1e h1:YRRazju3DMGuZTSWEj0nE2SCRcK3DW/qdHQ4UQx7sgs= | |||
| github.com/llgcode/draw2d v0.0.0-20200930101115-bfaf5d914d1e/go.mod h1:mVa0dA29Db2S4LVqDYLlsePDzRJLDfdhVZiI15uY0FA= | |||
| github.com/llgcode/ps v0.0.0-20150911083025-f1443b32eedb h1:61ndUreYSlWFeCY44JxDDkngVoI7/1MVhEl98Nm0KOk= | |||
| github.com/llgcode/ps v0.0.0-20150911083025-f1443b32eedb/go.mod h1:1l8ky+Ew27CMX29uG+a2hNOKpeNYEQjjtiALiBlFQbY= | |||
| github.com/yofu/dxf v0.0.0-20190710012328-5a6d1e83f16c h1:qgsxLgTXCVH8Dxar36HI5af2ZfinVz5vF8erPpyzM+A= | |||
| github.com/yofu/dxf v0.0.0-20190710012328-5a6d1e83f16c/go.mod h1:gnT4GQzgKW8+TLI0xheUgdmNV4dsAN0WJUVnztRZkfI= | |||
| golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= | |||
| golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI= | |||
| golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | |||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
| @@ -0,0 +1,16 @@ | |||
| include <knoopvoet.scad>; | |||
| button_d = 18.2; | |||
| button_h = 4; | |||
| button_offset = 1; | |||
| outside = 2; | |||
| foot_height = button_h+button_offset-0.5; | |||
| foot_width = 15; | |||
| hole_spacing = 5; | |||
| hole_diameter = 3; | |||
| hole_clearance = hole_spacing + hole_diameter; | |||
| rim_h = 1; | |||
| button_feet(); | |||
| @@ -0,0 +1,14 @@ | |||
| include <knoopvoet.scad>; | |||
| button_d = 24.5; | |||
| button_h = 4; | |||
| button_offset = 1; | |||
| foot_height = button_h+button_offset-0.5; | |||
| hole_spacing = 5.5; | |||
| hole_diameter = 3; | |||
| hole_clearance = hole_spacing + hole_diameter; | |||
| rim_h = 1; | |||
| button_feet(); | |||
| @@ -0,0 +1,50 @@ | |||
| include<knoopvoet.scad> | |||
| include<knoopvoet_box.scad> | |||
| number_of_feet = 8; | |||
| small_size = 12; | |||
| step_size = 2; | |||
| size_list = [for (a = [0:(number_of_feet-1)]) small_size+step_size*a]; | |||
| small_height = 2; | |||
| step_height = 0.25; | |||
| height_list =[for (a = [0:(number_of_feet-1)]) small_height+step_height*a]; | |||
| small_hole = 6; | |||
| step_hole = 0.2; | |||
| hole_list =[for (a = [0:(number_of_feet-1)]) small_hole+step_hole*a]; | |||
| module feet(){ | |||
| for (i = [0:7]){ | |||
| translate([36*i,0,0])//,small_size+step_size*i/2+10]) | |||
| //rotate([-90,0,-90]) | |||
| button_foot(height=height_list[i], diameter=size_list[i], hole_width = hole_list[i]); | |||
| } | |||
| } | |||
| module storage_box() { | |||
| box=[60,30,46]; | |||
| difference(){ | |||
| translate([0,0,8]) | |||
| bottom_box(box); | |||
| translate([-7*number_of_feet/2,-15*1.1/2,-15]) | |||
| for (i = [0:7]){ | |||
| translate([7*i,0,0]) | |||
| cube([(height_list[i]+0.5)*1.1,15*1.1,16]); | |||
| if (i % 2 == 0) { | |||
| translate([7*i+2,-2,15]) | |||
| linear_extrude(height=0.4,center = true) text(text=str(floor(size_list[i])),size=6,halign="center",valign="top"); | |||
| } | |||
| } | |||
| } | |||
| //translate([0,0,60]) | |||
| // translate([0,0,8]) | |||
| //top_box(box); | |||
| } | |||
| //rotate([90,0,0]) | |||
| storage_box(); | |||
| //rotate([90,0,0]) | |||
| //translate([-7*number_of_feet/2,0,-15]) | |||
| feet(); | |||
| @@ -0,0 +1,128 @@ | |||
| package main | |||
| import ( | |||
| "git.wtrh.nl/3D-models/objects" | |||
| "github.com/deadsy/sdfx/render" | |||
| "github.com/deadsy/sdfx/sdf" | |||
| "math" | |||
| ) | |||
| type Button struct { | |||
| Size float64 // diameter of button | |||
| Thickness float64 // height of button | |||
| HoleSpacing float64 // Broadest cross length of thread holes. | |||
| Curve float64 // Depth of the curve | |||
| } | |||
| type DoveTail struct { | |||
| Size sdf.V3 | |||
| Angle float64 | |||
| } | |||
| var flange_h = 1.0 | |||
| var flange_w = 2.0 | |||
| var cloth_offset = 1.0 | |||
| var doveTail = DoveTail{ | |||
| Size: sdf.V3{X: 10, Y: 8, Z: 2}, | |||
| Angle: sdf.Pi/10, | |||
| } | |||
| func ButtonHolder3D(b *Button) (holder sdf.SDF3, err error) { | |||
| cylinderTickness := flange_h+cloth_offset+b.Curve | |||
| holder, err = sdf.Cylinder3D(cylinderTickness,b.Size/2+flange_w,0.0) | |||
| if err != nil { | |||
| return | |||
| } | |||
| negative, err := buttonNegative(b) | |||
| if err != nil { | |||
| return | |||
| } | |||
| holder = sdf.Transform3D(holder, sdf.Translate3d(sdf.V3{0,0,cylinderTickness/2})) | |||
| negative = sdf.Transform3D(negative, sdf.Translate3d(sdf.V3{0,0,cloth_offset})) | |||
| negative2, err := wireNegative(b) | |||
| if err != nil { | |||
| return | |||
| } | |||
| negative = sdf.Union3D(negative2,negative) | |||
| holder = sdf.Difference3D(holder,negative) | |||
| return | |||
| } | |||
| func buttonNegative(b *Button) (negative sdf.SDF3, err error) { | |||
| h := (math.Pow(b.Size/2,2)/b.Curve - b.Curve)/2 | |||
| s1, err := sdf.Sphere3D(h) | |||
| if err != nil { | |||
| return | |||
| } | |||
| s1 = sdf.Transform3D(s1, sdf.Translate3d(sdf.V3{0,0,h})) | |||
| c1, err := sdf.Cylinder3D(h,b.Size/2,0.0) | |||
| if err != nil { | |||
| return | |||
| } | |||
| c1 = sdf.Transform3D(c1, sdf.Translate3d(sdf.V3{0,0,h/2})) | |||
| negative = sdf.Intersect3D(s1,c1) | |||
| return | |||
| } | |||
| func wireNegative(b *Button) (negative sdf.SDF3, err error) { | |||
| size := sdf.V3{X: b.HoleSpacing/2, Y: b.HoleSpacing/2, Z: 20}.MulScalar(math.Sqrt(2)) | |||
| b1, err := sdf.Box3D(size,1.5) | |||
| if err != nil { | |||
| return | |||
| } | |||
| b1 = sdf.Transform3D(b1,sdf.RotateZ(sdf.Pi/4)) | |||
| b1 = sdf.Elongate3D(b1,sdf.V3{X:b.Size,Y: 0, Z: 0}) | |||
| negative = sdf.Transform3D(b1,sdf.Translate3d(sdf.V3{-b.Size/2,0,0})) | |||
| return | |||
| } | |||
| func dovetail(size sdf.V3, angle float64, offset float64) (tail sdf.SDF3, err error) { | |||
| tail, err = sdf.Box3D(size, 0.0) | |||
| a1 := sdf.V3{X: 0, Y: size.Y/2+offset, Z:-size.Z/2} | |||
| a2 := sdf.V3{X: 0, Y: -size.Y/2+offset, Z:-size.Z/2} | |||
| n1 := sdf.V3{Y: -math.Cos(angle), X: 0, Z: -math.Sin(angle)} | |||
| n2 := sdf.V3{Y: math.Cos(angle), X: 0, Z: -math.Sin(angle)} | |||
| tail = sdf.Cut3D(tail, a1, n1) | |||
| tail = sdf.Cut3D(tail, a2, n2) | |||
| //bottomSize := sdf.V2{X: doveTail.Size.X, Y: doveTail.Size.Y} | |||
| //b2d := sdf.Box2D(bottomSize,0) | |||
| //topSize := bottomSize.Add(sdf.V2{X:0, Y: doveTail.Size.Z * math.Tan(doveTail.Angle) * 2}) | |||
| //t2d := sdf.Box2D(topSize,0) | |||
| //tail, err = sdf.Loft3D(b2d, t2d, doveTail.Size.Z,0) | |||
| return | |||
| } | |||
| func main() { | |||
| k := objects.BoxParams{ | |||
| Size: sdf.V3{100,100,100}, | |||
| Wall: 3, | |||
| BottomTopRatio: 1, | |||
| Margin: 0.1, | |||
| Taper: 0.1, | |||
| ClosingHeight: 4, | |||
| CornerRadius: 3, | |||
| } | |||
| box, err := objects.BottomBox3D(&k) | |||
| if err != nil { | |||
| return | |||
| } | |||
| render.RenderSTL(box, 300, "out.stl") | |||
| b := Button{ | |||
| Size: 18, | |||
| Curve: 1.2, | |||
| HoleSpacing: 8.5, | |||
| } | |||
| holder, err := ButtonHolder3D(&b) | |||
| if err != nil { | |||
| return | |||
| } | |||
| render.RenderSTL(holder, 300, "holder.stl") | |||
| negative, err := wireNegative(&b) | |||
| if err != nil { | |||
| return | |||
| } | |||
| render.RenderSTL(negative, 300, "negative.stl") | |||
| return | |||
| } | |||
| @@ -0,0 +1,47 @@ | |||
| $fn = $preview ? 16 : 72; | |||
| module button_foot(height = 4, diameter = 18, hole_width = 5) { | |||
| button_offset = 1; | |||
| foot_length = diameter/2+16; | |||
| outside = 2; | |||
| foot_height = height+button_offset; | |||
| foot_width = 15; | |||
| hole_diameter = 3; | |||
| hole_clearance = hole_width; | |||
| hole_spacing = hole_clearance - hole_diameter; | |||
| rim_h = 1; | |||
| //bottom | |||
| difference(){ | |||
| union(){ | |||
| cylinder(d=diameter+2*outside,h=foot_height); | |||
| translate([-foot_width/2,0,0]) | |||
| cube([foot_width,foot_length,foot_height]); | |||
| } | |||
| //slot | |||
| translate([-hole_clearance/2,-diameter,-1]) | |||
| cube([hole_clearance,diameter,foot_height+2]); | |||
| //button insert | |||
| translate([0,0,button_offset]) | |||
| cylinder(d=diameter,h=foot_height); | |||
| //rim | |||
| translate([-diameter/2-outside-2,-diameter,button_offset+rim_h]) | |||
| cube([diameter+2*outside+4,diameter,foot_height+2]); | |||
| //wire slots | |||
| hull(){ | |||
| translate([hole_spacing/2,0,-1]) | |||
| cylinder(d=hole_diameter*1.1,button_offset+2); | |||
| translate([-hole_spacing/2,0,-1]) | |||
| cylinder(d=hole_diameter*1.1,button_offset+2); | |||
| translate([0,hole_spacing/2,-1]) | |||
| cylinder(d=hole_diameter*1.1,button_offset+2); | |||
| } | |||
| // size indication | |||
| translate([0,foot_length-1,foot_height]){ | |||
| linear_extrude(height=0.4,center = true) text(text=str(floor(diameter)),size=8,halign="center",valign="top"); | |||
| translate([0,-10,0]) | |||
| linear_extrude(height=0.4,center = true) text(text=str("mm"),size=5,halign="center",valign="top"); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,99 @@ | |||
| $fn = $preview ? 16 : 72; | |||
| wall_thickness = 3; | |||
| //box = [21,21,21]; | |||
| box = [195,75,36]; | |||
| corner_radius = 2; | |||
| cutoff = 0.5; | |||
| overlap = 4; | |||
| taper = 0.1; | |||
| module outer_box(box) { | |||
| minkowski(){ | |||
| cube([box.x+wall_thickness,box.y+wall_thickness,box.z+wall_thickness], center=true); | |||
| sphere(d=wall_thickness); | |||
| } | |||
| } | |||
| module box(size, wall=3, taper=0) { | |||
| translate([0,0,-size.z/2]) | |||
| hull(){ | |||
| linear_extrude(height=0.1, scale=0) | |||
| offset(r=wall/2) square(size=[(size.x+wall-taper),(size.y+wall-taper)],center=true); | |||
| translate([0,0,size.z]) | |||
| rotate([0,180,0]) | |||
| linear_extrude(height=0.1, scale=0) | |||
| offset(r=wall/2) square(size=[size.x+wall+taper,size.y+wall+taper],center=true); | |||
| } | |||
| } | |||
| module bottom_box(box) { | |||
| difference(){ | |||
| //box(size=[box.x,box.y,box.z+2*wall_thickness] ,wall=wall_thickness); | |||
| outer_box(box); | |||
| translate([0,0,box.z*cutoff+wall_thickness]) | |||
| cube([box.x+60,box.y+60,box.z],center=true); | |||
| //cube(box,center=true); | |||
| translate([0,0,box.z*cutoff+overlap-wall_thickness+0.01]) | |||
| #box([box.x,box.y,overlap],wall=wall_thickness/2,taper=0.5); | |||
| translate([box.x/2+wall_thickness,0,0]) | |||
| rotate([90,0,90]) | |||
| side_text(); | |||
| translate([-box.x/2-wall_thickness,0,0]) | |||
| rotate([90,0,-90]) | |||
| side_text(); | |||
| } | |||
| } | |||
| module custom_text() { | |||
| linear_extrude(height=0.4,center=true) | |||
| text("Wetstone", valign="center", halign="center"); | |||
| } | |||
| module side_text(){ | |||
| linear_extrude(height=0.4,center=true) | |||
| scale(1.2) | |||
| text("Wetstone", valign="center", halign="center"); | |||
| } | |||
| module top_box(box) { | |||
| inner_wall_t = wall_thickness - 0.5; | |||
| difference(){ | |||
| union(){ | |||
| difference(){ | |||
| outer_box(box); | |||
| //box(size=[box.x,box.y,box.z+2*wall_thickness] ,wall=wall_thickness); | |||
| translate([0,0,-box.z*(1-cutoff)+wall_thickness]) | |||
| cube([box.x+60,box.y+60,box.z],center=true); | |||
| } | |||
| translate([0,0,overlap-wall_thickness+0.1]) | |||
| box([box.x,box.y,overlap],wall=wall_thickness/2,taper=0.5); | |||
| } | |||
| translate([0,0,box.z/2+wall_thickness]) | |||
| linear_extrude(height=0.4,center=true) | |||
| scale(3) | |||
| text("Wetstone", valign="center", halign="center"); | |||
| cube(box,center=true); | |||
| translate([box.x/2+wall_thickness,0,0]) | |||
| rotate([90,0,90]) | |||
| side_text(); | |||
| translate([-box.x/2-wall_thickness,0,0]) | |||
| rotate([90,0,-90]) | |||
| side_text(); | |||
| } | |||
| } | |||
| module top_box_flip() { | |||
| rotate([0,180,0]) | |||
| top_box(); | |||
| } | |||
| * rotate([0,90,0]){ | |||
| bottom_box(); | |||
| translate([0,0,20]) | |||
| top_box(); | |||
| } | |||
| @@ -0,0 +1,50 @@ | |||
| package main | |||
| import ( | |||
| "github.com/deadsy/sdfx/render" | |||
| "github.com/deadsy/sdfx/sdf" | |||
| "testing" | |||
| ) | |||
| //var doveTail = DoveTail{ | |||
| // Size: sdf.V3{X: 10, Y: 8, Z: 2}, | |||
| // Angle: sdf.Pi/10, | |||
| //} | |||
| var buttonStruct = Button{ | |||
| Size: 18, | |||
| Curve: 1.2, | |||
| HoleSpacing: 8.5, | |||
| Thickness: 1.0, | |||
| } | |||
| func TestButtonHolder3D(t *testing.T) { | |||
| stl, err := ButtonHolder3D(&buttonStruct) | |||
| if err != nil { | |||
| t.FailNow() | |||
| } | |||
| render.RenderSTL(stl,300, "buttonHolder.stl") | |||
| } | |||
| func TestButtonNegative(t *testing.T) { | |||
| stl, err := buttonNegative(&buttonStruct) | |||
| if err != nil { | |||
| t.FailNow() | |||
| } | |||
| render.RenderSTL(stl,300, "buttonNegative.stl") | |||
| } | |||
| func TestWireNegative(t *testing.T) { | |||
| stl, err := wireNegative(&buttonStruct) | |||
| if err != nil { | |||
| t.FailNow() | |||
| } | |||
| render.RenderSTL(stl,300, "wireNegative.stl") | |||
| } | |||
| func TestDoveTail(t *testing.T) { | |||
| stl, err := dovetail(sdf.V3{X: 10, Y: 8, Z: 2}, sdf.Pi/8, 0) | |||
| if err != nil { | |||
| t.FailNow() | |||
| } | |||
| render.RenderSTL(stl,300, "doveTail.stl") | |||
| } | |||
| @@ -0,0 +1,12 @@ | |||
| radius = 5; | |||
| depth = 2; | |||
| diff_h = (pow(radius,2)/depth - depth)/2; | |||
| diff_radius = (pow(radius,2)/depth - depth)/2 + depth; | |||
| difference(){ | |||
| translate([0,0,0]) | |||
| cylinder(r=radius,h=depth); | |||
| translate([0,0,diff_radius]) | |||
| sphere(r=diff_radius); | |||
| } | |||