Haskell Diagrams: arrows with fixed orientation

187 views Asked by At

I need to draw arrows between two arbitrary "nodes". The arrow ends needs to enter or exit the nodes from one of the four cardinal directions: N, S, E, W.

data Dir = N | S | E | W
     deriving (Eq, Ord, Show)

cir, circles :: Diagram B
cir  = circle 0.3 # showOrigin # lw thick
circles = (cir # named "1") ||| strutX 3 ||| (cir # named "2")

ctrlPoint :: Dir -> V2 Double
ctrlPoint N = r2 (0, 1)
ctrlPoint S = r2 (0, -1)
ctrlPoint E = r2 (1, 0)
ctrlPoint W = r2 (-1, 0)

-- This function should specify an arrow shaft entering nodes from directions dir1 and dir2
shaft :: Dir -> Dir -> Trail V2 Double
shaft dir1 dir2 = trailFromSegments [bézier3 (controlPoint dir1) (controlPoint dir2) (r2 (3, 0))]

example = circles # connect' (with ... & arrowShaft .~ shaft N S ) "1" "2"

enter image description here

In the picture above, the arrow enters correctly from North in the first circle, and South in the second. However, if I setup the points vertically, everything is rotated:

circles = (cir # named "1") === strutY 3 === (cir # named "2")

enter image description here

This is not correct, because I wanted the arrow to enter from North and South, respectively. It seems the shaft of the arrow is rotated altogether... How to write my function shaft :: Dir -> Dir -> Trail V2 Double? Thanks

1

There are 1 answers

0
cdupont On

I found an answer using arrowFromLocatedTrail' instead:

-- control points for bézier curves
control :: Dir -> V2 Double
control N = r2 (0, 0.5)
control S = r2 (0, -0.5)
control E = r2 (0.5, 0)
control W = r2 (-0.5, 0)

-- shaft of arrows
shaft :: (P2 Double, Dir) -> (P2 Double, Dir) ->  Located (Trail V2 Double)
shaft (p, d) (p', d') = trailFromSegments [bézier3 (control d) ((p' .-. p) - (control d')) (p' .-. p)] `at` p

-- create a single arrow
mkArrow :: (P2 Double, Dir) -> (P2 Double, Dir) -> Diagram B
mkArrow a b = arrowFromLocatedTrail' (with & arrowHead .~ dart
                                    & lengths .~ veryLarge
                                    & shaftStyle %~ lw thick) (shaft a b)

This version performs the necessary transformations:

bézier3 (control d) ((p' .-. p) + (control d')) (p' .-. p)

Here is the signature ofbézier:

bézier3 :: v n -> v n -> v n -> Segment Closed v n 

It takes 3 vectors, named here V1, V2 and V3. bézier curve are by default not located in Diagrams, they just specify how to move.

enter image description here

So, to draw the bézier curve, we set:

V1 = control d
V2 = (p' .-. p) + (control d')
V3 = p' .-. p

The resulting bézier curve will located at p.