{-# OPTIONS -Wall #-} -------------------------------------------------------------------------------- -- | -- Module : Wumpus.Drawing.Connectors.Base -- Copyright : (c) Stephen Tetley 2011 -- License : BSD3 -- -- Maintainer : Stephen Tetley -- Stability : highly unstable -- Portability : GHC -- -- Connectors... -- -------------------------------------------------------------------------------- module Wumpus.Drawing.Connectors.Base ( ConnectorPathQuery , SpacingProjection , ArrowTip(..) , ArrowConnector , ConnectorConfig(..) , ConnectorPathSpec(..) , renderConnectorConfig , arrowDecoratePath , leftArrowConnector , rightArrowConnector , uniformArrowConnector ) where import Wumpus.Drawing.Connectors.ConnectorProps import Wumpus.Drawing.Paths import Wumpus.Basic.Kernel -- package: wumpus-basic import Wumpus.Core -- package: wumpus-core import Data.Monoid type SpacingProjection u = ConnectorProps -> Point2 u -> Point2 u -> Query u (Point2 u) -- | The type of Connectors - a query from start and end point -- returning an AbsPath. -- type ConnectorPathQuery u = ConnectorQuery u (AbsPath u) -- | Arrowhead /algorithm/ - the components of an arrowhead. -- -- Retract distance is rather vague - depending on the arrowhead -- it may represent a flush join between the path and the tip -- or a join that uses the z-order (tip over path) to create the -- join. -- -- \*\* WARNING \*\* - pending revision... -- data ArrowTip = ArrowTip { retract_distance :: En , tip_half_len :: En , tip_deco :: LocThetaGraphic En } newtype ConnectorPathSpec u = ConnectorPathSpec { getConnectorPathSpec :: ConnectorProps -> ConnectorPathQuery u } -- | total_path is the path before accounting for arrow -- retract distances. -- data ConnectorConfig u = ConnectorConfig { conn_arrowl :: Maybe ArrowTip , conn_arrowr :: Maybe ArrowTip , conn_path_spec :: ConnectorPathSpec u } -- Ideally there should be a plus operation to combine tips -- allowing double tips. -- type ArrowConnector u = ConnectorImage u (AbsPath u) -- | NOTE - the prefix /render/ needs (re-) consideration... -- -- If it is a good prefix other functions e.g. drawPath should -- use render rather than draw. -- renderConnectorConfig :: (Real u, Floating u, InterpretUnit u) => ConnectorProps -> ConnectorConfig u -> ConnectorImage u (AbsPath u) renderConnectorConfig props (ConnectorConfig mbl mbr pspec) = promoteConn $ \src dst -> liftQuery (qapplyConn path_spec src dst) >>= \tot_path -> connectorSrcSpace props >>= \sepl -> connectorDstSpace props >>= \sepr -> arrowDecoratePath mbl mbr $ shortenL sepl $ shortenR sepr tot_path where path_spec = getConnectorPathSpec pspec props arrowDecoratePath :: (Real u, Floating u, InterpretUnit u) => Maybe ArrowTip -> Maybe ArrowTip -> (AbsPath u) -> Image u (AbsPath u) arrowDecoratePath mbl mbr initial_path = uconvertCtx1 (maybe 0 retract_distance mbl) >>= \retl -> uconvertCtx1 (maybe 0 retract_distance mbr) >>= \retr -> let (p1,theta1) = atstart initial_path (p2,theta2) = atend initial_path new_path = shortenL retl $ shortenR retr initial_path arrl = mbTip p1 (pi + theta1) mbl arrr = mbTip p2 theta2 mbr in replaceAns initial_path $ decorate ZABOVE (renderPath OSTROKE new_path) (arrl `mappend` arrr) where mbTip pt ang = maybe emptyImage (supplyLocTheta pt ang . uconvF . tip_deco) -- | Shorthand... -- leftArrowConnector :: (Real u, Floating u, InterpretUnit u) => ConnectorProps -> ConnectorPathSpec u -> ArrowTip -> ConnectorImage u (AbsPath u) leftArrowConnector props cpath tip = renderConnectorConfig props cfg where cfg = ConnectorConfig { conn_arrowl = Just tip , conn_arrowr = Nothing , conn_path_spec = cpath } rightArrowConnector :: (Real u, Floating u, InterpretUnit u) => ConnectorProps -> ConnectorPathSpec u -> ArrowTip -> ConnectorImage u (AbsPath u) rightArrowConnector props cpath tip = renderConnectorConfig props cfg where cfg = ConnectorConfig { conn_arrowl = Nothing , conn_arrowr = Just tip , conn_path_spec = cpath } uniformArrowConnector :: (Real u, Floating u, InterpretUnit u) => ConnectorProps -> ConnectorPathSpec u -> ArrowTip -> ConnectorImage u (AbsPath u) uniformArrowConnector props cpath tip = renderConnectorConfig props cfg where cfg = ConnectorConfig { conn_arrowl = Just tip , conn_arrowr = Just tip , conn_path_spec = cpath }