wumpus-tree-0.16.0: src/Wumpus/Tree/OTMConnectors.hs
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS -Wall #-}
--------------------------------------------------------------------------------
-- |
-- Module : Wumpus.Tree.Draw
-- Copyright : (c) Stephen Tetley 2011
-- License : BSD3
--
-- Maintainer : stephen.tetley@gmail.com
-- Stability : unstable
-- Portability : GHC
--
-- One-to-many connectors.
--
--------------------------------------------------------------------------------
module Wumpus.Tree.OTMConnectors
(
radialOTMC
, blankOTMC
, familyOTMC
, splayOTMC
) where
import Wumpus.Tree.Base
import Wumpus.Drawing.Paths.Absolute -- package: wumpus-drawing
import Wumpus.Basic.Kernel -- package: wumpus-basic
import Wumpus.Core -- package: wumpus-core
import Data.AffineSpace -- package: vector-space
import Data.Monoid
-- Pulling out the points (nodes) from parent plus list of
-- children.
radialNodes :: ( Real u, Floating u, InterpretUnit u
, CenterAnchor a, RadialAnchor a
, u ~ DUnit a )
=> a -> [a] -> [(Point2 u, Point2 u)]
radialNodes a as = map fn as
where
actr = center a
fn x = (radialAnchor ang0 a , radialAnchor ang1 x)
where (ang0, ang1) = anchorAngles actr (center x)
anchorAngles :: (Real u, Floating u)
=> Point2 u -> Point2 u -> (Radian,Radian)
anchorAngles f t = (theta0, theta1)
where
conn_v = pvec f t
theta0 = vdirection conn_v
theta1 = if theta0 < pi then theta0 + pi else theta0 - pi
--
-- @radialConn@ cannot be represented as a connector from
-- one-point-to-many-points as the initial points all start from
-- slightly different places.
--
-- | 'radialOTMC' has no need for the TreeDirection or height step.
--
radialOTMC :: ( Real u, Floating u, InterpretUnit u
, CenterAnchor a, RadialAnchor a
, u ~ DUnit a)
=> OTMAnchorConn u a
radialOTMC _ _ a xs = mconcat $ map fn $ radialNodes a xs
where
fn (p0,p1) = zapQuery (vertexPP [p0,p1]) >>= dcOpenPath
-- | Blank connector - nothing is drawn.
--
blankOTMC :: ( Real u, Floating u, InterpretUnit u
, CenterAnchor a
, u ~ DUnit a)
=> OTMAnchorConn u a
blankOTMC _ _ a _ = emptyLocImage `at` center a
--------------------------------------------------------------------------------
--
-- Note - can the \"crossbar\" of a famillyConn cannot be
-- calcuated parent-to-arbitrary-child?
--
-- Probably we need to know half the height step, rather than
-- calculate it from anchors.
--
-- Drawing a fmaily connector is quite horrible...
familyOTMC :: ( Real u, Floating u, Ord u, Tolerance u, InterpretUnit u
, CenterAnchor a, CardinalAnchor a
, u ~ DUnit a )
=> OTMAnchorConn u a
familyOTMC _ _ _ [] = mempty
familyOTMC dir h a xs =
let hh = 0.5 * h
(paF,caF) = famAnchors dir
ptick = outtick hh (center a) (paF a)
cticks = map (\o -> outtick hh (center o) (caF o)) xs
kids = sequence cticks
in ignoreAns ptick `mappend` (ignoreAns $ elaborate kids fn)
where
fn ps = case linkAll ps of
Nothing -> emptyLocImage `at` (center a)
Just path -> zapQuery (toPrimPath path) >>= dcOpenPath
famAnchors :: (CardinalAnchor a, u ~ DUnit a )
=> TreeDirection -> (a -> Anchor u, a -> Anchor u)
famAnchors TREE_UP = (north, south)
famAnchors TREE_DOWN = (south, north)
famAnchors TREE_LEFT = (west, east)
famAnchors TREE_RIGHT = (east, west)
outtick :: (Real u, Floating u, InterpretUnit u)
=> u -> Point2 u -> Point2 u -> Image u (Point2 u)
outtick ll p0 p1 =
let v0 = pvec p0 p1
ang = vdirection v0
v1 = avec ang ll
p2 = p0 .+^ v1
in replaceAns p2 (straightLine p1 p2)
-- | The input list is expected to be ordered...
--
linkAll :: (Real u, Floating u, Ord u, Tolerance u)
=> [Point2 u] -> Maybe (AbsPath u)
linkAll [] = Nothing
linkAll xs = Just $ optimizeLines $ vertexPath xs
splayOTMC :: ( Real u, Floating u, Ord u, Tolerance u, InterpretUnit u
, CenterAnchor a, CardinalAnchor a
, u ~ DUnit a )
=> OTMAnchorConn u a
splayOTMC _ _ _ [] = mempty
splayOTMC dir _ a xs =
let (paF,caF) = famAnchors dir
p0 = paF a
in mconcat $ map (\x -> fn p0 (caF x)) xs
where
fn p0 p1 = zapQuery (vertexPP [p0,p1]) >>= dcOpenPath
--------------------------------------------------------------------------------