Exit Full View
Up

/Garden/PlantLabel2.foocad

PlantLabel2

I'm reinventing plant labels. Most of my seedlings are the same year after year. So why do I clean off the lables, and write the names again each year? Because finding the correctl label is a PITA.

But it could be easy if I keep them in alphabetical order, and have different sets (such as a flower set, a salad/herb set a vegetable set etc).

Print Notes

My first batch used PLA, but this tends to warp over time (when in the sun). I may try again with PETG.

Use different colours for each "key ring".

  • Red : Fruit and Veg (excluding leafy veg)
  • Yellow : Flowers
  • Green : Leafy Veg + Herbs

I've used the same colours for my seed boxes ;-)

Colours

  • Leaf Veg and Herbs : 3DQF British Racing Green?
  • Other Veg : 3DQF Slignal Red
  • FLowers : Filamentive Yellow
  • Cukes : Eryone Galaxy Red
  • Stakes and slots : 3DQF 2 of : Jet Black? Pearl Black? Regal Black?
FooCAD Source Code
import static uk.co.nickthecoder.foocad.chamferedextrude.v1.ChamferedExtrude.*
import static uk.co.nickthecoder.foocad.changefilament.v1.ChangeFilament.*
import static uk.co.nickthecoder.foocad.layout.Layout2d.*
import static uk.co.nickthecoder.foocad.layout.Layout3d.*

class PlantLabel2 : Model {

    //@Custom(about="Length, width and thickness os the main part (does not include the text)")
    var size = Vector3( 80, 12.6, 1.2 )

    //@Custom( about="1 or 2 layers is normal" )
    var textThickness = 0.6

    //@Custom(about="Should be about doub-le the wire's diameter")
    var holeD = 5.0

    //@Custom(about="Length and width of the slot. Y should be just less than the wire's diameter")
    var slotSize = Vector2( 10, 2 )

    //@Custom    
    var style = TextStyle("Liberation Sans:style=Bold", 8)

    //@Custom(about="Should we add automatic printer pauses to change filament?")
    var changeColor = true

    @Custom( about="Text to appear on the labels (separated by new lines)", lines=10 )
    var names = """Lettuce
Mustard
Rocket
Spinach
Swiss Chard
Basil
Chamomile
Coriander
Fennel
Parsley
Thyme"""

    @Custom
    var columns = 2
    
    @Custom( about="Add extra to labels to help bed adhesion" )
    var ears = true

    //@Custom
    var slotMargin = 2.0

    //@Custom(about="The slack. The Y value is slack in the z direction!")
    var slack = Vector2( 1.0, 0.5 )

    var stakeExtra = 40
    var tStakeExtra = 40

    @Piece
    fun label() = label("")

    @Piece
    fun labels() : Shape3d {
        var y = 0
        var x = 0
        var column = 1
        var union : Shape3d = Union3d()

        for ( name in names.split("\n") ) {
            val label : Shape3d = label( name ).frontTo( y ).leftTo(x)
            if (column < columns) {
                x = label.right + 3
                column ++
            } else {
                x = 0
                column = 1
                y = label.back + 3
            }
            union = union + label
        }

        return union
    }
    fun labels( gcode: GCode ) {
        if ( changeColor && names != "" ) {
            pauseAtHeight( gcode, size.z, "Change Filament" )
        }
    }

    fun hole() : Shape2d {
        return (Circle( holeD/2 ).sides(4).translateX(slotSize.x/2) hull Square(slotSize.x/2, slotSize.y).centerY())
            .mirrorX().also().rightTo(size.x+holeD/2)
    }

