/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 : Model { 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.internalChamferedExtrude( 4, 1, 1 ) val thicker = (holeP.offset( 2 ) - holeP).extrude( 4 ) return lid + thicker - hole } 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 } }