class Funnel : Model { var stemSize = Vector2(30, 6) var coneSize = Vector2(50, 30) var thickness = 1.2 var tipAngle = 45 fun funnel( large : Shape2d ) : Shape3d { val midD = stemSize.y * 1.5 val mid = Circle( midD / 2 ) val small = Circle( stemSize.y / 2 ) val funnel = ExtrusionBuilder().apply { crossSection( large.offset( thickness ) ) forward( thickness ) crossSection() crossSection( large ) forward( coneSize.y -thickness) crossSection( mid ) forward( stemSize.x ) crossSection( small ) forward( stemSize.y ) crossSection() crossSection( - thickness ) forward( - stemSize.y ) crossSection() forward( - stemSize.x - thickness/2 ) crossSection ( mid.offset( - thickness ) ) forward( - coneSize.y + thickness / 2) crossSection( large.offset( - thickness ) ) }.buildClosed() val sliceTip = Cube( coneSize.x ).centerXY() .rotateX( tipAngle ) .translateZ( stemSize.x + coneSize.y ) return funnel - sliceTip } //@Piece //fun squashed() = funnel( Circle( coneSize.x / 2 ).scaleX( 0.5 ) ) //intersection Cube(1000).centerXY().topTo(20) @Piece fun heart() : Shape3d { val half = Circle( 5.5 ).translate( 4, 3 ) hull Circle( 1 ).translate(0, -8) val heart = half.mirrorX().also().scale( coneSize.x / 20 ) return funnel( heart ) intersection Cube(1000).centerXY().topTo(27) } override fun build() : Shape3d { return funnel( Circle( coneSize.x / 2 ) ) } }