import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* class ColdCanContraption : Model { @Custom var canD = 66 @Custom var canHeight = 115 @Custom var angle = 3.0 @Custom var bottomCans = 4 override fun build() : Shape3d { val bottomLength = canD*(bottomCans-1) val thickness = 4 val pointR = thickness/2 val innerR = canD*1.2 val outerR = innerR + thickness val extraHeight = Degrees.tan( angle ) * bottomLength val thickerFront = 8 val bottomSlope = PolygonBuilder().apply { moveTo(0,0) val foo = Degrees.sin(60) val bar = Degrees.cos(60) circularArcBy( (canD/2+thickness) *foo, (canD/2+thickness)*bar, canD/2+pointR, false, true ) circularArcBy( -pointR*2*foo, pointR*2*bar, pointR, false, true ) circularArcBy( -canD/2*foo, -canD/2*bar, canD/2, false, false ) lineBy( -bottomLength, extraHeight ) circularArcBy( -innerR, innerR, innerR, false, false ) circularArcBy( -pointR*2, 0, pointR, false, true ) circularArcBy( outerR, -outerR - extraHeight, outerR, false, true ) }.build() val topLength = bottomLength - canD*0.1 val topLine = PolygonBuilder().apply { moveTo(0,0) lineBy( topLength - canD/2, 0 ) bezierBy( Vector2( canD/8, 0 ), Vector2(canD/4, canD*0.1), Vector2(canD/2, canD*0.1) ) }.buildPath().thickness(thickness) val topSlope = topLine.rotate(angle).roundAllCorners(thickness/2) .leftTo(-bottomLength-canD*0.15) .translateY( canD + thickness + extraHeight + thickness) // Slack is "thickness" val can = Cylinder( canHeight, canD/2 ).previewOnly() val bottomCans = can.tileX(4).mirrorX().rotateZ(-angle).translateY(canD/2+thickness) val midCan = can.leftTo( -bottomLength-innerR ).frontTo(canD*0.95) val topCans = can.tileX(3).translateX(canD*0.75).rotateZ(180+angle).translateY(canD*2) val cans = bottomCans + midCan + topCans return bottomSlope.extrude( 20 ).color("Green") + topSlope.extrude( 20 ).color( "Green" ) + cans + Cube( 1, thickness, 22 ) + Cube( 1, thickness + extraHeight, 22 ).leftTo( -bottomLength ) } }