| @@ -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= | |||