import static uk.co.nickthecoder.foocad.layout.Layout2d.* import static uk.co.nickthecoder.foocad.layout.Layout3d.* class ThickWalledBox2 : RoundedThickWalledBox2 { @Custom( about="Size (not including the height) of the insides of the box" ) var size = Vector2(70,30) override fun profile() = Square( size ).center() } abstract class RoundedThickWalledBox2 : AbstractThickWalledBox2 { // NOTE Unlike the old ThickneWalledBox, the exterior is always rounded @Custom( about="Internal radius of the box" ) var radius = 0 abstract fun profile() : Shape2d override fun profile(offset : double ) : Shape2d { val p = profile().offset(offset) return if (radius + offset <= 0 ) { p } else { p.roundAllCorners( radius + offset) } } } /** A thick walled box which snaps together with an interferance fit of lips. The ouside and inside of the box are smooth. The shape of the box can be anything you like (not only rectangular). override the method profile(), or use ThickWalledBox2 which is a rectanngular box. Comprised of a bottom and a top, and optionaly middle sections, which are hollow tubes (with the same lip connectors). You can include as many middle sections as you like, and either keep them free, or glue them to the bottom. An upgraded version of ThickWalledBox, but changed the name so that other scripts can use the old version still. */ abstract class AbstractThickWalledBox2 : AbstractModel { @Custom var middleHeight = 20.0 // Internal size @Custom var topHeight = 10.0 // Internal size @Custom var bottomHeight = 30.0 // Internal size @Custom var thickness = 4.0 // Thickness of the top (sides and top/bottom) @Custom var baseThickness = 2.0 @Custom var lipThickness = 2.0 // Should probably be half of thickness (or close to it) @Custom var lipHeight = 6.0 // The height of the lip on the bottom piece. // I created small prototypes to find the best value for this. // It is the additional space in the top part for the bottom's lip // to fit into. @Custom var lipSlack = 0.3 @Custom var chamfer = 2.0 // Chamfer of the bottom and top edges. abstract fun profile( offset: double ) : Shape2d @Piece fun top() : Shape3d { val inside = profile(0) val outside = profile( thickness ) val outsideChamfer = profile( thickness - chamfer ) val outsideLip = profile( lipThickness ) val top : Shape3d = ExtrusionBuilder().apply { crossSection( outsideChamfer ) forward( chamfer ) crossSection( outside ) forward( topHeight + baseThickness - chamfer ) crossSection( outside ) crossSection( outsideLip ) forward( -lipHeight ) crossSection( outsideLip ) crossSection( inside ) forward( -topHeight + lipHeight) crossSection( inside ) }.build().color( "Green" ) return top.mirrorX() } @Piece fun middle() : Shape3d { val inside = profile(0) val outside = profile( thickness ) val slackLip = profile( lipThickness - lipSlack ) val outsideLip = profile( lipThickness ) val middleSolid = ExtrusionBuilder().apply { crossSection( outside ) forward( middleHeight ) crossSection( outside ) crossSection( slackLip ) forward( lipHeight ) crossSection( slackLip ) }.build() .color( "Blue" ).brighter() val middleHole = ExtrusionBuilder().apply { forward(-0.1) crossSection( outsideLip ) forward(0.1 + lipHeight + 1 ) crossSection( outsideLip ) forward( thickness ) // Chamfer so that we don't need support material crossSection( inside ) forward( middleHeight - thickness -1 + 0.1) crossSection( inside ) }.build() return ( middleSolid - middleHole ).mirrorX() } @Piece fun bottom() : Shape3d { val inside = profile(0) val outside = profile( thickness ) val outsideChamfer = profile( thickness - chamfer) val slackLip = profile( lipThickness - lipSlack ) val bottom : Shape3d = ExtrusionBuilder().apply { crossSection( outsideChamfer ) forward( chamfer ) crossSection( outside ) forward( bottomHeight + baseThickness - chamfer ) crossSection( outside ) crossSection( slackLip ) forward( lipHeight - 1 ) crossSection( slackLip ) crossSection( inside ) forward( -bottomHeight - lipHeight + 1 ) crossSection( inside ) }.build().color( "Blue" ) return bottom } override fun build() : Shape3d { val gap = 10 val bottom : Shape3d = bottom() val middle : Shape3d = if ( middleHeight <= 0 ) { Cube(0).bottomTo( bottom.top ) } else { middle().bottomTo(bottom.top + gap ).color("Yellow") } val top : Shape3d = top().rotateX(180).rotateZ(180).bottomTo( middle.top + gap ) return bottom + middle + top } }