Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow trail sections as arrow shafts #151

Open
EdwardMorehouse opened this issue Jan 31, 2014 · 6 comments
Open

allow trail sections as arrow shafts #151

EdwardMorehouse opened this issue Jan 31, 2014 · 6 comments

Comments

@EdwardMorehouse
Copy link

I've been trying to use Diagrams' named subdiagrams and arrows to draw commuting (categorical) diagrams using connect and friends, and found that the arrows don't behave the way I expected.

For shafts that are not straight lines, when using connectOutside(') or head and tail gaps with connect('), I would like the trail that I specify for the shaft to connect the origins of the source and target diagrams, but only the section (as in Diagrams.Parametric) outside of their boundaries (in the case of connectOutside) or the gap distances away from their origins (in the case of gaps) to be stroked.

The problem with the current behavior is that it is very fiddly to get curved arrows, and especially self-loops, to look right. Is the mode of use described above something that might be supported in the future?

@jeffreyrosenbluth
Copy link
Member

Can you provide an example diagram to us help understand what you are trying to do.

@EdwardMorehouse
Copy link
Author

Does this help?

-Ed

On 2014-01-31 5:10 PM, Jeffrey Rosenbluth wrote:

Can you provide an example diagram to us help understand what you are
trying to do.


Reply to this email directly or view it on GitHub
#151 (comment).

{-# LANGUAGE NoMonomorphismRestriction #-}

import Diagrams.Prelude
import Diagrams.Backend.SVG.CmdLine
import Diagrams.TwoD.Path.Metafont

main = mainWith (diagram # pad 1.1)

compile with:
ghc --make ArrowsExample.lhs ; ./ArrowsExample -o ArrowsExample.svg -w 800

Suppose I choose a shaft that I would like to use for arrows from things to themselves:

shaft =
metafont
(
origin
.- leaving (unitY # rotateBy (1/6)) <> arriving unitX -.
p2 (0,2)
.- leaving unitX <> arriving (unit_Y # rotateBy (-1/6)) -. endpt
origin
) # reverseTrail

It would be convenient to just be able to say something like:

try_1 = circle 0.25 # named "p_1" # connectOutside' (with & arrowShaft .~ shaft) "p_1" "p_1"

And have Diagrams figure out for me which section of the shaft trail
is outside of the perimeter of the dot and use that as the arrow shaft.

But this fails with, Maybe.fromJust: Nothing

So instead of connectOutside' I can just use connect' with head and tail gaps:

try_2 = circle 0.25 # named "p_2" # connect' arrowOpts "p_2" "p_2"
where
arrowOpts =
(with
& arrowShaft .~ shaft
& arrowHead .~ spike
& headSize .~ 0.5
& headGap .~ 0.5
& tailGap .~ 0.5
)

But connect' doesn't use the section of the trail beyond the gaps for the shaft,
rather the whole trail.
Okay, so I can just take the section myself:

shaft' = section shaft (1/10) (9/10)

And now it should work, right?

try_3 = circle 0.25 # named "p_3" # connect' arrowOpts "p_3" "p_3"
where
arrowOpts =
(with
& arrowShaft .~ shaft'
& arrowHead .~ spike
& headSize .~ 0.5
& headGap .~ 0.5
& tailGap .~ 0.5
)

Except now the two endpoints aren't the same so it doesn't seem fair
to use it to connect a point to itself.
And indeed, the tip isn't really pointed in the right direction anymore.
Also, the arrow has become rotated by an angle that's very difficult to figure out
short of by trial-and-error.

This is what I meant by "fiddly".

Is there a way to do what I want -- basically atop the circle and the shaft,
and draw the arrowhead tip at the intersection (plus gap, if any) --
short of using connectPerim' and calculating the angles involved?

diagram :: Diagram B R2
diagram =
strokeTrail shaft ||| strutX 2 ||| try_2 ||| strutX 2 |||
strokeTrail shaft' ||| strutX 2 ||| try_3

@jeffreyrosenbluth
Copy link
Member

I ran the examples and I understand the problem. Let me think about it and see it there is some way to get the semantics you are looking for.

@jeffreyrosenbluth
Copy link
Member

Have you thought about using the connecPerim' funcition as in the dfa example in the tutorial,
http://projects.haskell.org/diagrams/doc/arrow.html

@jeffreyrosenbluth
Copy link
Member

Ed, I had a chance to look into the this issue a bit more, and I'm afraid the current implementation of arrows does not cover this case. The length of an arrow is defined to be the linear distance from its tip to its tail and the entire arrow is scaled to a give length. An arrow that starts and ends at the same point has zero length. You could do something like what I do in the DFA example in the tutorial as I mentioned above, but I'm not sure it will suffice for what you are trying to do.

Another possible work around is to use two arrows, one with no head starting at the dot and going to some point off the dot, and one with no tail starting at the point off the dot and ending at the dot.

The functionality you are looking for would be nice to have and I will look into adding it.

@EdwardMorehouse
Copy link
Author

Hi Jeffrey,

Thanks for taking the time to look into this.

Yes, I certainly can use connectPerim' in the manner of the DFA example
of the tutorial. But to get the result that I want, I must then
manually calculate the angles and the parameters for the section. I do
not (yet, anyway) know how to get Diagrams to do this for me, or else I
would just write a connect'' that does it automatically.

I humbly submit that a natural use case with curved arrows is to have
them placed as though they were connecting the origins of the source and
target diagrams, but to have only the section outside of their envelopes
-- modulo head and tail gaps -- to be stroked; with the tips (if any)
then place at the ends of the stroked section.

I believe (but am not completely sure) that this is what TikZ does by
default when drawing paths between "nodes" (basically, subdiagrams).
The results usually "look right", I think because my mind extrapolates
the paths of the arrows into (or behind) the nodes. The effect is
especially pleasing when there are multiple curved arrows going into or
out of a node.

Anyway, thanks again for looking into this. I was hoping that there was
an easy answer, but if not then I will dig into Diagrams a bit more and
see if I can figure out a way to do what I want.

With best wishes,

-Ed

On 2014-02-01 11:20 AM, Jeffrey Rosenbluth wrote:

Ed, I had a chance to look into the this issue a bit more, and I'm
afraid the current implementation of arrows does not cover this case.
The length of an arrow is defined to be the linear distance from its tip
to its tail and the entire arrow is scaled to a give length. An arrow
that starts and ends at the same point has zero length. You could do
something like what I do in the DFA example in the tutorial as I
mentioned above, but I'm not sure it will suffice for what you are
trying to do.

Another possible work around is to use two arrows, one with no head
starting at the dot and going to some point off the dot, and one with no
tail starting at the point off the dot and ending at the dot.

The functionality you are looking for would be nice to have and I will
look into adding it.


Reply to this email directly or view it on GitHub
#151 (comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants