/Boxes/TissueBoxCover.foocad

A tissue box cover, for those who don't like to look at cardboard boxes! Print the main body using "vase" mode, and make the walls thicker than normal by increasing the "Default Extrusion Width" to say 200%
import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.*
class TissueBoxCover : AbstractModel() {
var boxWidth = 120
var boxDepth = 120
var boxHeight = 130
var margin = 10
var cornerRadius = 3
var extra = 8
fun profile( amplitude : double ) : Shape2d {
val width = boxWidth + extra
val depth = boxWidth + extra
val profile = PolygonBuilder().apply {
val bumps = 4
val dx = (width - margin) / bumps
val dy = (depth - margin) / bumps
val xRadius = Vector2( dx/4, amplitude )
val yRadius = Vector2( amplitude, dy/4 )
// First side
moveTo( margin, 0 )
radius( 0 )
for ( i in 0 until bumps ) {
arcTo( Vector2(margin + dx * i, 0), xRadius, 0, true, true )
arcTo( Vector2(margin + dx * i + dx/2, 0), xRadius, 0, true, false )
}
radius( cornerRadius )
lineTo( width, 0 )
radius( 0 )
// Second side
lineTo( width, margin )
for ( i in 0 until bumps ) {
arcTo( Vector2( width, margin + dy * i), yRadius, 0, true, true )
arcTo( Vector2( width, margin + dy * i + dy/2), yRadius, 0, true, false )
}
radius( cornerRadius )
lineTo( width, depth )
radius( 0 )
// Third side
lineTo( width-margin, depth )
for ( i in 0 until bumps ) {
arcTo( Vector2( width - (margin + dx * i), depth), xRadius, 0, true, true )
arcTo( Vector2( width - (margin + dx * i + dx/2), depth), xRadius, 0, true, false )
}
radius( cornerRadius )
lineTo( 0, depth )
radius( 0 )
// Forth side
lineTo( 0, depth - margin )
for ( i in 0 until bumps ) {
arcTo( Vector2( 0, depth - (margin + dy * i) ), yRadius, 0, true, true )
arcTo( Vector2( 0, depth - (margin + dy * i + dy/2) ), yRadius, 0, true, false )
}
radius( cornerRadius )
lineTo( 0,0 )
}.build()
return profile
}
@Piece
fun body() : Shape3d {
val middle = ExtrusionBuilder().apply {
crossSection( profile( 1 ) )
forward( 2 )
crossSection( profile( 3 ) )
forward( boxHeight - margin * 2 - 4 )
crossSection()
forward( 2 )
crossSection( profile( 1 ) )
}.build()
val ends = baseProfile(0).extrude( margin )
return ends +
middle.centerXY().translateZ(margin) +
ends.translateZ( boxHeight - margin )
}
fun baseProfile( offset : double ) : Shape2d {
val profile = Square( boxWidth + extra, boxDepth + extra ).center()
.roundAllCorners( cornerRadius )
return if ( offset == 0 ) {
profile
} else {
val scale = (profile.size - Vector2( offset, offset )) / profile.size
profile.scale( scale )
}
}
@Piece
fun lid() : Shape3d {
val thickness = 1.2
val chamfer = 1
val lipOffset = 2
val lipInset = 2
val lipThickness = 2
val lipHeight = 5
val lid = ExtrusionBuilder().apply {
crossSection( baseProfile(chamfer) )
forward( chamfer )
crossSection( baseProfile(0) )
forward( thickness )
crossSection()
crossSection( baseProfile( lipInset ) )
forward( lipHeight )
crossSection()
crossSection( baseProfile( lipInset + lipThickness ) )
forward( - lipHeight )
crossSection()
}.build()
val a = Circle( 12 ).translateX(14)
val holeP = a.hull( a.mirrorX() )
val hole = holeP.chamferedExtrude( 4.2, -1, -1 ).translateZ(-0.1)
val thicker = (holeP.offset( 2 ) - holeP).extrude( 4 )
return lid + thicker - hole
}
@Piece( printable = false )
override fun build() : Shape3d {
val box = Cube( boxWidth, boxDepth, boxHeight ).previewOnly().centerXY()
val main = body()
val lid : Shape3d = lid().mirrorZ().bottomTo(main.top)
return box.translateZ(10) + main + lid
}
}

