/Bathroom/ToothbrushHolder.foocad

A wall-mounted toothbrush holder for 4 toothbrushes and toothpaste. Each of the 5 holders are detachable for easy cleaning.
Similar shop-bought items do not have the long tubes, which is a problem. Either the holes are too small for the brush handle, or the toobrush head touches the holder (yuk!).
Each tube has a small hole at the bottom for drainage.
Print Notes
Due to the height of the tubes, a large brim is recommended.
Use the customiser to print shorter tubes for child toothbrushes.
Improvements
Make the toothpaste insert slightly wider.
class ToothbrushHolder : AbstractModel() {
@Custom
var insertHeight = 125
var insertWidth = 17
var insertThickness = 1
var pasteHeight = 60
var pasteR = 20
var pasteX = 20
var lipHeight = 2
var lipWidth = 5
var bracketThickness = 8
var bracketTaper = 3
val offset = 5
val slack = 0.5
var piece = ""
fun bushing( size : double ) : Shape3d {
val solid = Cylinder( bracketThickness, insertWidth/2 + insertThickness) +
Cylinder( lipHeight, insertWidth/2 + insertThickness + lipWidth)
.color("Green")
val hole = Cylinder( 30, size / 2 ).center()
return solid - hole
}
fun displayBrushInsert() : Shape3d {
val solid = Sphere( insertWidth/2 + insertThickness ) +
Cylinder( insertHeight, insertWidth/2 + insertThickness) +
Cylinder( lipHeight, insertWidth/2 + insertThickness + lipWidth)
.translateZ( insertHeight )
.color("Green")
val inside = Sphere( insertWidth/2) +
Cylinder( insertHeight+10, insertWidth/2 )
// The hole makes the print worse, so I prefer to drill it out manually
// val drainage = Cylinder( 200, 2 ).center()
// translate the inside up a little, so that the bottom is thicker
// and therefore it is more likely to be well printed
return solid - inside.translateZ(1)
}
fun pasteInsert() : Shape3d {
val solid = Sphere( pasteR+insertThickness ).hull( Sphere(pasteR+insertThickness).translateX(pasteX) ).center() +
Circle( pasteR+insertThickness ).hull( Circle( pasteR+insertThickness ).translateX(pasteX) ).center()
.extrude( pasteHeight ) +
Circle( pasteR+insertThickness + lipWidth ).hull( Circle( pasteR + insertThickness + lipWidth ).translateX(pasteX) ).center()
.extrude( lipHeight )
.translateZ( pasteHeight ).color("Green")
val inside =
(Sphere( pasteR ).hull( Sphere(pasteR).translateX(pasteX) ).centerX()) +
(Cylinder( pasteHeight+10, pasteR ).hull( Cylinder( pasteHeight+10, pasteR ).translateX(pasteX) ).centerX())
// The hole makes the print worse, so I prefer to drill it out manually
// val drainage = Cylinder( 200, 2 ).translateX(pasteX/2).mirrorX().also().center()
// translate the inside up a little, so that the bottom is thicker
// and therefore it is more likely to be well printed
return solid - inside.translateZ(1) //- drainage
}
fun displayBracket() : Shape3d {
val brushP = Circle(insertWidth/2 + insertThickness + offset)
val pasteHole = Circle( pasteR + insertThickness + slack ).hull(
Circle( pasteR + insertThickness + slack ).translateX(pasteX)
).center()
val profile = pasteHole.offset( offset ) +
layoutBrushes( brushP.hull( brushP.translateX(40) ) )
val hole = Circle( insertWidth/2 + insertThickness + slack )
.translateX(40)
val holes = layoutBrushes(hole) + pasteHole
val solid = ExtrusionBuilder.drum(
profile.offset(-bracketTaper),
profile,
bracketThickness
)
val mount = Square( 38, 30 )
.roundAllCorners( 4 )
.centerX()
.extrude( 10 )
.rotateX(90)
.translateY( pasteR + offset + insertThickness )
.translateZ( -30 + bracketThickness )
val screwHole = (
Cylinder( 50, 2 ) + (Cylinder( 10, 2, 10 ).mirrorZ().translateZ(4))
).rotateX(-90).translateY( pasteR + offset + insertThickness -8)
.translateZ(-6)
return mount + solid -
holes.extrude( 100 ).centerZ() -
screwHole.translateX(10).mirrorX().also()
}
fun layoutBrushes( shape : Shape3d ) : Shape3d {
return shape
.translateX(11).rotateZ(-20)
.mirrorX().also() +
shape
.translateX(5).rotateZ(-65)
.mirrorX().also()
}
fun layoutBrushes( shape : Shape2d ) : Shape2d {
return shape
.translateX(11).rotate(-20)
.mirrorX().also() +
shape
.translateX(5).rotate(-65)
.mirrorX().also()
}
@Piece
fun bracket() = displayBracket().mirrorZ().toOriginZ()
@Piece
fun brushInsert() = displayBrushInsert().mirrorZ().toOriginZ()
@Piece
fun bushing() = bushing( 13 )
@Piece
fun bushings() = bushing( 13 ) +
bushing( 14 ).translateX( 30 ) +
bushing( 15 ).translateY( 30 ) +
bushing( 12 ).translate( 30, 30, 0 )
@Piece
fun paste() = pasteInsert().mirrorZ().toOriginZ()
@Piece( printable = false )
override fun build() : Shape3d {
return displayBracket().color("Blue") +
pasteInsert()
.translateZ(-pasteHeight + bracketThickness + lipHeight ) +
layoutBrushes( displayBrushInsert().translateX(40) )
.translateZ(-insertHeight + bracketThickness + lipHeight )
}
}

