Arrows do not behave correctly under scaling #112

Closed
byorgey opened this Issue Sep 15, 2013 · 3 comments

Comments

Projects
None yet
2 participants
Owner

byorgey commented Sep 15, 2013

The head/tail are scale invariant and but the shaft is not: that is as it should be. However, the interaction of these facts with the way we do joints leads to funny gaps after scaling. For example:

a = arrowAt origin unitX

main = defaultMain $
  mconcat
  [ square 5 # alignBL # translate (r2 (-1,-1))
  , a
  , a # scale 4 # translateY 1
  ]

produces

arrowscalegap

Owner

byorgey commented Sep 15, 2013

One possibility that occurs to me for fixing this is to make a new primitive for arrows. All the functions that currently draw arrows would now simply create an arrow primitive; the current implementation would be provided as a default way for backends to draw them. That way we do not actually commit to drawing an arrow until it is done being transformed. I am not 100% sure that this will actually work.

This is not primarily a problem with the way we do joints but more just a consequence of the fact the shaft is not scale invariant and the heads and tails are. The shaft in the above example is just too small after scaling. Even arrows with no joints will present problems with scaling. For example if you scale a diagram that has an arrow connecting two points. The two points will not be connected in the result (If the you scale by a factor > 1 the arrow will not reach the points). This can be demonstrated visually by using arrowHead = tri, which has an empty joint.

Here is the math for a straight horizontal arrow. Suppose the head and tail (including their joints) are both of length x and the shaft is of length s. This arrow will connect two points A and B, that are s + 2x units apart. After scaling the diagram containing this arrow by n, the points A and B are now n(s + 2x) units apart. Since the head and tail are scale invariant, in order for the arrow to connect A and B the shaft has to be scaled by n + 2(n-1)x/s, instead of n. Things get even more complicated when we consider curved arrows as there may not be a closed form solution for the proper scale factor of a curved shaft.

This does not mean byorgey's proposed fix will not work, it may. However, since the arrow heads are pretty much custom, I don't think any of the back ends would be able to draw them without using the provided default.

byorgey was assigned Nov 7, 2013

@byorgey byorgey pushed a commit to diagrams/diagrams-core that referenced this issue Nov 10, 2013

Brent Yorgey initial work on implementing "delayed" subtrees
Delayed subtrees consist of a continuation which generate a QDiagram
when given the accumulated d-annotation at that point in the tree.
Useful for things which need to know the final transformation applied
to them before deciding what diagram to generate.  The prototypical
use case is arrows: see
diagrams/diagrams-lib#112 .  However, I hope
this may be useful for other things as well: for example, diagrams
which scale normally until hitting some maximum or minimum size, at
which point they refuse to scale any further (or more generally
diagrams which scale as some non-linear function of the transformation
applied to them).

The only downside is that the u-annotation must be fixed ahead of
time---doing otherwise requires a more general solution for constraint
solving.
8bb5e17

@byorgey byorgey pushed a commit that referenced this issue Nov 13, 2013

Brent Yorgey change arrow' to produce a delayed leaf.
The idea is that arrow' can now take the *final* transformation into
account so it can properly decide what to draw.  See #112.

Things seem to be almost working... but it seems we don't quite handle
frozen transforms properly yet, since things are flipped in the Y-axis.
c355559

This was referenced Nov 13, 2013

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