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 SmoothOutsideBox : Model { @Custom var height = 40 @Custom var topHeight = 10 @Custom var middleHeight = 30 @Custom var topChamfer = 2.0 @Custom var bottomChamfer = 2.0 @Custom var lipHeight = 8.0 @Custom var lipThickness = 2.0 @Custom var wallThickness = 1.0 @Custom var baseThickness = 2.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 profile : Shape2d = profile() val chamfered = inset( topChamfer ) val lipA = inset( slack + lipThickness ) val lipB = inset( slack + lipThickness*2 ) val inside = inset( wallThickness ) val insideChamfer = inset( wallThickness + topChamfer ) return ExtrusionBuilder().apply { joinStrategy = OneToOneJoinStrategy.instance crossSection( chamfered ) forward( topChamfer ) crossSection( profile ) forward( topHeight - topChamfer ) crossSection() crossSection( lipA ) forward( lipHeight ) crossSection() crossSection( lipB ) forward( -lipHeight - lipThickness/2 ) crossSection() val foo = - topHeight + lipThickness*2 + slack - wallThickness + lipThickness/2 + baseThickness + topChamfer if (foo < 0) { forward( - lipThickness*2 - slack + wallThickness ) crossSection(inside) forward( foo ) } crossSection() if ( foo < 0 ) { forward( -topChamfer ) } else { //forward( foo - topChamfer ) } crossSection( insideChamfer ) }.build().mirrorX() } @Piece fun middle() : Shape3d { if ( middleHeight <= 0 ) return Cube(0) val profile : Shape2d = profile() val bottomLipA = inset( slack + lipThickness ) val bottomLipB = inset( slack + lipThickness*2 ) val inside = inset( wallThickness ) val topLipA = inset( lipThickness ) return ExtrusionBuilder().apply { joinStrategy = OneToOneJoinStrategy.instance crossSection( profile ) forward( middleHeight ) crossSection() crossSection( bottomLipA ) forward( lipHeight ) crossSection() crossSection( bottomLipB ) forward( -lipHeight - lipThickness/2 ) crossSection() forward( -lipThickness * 2 - slack + wallThickness ) crossSection( inside ) forward( - middleHeight + lipThickness*2 + slack - wallThickness + lipHeight + lipThickness/2 - lipHeight + lipHeight + lipThickness - wallThickness // Matches below ) crossSection() forward( -lipThickness + wallThickness ) crossSection( wallThickness - lipThickness ) forward( -lipHeight ) crossSection() }.buildClosed().mirrorX() } @Piece fun bottom() : Shape3d { val profile : Shape2d = profile() val chamfered = inset( bottomChamfer ) val lipA = inset( lipThickness ) val inside = inset( wallThickness ) val insideChamfer = inset( wallThickness + bottomChamfer ) return ExtrusionBuilder().apply { joinStrategy = OneToOneJoinStrategy.instance crossSection( chamfered ) forward( bottomChamfer ) crossSection( profile ) forward( height - bottomChamfer ) crossSection() crossSection( lipA ) forward( -lipHeight ) crossSection() forward( -lipThickness + wallThickness ) crossSection( inside ) forward( -height - wallThickness + lipThickness + lipHeight + bottomChamfer + baseThickness ) crossSection() forward( -bottomChamfer ) crossSection( insideChamfer ) }.build() } @Piece override fun build() : Shape3d { val gap = 10 return bottom() .centerXY().color("Blue") + middle() .rotateX(180) .translateZ(height + middleHeight + slack + gap) .centerXY().color("Silver") + top() .rotateX(180).rotateZ(180) .translateZ(height + middleHeight + topHeight + slack*2 + gap*2 ) .centerXY().color("Yellow") } }