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() } }