| @@ -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); | |||||
| } | |||||