desk-hook.hs
A hook that can be attached to the side of a desk, possibly to hang headphones from.
Assumes a 18mm thick desk, but should be quite easy to modify for a different thickness.
#!/usr/bin/env stack
{- stack script --resolver lts-23.15
--package linear
--package waterfall-cad
--extra-dep waterfall-cad-0.6.3.0
--extra-dep opencascade-hs-0.6.3.0
-}
-- short-description: Hook, for the Underside of a Desk
--
-- description: A hook that can be attached to the side of a desk, possibly to hang headphones from.
-- description:
-- description: Assumes a 18mm thick desk, but should be quite easy to modify for a different thickness.
--
-- image: https://doscienceto.it/blog/photos/desk-hook-01.jpg
import qualified Waterfall
import Linear
import Data.Function ((&))
import Control.Lens ((^.), (.~ ))
hook :: Waterfall.Solid
hook =
let
w = 20
deskT = 18
t = 4
l = 95
clampA = Waterfall.centeredCube
& Waterfall.translate (zero & _yz .~ 0.5)
& Waterfall.scale (V3 w 20 (deskT + t * 2))
& Waterfall.roundFillet (t/2)
clampB = Waterfall.centeredCube
& Waterfall.translate (zero & _yz .~ 0.5)
& Waterfall.scale (V3 w l t)
& Waterfall.roundConditionalFillet (\(s, e) -> if s ^. _xy == e ^. _xy then Just 2 else Nothing)
clampGap = Waterfall.centeredCube
& Waterfall.translate (zero & _yz .~ 0.5)
& Waterfall.scale (V3 (w*2) l deskT)
& Waterfall.translate (zero & _y .~ t & _z .~ t)
screwR = 1.5
screwHole = Waterfall.centeredCylinder
& Waterfall.scale (V3 screwR screwR 100)
& (<> (Waterfall.unitCone & Waterfall.uScale 100 & Waterfall.rotate (unit _x) pi))
& Waterfall.translate (zero & _z .~ t & _y .~ (l - w/2 - t))
clamp = (clampA <> clampB) `Waterfall.difference` (clampGap <> screwHole)
hookR = 30
hookAH = 50
hookPath = Waterfall.pathFrom ((zero & _y .~ (l/2 - 20)) :: V3 Double)
[ Waterfall.bezierRelative (zero & _z .~ -hookAH/2) (zero & _z .~ -hookAH/2 & _y .~ hookR) (zero & _z .~ -hookAH & _y .~ hookR)
, Waterfall.arcViaRelative (zero & _z .~ (-hookR) & _y .~ (-hookR)) (zero & _y .~ (-2 * hookR))
]
{--hookPathB = Waterfall.pathFrom ((zero & _y .~ (l/2 + 5)) :: V3 Double)
[ Waterfall.bezierRelative (zero & _z .~ -hookAH/2) (zero & _z .~ -hookAH/2 & _y .~ (hookR -25)) (zero & _z .~ -hookAH & _y .~ (hookR-25))
]--}
hookPathC = Waterfall.pathFrom ((zero & _y .~ (l/2 + 35)) :: V3 Double)
[ Waterfall.bezierRelative (zero & _z .~ -hookAH/2) (zero & _z .~ -hookAH/2 & _y .~ (hookR -55)) (zero & _z .~ -hookAH & _y .~ (hookR-55))
]
hookTR = 12
Just (_, end) = Waterfall.pathEndpoints hookPath
hookEndcap = Waterfall.uScale hookTR Waterfall.unitSphere
& Waterfall.translate end
hookProfile = (Waterfall.uScale2D hookTR Waterfall.unitCircle)
hookScrewR = 5
hookScrewHole = Waterfall.centeredCylinder
& Waterfall.scale (V3 hookScrewR hookScrewR 400)
& Waterfall.translate (zero & _z .~ t & _y .~ (l - w/2 - t))
hook = ((Waterfall.sweep hookPath hookProfile
-- <> Waterfall.sweep hookPathB hookProfile
<> Waterfall.sweep hookPathC hookProfile
<> hookEndcap) `Waterfall.intersection`
( Waterfall.centeredCube & Waterfall.scale (zero & _x .~ w & _yz .~ 400))
) `Waterfall.difference` hookScrewHole
in clamp <> hook
main :: IO ()
main = Waterfall.writeSolid 0.1 "desk-hook.stl" hook