import static uk.co.nickthecoder.foocad.along.v2.Along.* import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* /* A Cold Frame / Seating / Table / Storage Designed with double seed trays in mind, which measure 52x42 cm https://www.wilko.com/en-uk/wilko-black-premium-gravel-tray-52cm/p/0099388 Modular. Each item is constructed using layers; one layer just sits on top of a previous layer. Not shown on the model are either : Posts in the corners keeping things aligned There are two kinds of lid. a) A transparent one, when being used as a cold frame. This may use plastic, or glass. b) Seat sections. Each item has 2 seat sections which fit over the transparent lid. Each section is bigger than the lid. Rotate the sections by 90 degrees, and then then fit inside. (or keep them elsewhere then using as a cold frame). If we make the lid with GLASS, then cut it slightly smaller, so that plastic angled sections can be addded around the edges to hold the glass in place, and protect from the glass's edges. uPVC or anodised aluminium : https://www.wickes.co.uk/Wickes-Angle---Anodised-Aluminium-15-x-15mm-x-2m/p/188259 Alternate Lid ============= Instead of the glass being topmost, have the glass sit on a shelf inside the lid. OR the shelf is a piece of uPVC/Al "U" section trim which the glass fits into (the trim screws directly to the lid.(maybe with packing). */ class ColdFrame : Model { // A double seed tray is 42x56, and I want 2 per cold frame. // for 50mm extra width and front-to-back... @Custom var internal = Vector2( 890, 580 ) @Custom( about="Extra space for the seat to sit on top of the lid. Remember hinges!" ) var seatExtra = 30 // https://www.wickes.co.uk/Wickes-Deck-Board---25mm-x-120mm-x-2-4m/p/114551 @Custom var decking = Lumber( "Decking", 120, 25, "Green" ).stockLength( 2400 ) // decking cut width-ways in 4. Used for the posts, and the clear lid. // Note the thickness must be the same as decking's thickness. @Custom val quarter = Lumber( "Quarter", 25, decking.thickness, "Orange" ).stockLength( 2400 ) @Custom val third = Lumber( "Third", 38, decking.thickness, "Yellow" ).stockLength( 2400 ) @Piece fun seedTray() = ExtrusionBuilder().apply { crossSection( Square( 420, 520 ).offset(-25).center().roundAllCorners( 30 ) ) forward( 80 ) crossSection( 20 ) crossSection( 5 ) forward(10) crossSection() crossSection( -15 ) forward( -83 ) crossSection( -13 ) }.build().bottomTo(0) /* A placeholder for a tubuar heater https://www.ebay.co.uk/itm/133174729094?_trkparms=amclksrc%3DITM%26aid%3D1110006%26algo%3DHOMESPLICE.SIM%26ao%3D1%26asc%3D20201210111314%26meid%3D0c3b6b0306d6474f857d3d9aaed62d4e%26pid%3D101195%26rk%3D2%26rkt%3D12%26sd%3D303989286097%26itm%3D133174729094%26pmt%3D1%26noa%3D0%26pg%3D2047675%26algv%3DSimplAMLv9PairwiseWithPLXWeb%26brand%3DSUNHOUSE&_trksid=p2047675.c101195.m1851&amdata=cksum%3A1331747290940c3b6b0306d6474f857d3d9aaed62d4e%7Cenc%3AAQAGAAACELO5sAcQBCho2VkUOn3NsyVL1xh8j%252BO6V%252BZ1KuDlFGJOzkYTe%252B1%252Br9%252FdPR79pl4NIQzG6zZCGa8UixbkT2spMhRK%252BCaX3D2URKHFg8tOKeuUT31jFebjvofcwlJzJGrIbeaCnUGH%252FmQrScLj8uAYCdGymM%252FP0Oo1qRm5HOeA5VHhlEizjyMvmNNJaiQuaMwQ1LSEkt73WNlA1sKm917G1RWwQnHiQ7HjinNIo%252B5oxSuMq7McEPIjgIvN6SeKC6O%252FeMDXQTg%252BTsLjEs5BlWsfxBhI8uQ5rGNYO2uzRPnPawqQyN%252Bydc4eqQ%252FSiPlSwLHxSQEUb%252BmptvYu6u5clNnegnbED4Lkw7DXwAP6%252FOc8NWp2e6W9bRLp4%252BfcCgnsaJuB04jF%252FO34X7RtlMT1QCI61UsBd29bvuvH6MfuGJYz07CcVaOi4PuhjmuYwAAQz%252B5oRF1mwJ3Coz%252BRSE3b5tuMFd%252FuWmHT%252BO6iQ4F3dTFxFIkaizODjCRyhRL%252BY6fHIKc9%252FiZoy8TuW5ZhUHKchnU5YpP7uvnetTVH77fjJerT3H4mZ2AuN7UlYsPD8kNUt6fCOi8f8MAxthuaE%252FSThG3bCKPOO%252Bmi9CCDBWKW47K%252B%252BNiGDWdJ3xE4jb5OjhTU%252FhZahOll76woQwsH2YAnZ9v9nyjB%252Boh%252BKkADITEmedioQSFEMs3W7azcmb5qwtmFUy3%252Bsg%253D%253D%7Campid%3APL_CLK%7Cclp%3A2047675 */ fun heater() : Shape3d { return Cylinder( 713, 57/2 ).center().rotateY(90) + Cube( 20, 20, 81 ).tileX(2, 300).centerX().centerZ().backTo(50) } fun around( name : String, lumber : Lumber ) : Shape3d { val frontBack = lumber.cut( internal.x + decking.thickness() * 2 ) .label( "${name}FrontBack" ) .alongX() .centerX() .translateY( internal.y / 2 ) .mirrorY().also() val sides = lumber.cut( internal.y ) .darker() .label( "${name}Side" ) .alongY().translateY( lumber.thickness() ) .leftTo(frontBack.left) .centerY() .mirrorX().also() return frontBack + sides } /* A single ring of wood making up the sides of the cold frame. Stories can be stacked ontop of each other to make any height you like. Each storey has a post in each corner which aligns the story above it (or the lid). */ fun storey( withPosts : bool ) : Shape3d { val around = around("storey", decking) val posts = quarter.cut( decking.width() * 0.9 ) .color( "Blue" ) .label( "post" ) .translateX( -internal.x /2 ) .translateY( -internal.y /2 ) .topTo( around.top + quarter.thickness ) .mirrorX().also() .mirrorY().also() return if (withPosts) { (around + posts) } else { around } } @Piece fun lid() : Shape3d { val middle = third.cut( internal.y ) .label( "lidMiddle" ) .alongY() .centerXY() val wood = around( "lid", third ) + middle return wood } /* I've removed the trim, because without it, the seat can be placed half way, not only at ONE end. Also, without the trim, two seat sections can be stacked nicely. */ @Piece fun seat( pieces : int ) : Shape3d { val lengths = decking.cut( internal.y + decking.thickness() * 4 + seatExtra ) .color("LightGreen" ) .label( "seatLength" ) .alongY2() .tileX( pieces, 5 ) .centerXY() val edges = quarter.cut( lengths.size.x ) .color("LightGreen" ).darker() .label( "seatEdge" ) .alongX() .centerX() .frontTo( lengths.front ) .topTo(0) .mirrorY().also() val trim = quarter.cut( internal.y + decking.thickness() * 2 ) .color( "LightGreen" ).darker() .label( "seatTrim" ) .alongY() .rightTo( lengths.right ).centerY() .topTo(0) return lengths + edges // + trim } @Piece fun coldFrame(stories : int, withSeat : bool, withSupports : bool ) : Shape3d { val base = storey(true).tileZ(stories, 5 - quarter.thickness) val lid = lid().bottomTo( base.top + 5 - quarter.thickness ) val seat = seat( 4 ).bottomTo(lid.top) val seats = seat.leftTo(2).mirrorX().also() // Show a cylider heater in the bottom. // The seed trays are lifter up off the ground, and above the tubular heater. // The spare seating sections does fit below the supports. val heater = heater().previewOnly().backTo( base.back - 20 ).bottomTo(0) val supports = third.cut( base.size.y ) .cutZRatio( LapJoint( third, 1, decking.thickness ), 0 ) .cutZRatio( LapJoint( third, 1, decking.thickness ), 1 ) .label("support") .alongY() .tileX( 4, 200 ) .centerX() .frontTo(base.front).topTo(decking.width) var result : Shape3d = base + lid if (withSeat) result += seats if (withSupports) result += heater + supports return result } override fun build() : Shape3d { val a = coldFrame( 5, true, false ) val b = coldFrame( 2, false, false ).leftTo( a.right + 10 ) val c = coldFrame( 3, false, true ).backTo( a.front + 10 ) val coldFrames = a + b + c // Show seed trays in one of the cold frames val seedTrays = seedTray().previewOnly().leftTo(b.left + 40).tileX(2, 10) // Show the 2 piece seat sections stacked on eachother at the bottom of the cold frame. val extraSeat = seat(4).bottomTo(0) .rotateZ(90).frontTo( c.front + 30 ) val extraSeats = (extraSeat + extraSeat.mirrorZ().translate( 40, 0, quarter.thickness )) .bottomTo(0) return coldFrames + seedTrays + extraSeats } }