/Garden/Layering.foocad
Layering is a technique which creates genetic clones of plants. Take a branch, and bend it over so that it touches the soil. Now secure it in place using a brick, or a tent peg. That's it! The plant may send out roots, and you can the branch from the parent plant. To speed up the process, you could slice the outer layer of bark where it will touch the ground. Note that the roots tend to begin just below a "left node" i.e. where a leaf produded from the branch.
This model lets you layer plants without having to bend the branch to the ground. Place the gromet (printed with TPU, or just use a piece of foam) around the prepared branch. Slide on the cylinder, and slide the "join". Fill with growing medium (soil, compost, moss, vermiculite). Add a little water and pop on the lid.
import static uk.co.nickthecoder.foocad.layout.v1.Layout2d.* import static uk.co.nickthecoder.foocad.layout.v1.Layout3d.* class Layering : Model { // The length of the cylinder @Custom var length = 50 // The diameter of the cylinder @Custom var diameter = 30 // The thickness of the walls @Custom var thickness = 1.2 // The width of the gap (must be bigger than the diameter of the branch) @Custom var gap = 12 // The diameter of the hole in the gromet. Should be about the size of the branch. // If you use the piece name "gromets", it will produce a range of sizes, and ignore this value. @Custom var gromet = 5 @Custom var slack = 0.3 fun profile() = Circle( diameter/2 )//.sides(8).rotate(45/2) fun cylinder() : Shape3d { val profile : Shape2d = profile() val thin = profile - profile.offset(-thickness) val cylinder = thin.extrude(length) // The small holes ensure that water doesn't pool in the bottom. val hole = Circle( gap/2 ) val holes = Circle( thickness ).translateY(diameter/2-thickness*3).repeatAround( 9 ) val bottom = (profile - hole - holes).extrude(thickness) val slot = Cube( diameter, gap, length + 2 ).centerY().translateZ(-1) return (cylinder + bottom).color("Orange") - slot } @Piece fun join() : Shape3d { val profile : Shape2d = profile() val fat = (profile.offset(thickness+slack) - profile.offset(-thickness*2-slack)) / Square(diameter, gap).centerY().translateX(gap/2) val overlap = thickness*4 val thin1 = (profile.offset(thickness+slack) - profile.offset(+slack)) / Square(diameter, gap+overlap).centerY().translateX(gap/2) val thin2 = (profile.offset(-thickness-slack) - profile.offset(-thickness*2-slack*2)) / Square(diameter, gap+overlap).centerY().translateX(gap/2) val hole = Circle( gap/2 ) val slot = Square( diameter, gap ).centerY().mirrorX() val bottom = (profile.offset(-thickness-slack) - hole - slot).extrude(thickness) val foo = (fat + thin1 + thin2).extrude(length-thickness*4-slack*2) return (foo+bottom).color("yellow") } @Piece fun top() : Shape3d { val profile : Shape2d = profile() val hole = Circle( gap/2) + Square( diameter, gap ).centerY() val outerRing = (profile.offset(thickness+slack) - profile.offset(slack) - hole) .extrude(thickness*4) val innerRing = (profile.offset(-thickness-slack) - profile.offset(-thickness*2-slack) - hole) .extrude(thickness*4) val base1 = (profile.offset(thickness+slack) - profile.offset(-thickness-slack) - hole) .extrude(thickness).translateZ(thickness*3) val base2 = (profile.offset(-thickness-slack) - hole) .extrude(thickness) return (innerRing + outerRing+ base1 + base2).color("Green") } @Piece fun gromet( size : double ) : Shape3d { val envelope = Circle( diameter/2 - thickness*3 - slack ) val profile = ( Square(diameter,gap-slack*2).centerY() / envelope ) + Circle( gap/2 - slack ) - Square( diameter,2).centerY() - Circle( size/2 ) val bigger = ( Square(diameter,gap+thickness*2).centerY() / envelope ) + Circle( gap/2 +thickness ) - Square( diameter,2).centerY() - Circle( size/2 ) return profile.extrude( 6 ) + bigger.extrude( 3 ) } @Piece fun gromets() : Shape3d { val dy = gap + thickness*3 return gromet(4) + gromet(5).translateY(dy) + gromet(6).translateY(dy*2) + gromet(7).translateY(dy*3) + gromet(8).translateY(dy*4) } @Piece fun all() : Shape3d { return cylinder() + join().translateX(-diameter-thickness*2) + top().translateX(diameter+thickness*2) } override fun build() : Shape3d { return cylinder()+ join().mirrorZ().bottomTo(thickness+slack) + top().topTo( length + thickness ) + gromet(gromet).topTo( thickness -slack ) } }