    fun label( name : String ) : Shape3d {
        
        val outline = labelOutline()
        val hole : Shape2d = hole()
        val main = (outline-hole).extrude(size.z)

        val result = if (name == "" ) {
            main
        } else {
            val text = Text( name, style )
                .centerXTo(main.middle.x)
                .centerY()
                .extrude( size.z + textThickness )
                .color( "Black" )

            if (text.right > hole.left) {
                main + text.rightTo( hole.left )
            } else {
                main + text
            }
        }
        return if (ears) {
            val ears = Circle( size.y*0.8 ).roundAllCorners(3).extrude( 0.3 )
                .rightTo(3).centerYTo(result.middle.y)
                .mirrorX().leftTo(result.right-3).also(2)
                .margin( -size.y*0.8-1.5, -size.y, 0 )
                .color("Green")
            result + ears
        } else {
            result
        }
    }
    fun labelOutline() = Square( size.x, size.y ).roundAllCorners(size.y/3).centerY()

    @Piece
    fun slotSide() : Shape3d {

        val outline = labelOutline().offset(slack.x)
        val window = outline.offset(-slotMargin/2)
        val outside = outline.offset(slotMargin)

        val inside = outline.extrude( size.z + textThickness + slack.y + 1).bottomTo( size.z )

        return (outside-window).extrude(size.z * 2 + textThickness + slack.y ) -
            (inside.translateX(-10).also())
    }

    @Piece
    fun slotTop() : Shape3d {

        val outline = labelOutline().offset(slack.x)
        val window = outline.offset(-slotMargin/2)
        val outside = outline.offset(slotMargin)

        val inside = outline.extrude( size.z + textThickness + slack.y + 1).bottomTo( size.z )
            .translate(-10, -6, 0).also()

        return (outside-window).extrude(size.z * 2 + textThickness + slack.y ) - inside
    }

   
    @Piece
    fun stake() : Shape3d {
        val slot = slotSide()
        val width = slot.size.y
        val length = slot.size.x + stakeExtra

        val outline = PolygonBuilder().apply {
            radius(width/3)
            moveTo(0,0)
            lineTo(0,width)
            lineTo(length,width)
            radius(1)
            lineTo(length + width*1.5, width/2)
            radius(5)
            lineTo(length,0)         
        }.build().centerY()

        return outline.extrude(size.z)
    }

    @Piece
    fun tStake() : Shape3d {
        val slot = slotSide()
        val width = slot.size.y
        val length = tStakeExtra

        val vertical = PolygonBuilder().apply {
            radius(width/3)
            moveTo(0,0)
            lineTo(0,width)
            lineTo(length,width)
            radius(1)
            lineTo(length + width*1.5, width/2)
            radius(5)
            lineTo(length,0)         
        }.build().rotate(-90).centerX()

        val outline = labelOutline().offset(slack.x + slotMargin).centerX() + vertical
    
        return outline.extrude(size.z)
    }

    @Piece
    fun nStake() : Shape3d {
        val slot = slotSide()
        val width = slot.size.y * 2/3
        val length = tStakeExtra

        val vertical = PolygonBuilder().apply {
            radius(width/3)
            moveTo(0,0)
            lineTo(0,width)
            lineTo(length,width)
            radius(1)
            lineTo(length + width*1.5, width/2)
            radius(5)
            lineTo(length,0)         
        }.build().rotate(-90).translateX(size.x * 0.6).also().centerX()

        val outline = labelOutline().offset(slack.x + slotMargin).centerX() + vertical
    
        return outline.extrude(size.z)
    }

    /*
        To cover up the rough end of a piece of wire that the labels are threaded onto.
    */
    @Piece
    fun endStop() : Shape3d {
        val solid = Square( 10, 5 ).roundCorner(2,1).roundCorner(1,1)
            .chamferedExtrude( 5, 1 )
            .center()

        val hole = Cylinder.hole(10,2.4/2).rotateY(90).center()
            .rightTo(0)

        return (solid - hole).bottomTo(0)
    }

    override fun build() : Shape3d {
        return label("Example").centerX() +
            slotSide().color("Orange").mirrorZ().leftTo(0).bottomTo(0) +
            stake().topTo(0).color("Blue") +
            slotSide().color("LightGreen").mirrorZ().bottomTo(0).centerX().backTo(-20) +
            tStake().topTo(0).color("Green").backTo(-20)
    }
}