Exit Full View
ZipUp

/Bottles/Funnel.foocad

Funnel

A funnel which screws onto the top of a container.

The default thread is compatable with UK milk bottles.

FooCAD Source Code
import uk.co.nickthecoder.foocad.smartextrusion.v1.*
import static uk.co.nickthecoder.foocad.smartextrusion.v1.SmartExtrusion.*
import uk.co.nickthecoder.foocad.cup.v1.*
import static uk.co.nickthecoder.foocad.cup.v1.Cup.*
import uk.co.nickthecoder.foocad.threaded.v2.*

include Bottle.foocad

class Funnel : Model {

    @Custom
    val size = Vector3( 160, 100, 120 )

    @Custom
    var length : double = 10

    @Custom
    var round = 20

    @Custom( about="The default thread is compatible with the UK milk bottles" )
    var thread = Thread( 39, 5 )

    @Custom
    var wallThickness = 1.8

    meth cap() : Shape3d {
        val capHeight = 12

        val solid = Circle( thread.diameter/2 + 3 )
            .cup( capHeight, 6 ).baseThickness(wallThickness)
            .outsideBottom( ProfileEdge.roundedChamfer(3) )
            .insideBottom( Chamfer(wallThickness) )
            .outsideTop( Chamfer(1) )

        val hole = thread.threadedHole( solid.top - wallThickness*1.5 )
            .chamferStart(false)
            .chamferEnd(true)
            .bottomTo( wallThickness*1.5 )

        return solid - hole
    }

    @Piece
    @Slice( brimWidthInterior = 5 )
    meth funnel() : Shape3d {
    
        val rimHeight = 6
        val neckDiameter = thread.coreRadius()*2 - 4
        var throatDiameter = neckDiameter - wallThickness*2
        val size2d = Vector2( size.x, size.y )

        val cap = cap().topTo( size.z - length )

        val wideNeck = (Circle( cap.size.x/2 - 0.55 ) - Circle( throatDiameter/2 ) )
            .smartExtrude( 30 )
            //.offsetBottom( 0 )
            .topTo( cap.bottom + wallThickness*1.5 )

        val lip = (Circle( neckDiameter/2 ) - Circle( throatDiameter/2 ))
            .smartExtrude( cap.size.z + length )
                .outsideTop( Chamfer(1) )
            .bottomTo( cap.bottom )
        val capHole = Circle( throatDiameter/2 )
            .extrude( wallThickness *2 )
            .bottomTo( cap.bottom-0.01 )

        val squarish = Square( size2d ).center().roundAllCorners(round ) 
        val rim = (squarish - squarish.offset( -wallThickness ))
            .smartExtrude(rimHeight)
            .outsideBottom( ProfileEdge.chamfer(1).reverse() and ProfileEdge.flat(4) and ProfileEdge.chamfer(0.6) )

        val main = Bottle.extrudeRoundedSquareToCircle( cap.bottom - rim.top, size2d, round, neckDiameter )
            .bottomTo( rim.top )
            //.color("Orange")
        val insideMain = Bottle.extrudeRoundedSquareToCircle( cap.bottom - rim.top +0.02, size2d, round, neckDiameter, -wallThickness )
            .bottomTo( rim.top - 0.01 )

        return rim + main + cap + wideNeck - insideMain - capHole + lip 

    }

    @Piece( about="Test fit for the cap." )
    meth test() : Shape3d {
        length = -5
        val all = funnel()
        return all.translateZ( 4- size.z ) - Cube( 1000 ).centerXY().topTo(0)
    }


    override fun build() : Shape3d {

        return funnel()
    }

}