module Wumpus.Drawing.Shapes.Semicircle
(
Semicircle
, DSemicircle
, semicircle
) where
import Wumpus.Drawing.Basis.ShapeTrails
import Wumpus.Drawing.Paths
import Wumpus.Drawing.Paths.Intersection
import Wumpus.Drawing.Shapes.Base
import Wumpus.Basic.Kernel
import Wumpus.Core
import Control.Applicative
data Semicircle u = Semicircle
{ sc_ctm :: ShapeCTM u
, sc_radius :: !u
}
type instance DUnit (Semicircle u) = u
type DSemicircle = Semicircle Double
instance Functor Semicircle where
fmap f (Semicircle ctm r) = Semicircle (fmap f ctm) (f r)
hminor :: Floating u => u -> u
hminor radius = (4 * radius) / (3 * pi)
hmajor :: Floating u => u -> u
hmajor radius = radius hminor radius
mapCTM :: (ShapeCTM u -> ShapeCTM u) -> Semicircle u -> Semicircle u
mapCTM f = (\s i -> s { sc_ctm = f i }) <*> sc_ctm
instance (Real u, Floating u) => Rotate (Semicircle u) where
rotate ang = mapCTM (rotate ang)
instance (Real u, Floating u) => RotateAbout (Semicircle u) where
rotateAbout ang pt = mapCTM (rotateAbout ang pt)
instance Fractional u => Scale (Semicircle u) where
scale sx sy = mapCTM (scale sx sy)
instance InterpretUnit u => Translate (Semicircle u) where
translate dx dy = mapCTM (translate dx dy)
runDisplaceCenter :: (Real u, Floating u)
=> (u -> Vec2 u) -> Semicircle u -> Anchor u
runDisplaceCenter fn (Semicircle { sc_ctm = ctm
, sc_radius = radius }) =
projectFromCtr (fn radius) ctm
instance (Real u, Floating u) =>
CenterAnchor (Semicircle u) where
center = runDisplaceCenter $ \_ -> V2 0 0
instance (Real u, Floating u) =>
ApexAnchor (Semicircle u) where
apex = runDisplaceCenter $ \r -> V2 0 (hmajor r)
instance (Real u, Floating u) =>
BottomCornerAnchor (Semicircle u) where
bottomLeftCorner = runDisplaceCenter $ \r -> V2 (r) (negate $ hminor r)
bottomRightCorner = runDisplaceCenter $ \r -> V2 r (negate $ hminor r)
instance (Real u, Floating u) =>
CardinalAnchor (Semicircle u) where
north = apex
south = runDisplaceCenter $ \r -> V2 0 (negate $ hminor r)
east = runDisplaceCenter $ \r -> let x = pyth r (hminor r) in V2 x 0
west = runDisplaceCenter $ \r -> let x = pyth r (hminor r) in V2 (x) 0
pyth :: Floating u => u -> u -> u
pyth hyp s1 = sqrt $ pow2 hyp pow2 s1
where
pow2 = (^ (2::Int))
instance (Real u, Floating u, InterpretUnit u, Tolerance u) =>
CardinalAnchor2 (Semicircle u) where
northeast = radialAnchor (0.25*pi)
southeast = radialAnchor (1.75*pi)
southwest = radialAnchor (1.25*pi)
northwest = radialAnchor (0.75*pi)
instance (Real u, Floating u, InterpretUnit u, Tolerance u) =>
RadialAnchor (Semicircle u) where
radialAnchor ang = runDisplaceCenter $ \r ->
maybe zeroVec id $ semicircleRadialAnchor r ang
semicircleRadialAnchor :: (Real u, Floating u, InterpretUnit u, Tolerance u)
=> u -> Radian -> Maybe (Vec2 u)
semicircleRadialAnchor r ang =
fmap (pvec zeroPt) $ rayPathIntersection (inclinedRay zeroPt ang) rp
where
rp = anaTrailPath zeroPt $ semicircle_trail r
semicircle :: (Real u, Floating u, InterpretUnit u, Tolerance u)
=> u -> Shape Semicircle u
semicircle radius = makeShape (mkSemicircle radius) (mkSemicirclePath radius)
mkSemicircle :: InterpretUnit u
=> u -> LocThetaQuery u (Semicircle u)
mkSemicircle radius = qpromoteLocTheta $ \ctr theta ->
pure $ Semicircle { sc_ctm = makeShapeCTM ctr theta
, sc_radius = radius
}
mkSemicirclePath :: (Real u, Floating u, InterpretUnit u, Tolerance u)
=> u -> LocThetaQuery u (AbsPath u)
mkSemicirclePath radius = qpromoteLocTheta $ \ctr theta ->
return $ anaTrailPath ctr $ rsemicircle_trail radius theta