| @@ -0,0 +1,98 @@ | |||||
| package objects | |||||
| import ( | |||||
| "github.com/deadsy/sdfx/sdf" | |||||
| "math" | |||||
| ) | |||||
| type BoxParams struct { | |||||
| Size sdf.V3 // internal box size | |||||
| Wall float64 // wall thickness | |||||
| BottomTopRatio float64 // ratio between the height of the top and the bottom | |||||
| CornerRadius float64 // radius of rounded corners | |||||
| Taper float64 // angle of split | |||||
| ClosingHeight float64 // height of the closing | |||||
| Margin float64 // Margin for closing | |||||
| Text string | |||||
| } | |||||
| func Box3D(k *BoxParams) (top sdf.SDF3, bottom sdf.SDF3, err error) { | |||||
| top, err = TopBox3D(k) | |||||
| bottom, err = TopBox3D(k) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| return | |||||
| } | |||||
| func baseBox3D(k *BoxParams) (sdf.SDF3, error) { | |||||
| box, err := sdf.Box3D(k.Size.AddScalar(k.Wall*2), k.CornerRadius) | |||||
| if err != nil { | |||||
| return nil, err | |||||
| } | |||||
| return box, nil | |||||
| } | |||||
| func TopBox3D(k *BoxParams) (top sdf.SDF3, err error) { | |||||
| box, err := baseBox3D(k) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| a := sdf.V3{X: 0, Y: 0, Z: 0.5 - k.BottomTopRatio}.Mul(k.Size).Add(sdf.V3{X: 0, Y: 0, Z: k.ClosingHeight / 2}) | |||||
| n := sdf.V3{X: 0, Y: 0, Z: 1} | |||||
| top = sdf.Cut3D(box, a, n) | |||||
| closing, err := InnerClosing(k) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| top = sdf.Union3D(top,closing) | |||||
| return | |||||
| } | |||||
| func BottomBox3D(k *BoxParams) (bottom sdf.SDF3, err error) { | |||||
| box, err := baseBox3D(k) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| a := sdf.V3{X: 0, Y: 0, Z: 0.5 - k.BottomTopRatio}.Mul(k.Size).Add(sdf.V3{X: 0, Y: 0, Z: k.ClosingHeight / 2}) | |||||
| n := sdf.V3{X: 0, Y: 0, Z: -1} | |||||
| bottom = sdf.Cut3D(box, a, n) | |||||
| closing, err := InnerClosing(k) | |||||
| scale := k.Size.Add(sdf.V3{X: k.Margin, Y: k.Margin, Z: 0}).Div(k.Size) | |||||
| closing = sdf.Transform3D(closing, sdf.Scale3d(scale)) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| bottom = sdf.Difference3D(bottom,closing) | |||||
| return | |||||
| } | |||||
| func InnerClosing(k *BoxParams) (closing sdf.SDF3, err error) { | |||||
| offset := math.Tan(k.Taper) * k.ClosingHeight / 2 | |||||
| size := sdf.V2{X: k.Size.X, Y: k.Size.Y} | |||||
| s1 := sdf.Box2D(size.AddScalar(k.Wall-offset), k.CornerRadius) | |||||
| s2 := sdf.Box2D(size.AddScalar(k.Wall+offset), k.CornerRadius) | |||||
| closing, err = sdf.Loft3D(s1, s2, k.ClosingHeight, 0) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| closing = sdf.Transform3D(closing, sdf.Translate3d(sdf.V3{0,0,0.5-k.BottomTopRatio}.Mul(k.Size))) | |||||
| return | |||||
| } | |||||
| func OuterClosing(k *BoxParams) (closing sdf.SDF3, err error) { | |||||
| s0, err := InnerClosing(k) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| s1, err := baseBox3D(k) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| a := sdf.V3{0, 0, k.ClosingHeight / 2} | |||||
| n := sdf.V3{0, 0, -1} | |||||
| s1 = sdf.Cut3D(s1, a, n) | |||||
| s1 = sdf.Cut3D(s1, a.Neg(), n.Neg()) | |||||
| closing = sdf.Difference3D(s1, s0) | |||||
| return | |||||
| } | |||||
| @@ -0,0 +1,51 @@ | |||||
| package objects | |||||
| import ( | |||||
| "github.com/deadsy/sdfx/render" | |||||
| "github.com/deadsy/sdfx/sdf" | |||||
| "testing" | |||||
| ) | |||||
| var k = BoxParams{ | |||||
| Size: sdf.V3{X: 40, Y: 40, Z: 40}, | |||||
| CornerRadius: 6.0, | |||||
| BottomTopRatio: 0.3, | |||||
| Wall: 3, | |||||
| ClosingHeight: 4, | |||||
| Taper: 0.2, | |||||
| Margin: 0.2, | |||||
| } | |||||
| func TestBottomBox3D(t *testing.T) { | |||||
| bottom, err := BottomBox3D(&k) | |||||
| if err != nil { | |||||
| t.Failed() | |||||
| return | |||||
| } | |||||
| render.RenderSTL(bottom, 400, "test_box_bottom.stl") | |||||
| } | |||||
| func TestTopBox3D(t *testing.T) { | |||||
| top, err := TopBox3D(&k) | |||||
| if err != nil { | |||||
| t.Failed() | |||||
| return | |||||
| } | |||||
| render.RenderSTL(top, 100, "test_box_top.stl") | |||||
| } | |||||
| func TestInnerClosing(t *testing.T) { | |||||
| stl, err := InnerClosing(&k) | |||||
| if err != nil { | |||||
| t.FailNow() | |||||
| } | |||||
| render.RenderSTL(stl, 100, "inner_closing.stl") | |||||
| } | |||||
| func TestOuterClosing(t *testing.T) { | |||||
| stl, err := OuterClosing(&k) | |||||
| if err != nil { | |||||
| t.FailNow() | |||||
| } | |||||
| render.RenderSTL(stl, 100, "outer_closing.stl") | |||||
| } | |||||
| @@ -0,0 +1,5 @@ | |||||
| module git.wtrh.nl/3D-models/objects | |||||
| go 1.16 | |||||
| require github.com/deadsy/sdfx v0.0.0-20210428225541-69bac33c47f0 | |||||
| @@ -0,0 +1,19 @@ | |||||
| 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= | |||||