import static uk.co.nickthecoder.foocad.chamferedExtrude.ChamferedExtrude.* import static uk.co.nickthecoder.foocad.layout.Layout2d.* import static uk.co.nickthecoder.foocad.layout.Layout3d.* class SmoothInsideBox : Model { @Custom var height = 40 // Make the top higher than the "lipHeight" + "topChamfer" @Custom var extraTopHeight = 0 @Custom var middleHeight = 30 @Custom var topChamfer = 2.0 @Custom var bottomChamfer = 2.0 @Custom var lipHeight = 8.0 @Custom var lipThickness = 2.0 // Make this bigger than wallThickness, so that the rim of the bottom and middle // pieces are stronger. The "rims" are parts that are on the inside pointing upwards, // and the "lips" are outside pointing downwards. @Custom var rimThickness = 1.5 @Custom var wallThickness = 1.0 @Custom var baseThickness = 1.0 @Custom var slack = 0.3 fun profile() : Shape2d = Square( 70 ).center() fun inset( amount : double ) : Shape2d { val profile : Shape2d = profile() return profile.scale( (profile.size.x - amount * 2) / profile.size.x, (profile.size.y - amount * 2) / profile.size.y ) } @Piece fun top() : Shape3d { val out = slack + lipThickness + rimThickness - wallThickness val topHeight = extraTopHeight + topChamfer + baseThickness val outside = inset( - out ) val chamfered = inset( topChamfer - out ) val lipA = inset( -slack - rimThickness + wallThickness ) val inside = inset( wallThickness ) val insideChamfered = inset( wallThickness + topChamfer ) return ExtrusionBuilder().apply { joinStrategy = OneToOneJoinStrategy.instance crossSection( chamfered ) forward( topChamfer ) crossSection( outside ) forward( topHeight + lipHeight - topChamfer ) crossSection() crossSection( lipA ) forward( -lipHeight ) crossSection() crossSection( inside ) forward( -topHeight + topChamfer + baseThickness ) crossSection() forward( -topChamfer ) crossSection( insideChamfered ) }.build().mirrorX() } @Piece fun middle() : Shape3d { if ( middleHeight <= 0 ) return Cube(0) val out = slack + lipThickness + rimThickness - wallThickness val diff = rimThickness - wallThickness val profile : Shape2d = profile() val inside = inset( wallThickness ) val outside = inset( -out ) val lipA = inset( - diff - slack ) val rim = inset( -rimThickness + wallThickness ) return ExtrusionBuilder().apply { joinStrategy = OneToOneJoinStrategy.instance crossSection( rim ) forward( lipHeight - diff ) if ( diff != 0 ) { crossSection() forward( diff ) } crossSection( profile ) forward( middleHeight - lipHeight - out ) crossSection() forward( out ) crossSection( outside ) forward( lipHeight - lipThickness ) crossSection() forward( lipThickness ) crossSection( lipA ) forward( -lipHeight ) crossSection() crossSection( inside ) forward( -middleHeight ) crossSection() }.build().mirrorX() - Cube ( profile.size.x * 3, profile.size.y * 3, 2 ) .centerXY().translateZ(-2) } @Piece fun bottom() : Shape3d { val diff = rimThickness - wallThickness val profile : Shape2d = profile() val chamfered = inset( bottomChamfer ) val inside = inset( wallThickness ) val insideChamfer = inset( wallThickness + bottomChamfer ) val rim = inset( -diff ) return ExtrusionBuilder().apply { joinStrategy = OneToOneJoinStrategy.instance crossSection( chamfered ) forward( bottomChamfer ) crossSection( profile ) forward( height - bottomChamfer - lipHeight - diff ) crossSection() forward( diff ) crossSection( rim ) forward( lipHeight ) crossSection() crossSection( inside ) forward( -height + bottomChamfer + baseThickness ) crossSection() forward( -bottomChamfer ) crossSection( insideChamfer ) }.build() } @Piece override fun build() : Shape3d { var gap = 10 return bottom() .color("Blue") + middle() .mirrorZ() .translateZ(height + middleHeight + slack + gap) .color("Silver") + top() .mirrorZ() .translateZ(height + middleHeight + extraTopHeight + topChamfer + baseThickness + slack*2 + gap*2 ) .color("Green") } }