Closed jonschz closed 1 year ago
@psisquared2: the style does not currently seem compatible with bend left
. If it is possible to fix this, how difficult do you think it would be to extend this style to also support triple arrows (or possibly even higher)? This is something it is currently tricky to do with tikz-cd, but would be very useful.
I will take a look at bending soon, can't tell yet how hard it is going to be. A quick test has shown that using Bezier curves is possible, but computing the anchor points might be a challenge. I will try to recycle \tikz@to@compute
- a few tests suggest that it might be possible, but there are glitches and I don't know yet if they can be fixed.
Adding triple arrows is as easy as adding one line, and n-fold arrows for fixed n is hardly more difficult. Support for variable n might not be as easy (though I suspect possible using foreach
).
This is an interesting idea. Of course the difficulty is to make it composable with all other TikZ options.
Assuming this can be overcome, it's probably a good addition to PGF/TikZ itself, possibly as a separate library. And for that purpose, I think the more general feature of drawing any number parallel splines would be somewhat important.
(It should also be mentioned that the glitches you refer to are, in fact, glitches in your PDF renderer. Your here is in a generic sense — everyone's PDF rendered has this problem :smile:.)
Hello everyone,
based on the feedback I went on to implement multiple arrows and bending (with some known issues, see below).
\usepgflibrary{intersections}
for full functionality, though there is also backup code in case the library cannot be used (Question: Is there any reason why we would not want to use the intersections library?).to path
: straight lines, absolute bending (in=..,out=..
), relative bending (bend left=..
, relative=true
), looseness settings, explicit control points (in control=...
).shorten <
and shorten >
work and give the same results as Rightarrow
.shift left=..
, which now works both before and after nRightarrow
.Rightarrow
(or, more generally, the double
option of tikz), nRightarrow
produces the expected output with opacity < 1
.Rightarrow
.Rightarrow
places the labels with respect to the centre curve going all the way to the arrow's tip, while nRightarrow
considers only the rightmost line, which ends way before the tip. The centre of the rightmost line seems to be "too early" on the path, so it is still sloped siginficantly. I as surprised to learn that the automatic label positions are limited to 8 directions. One workaround is to specify the label position as in [..., "a" left, ...]
. I also noticed a difference between article
and minimal
in the behaviour that I cannot explain.As can be seen in all screenshots, the arrow's body decreases in width towards its centre, with the width even going negative for extreme angles. It is obvious that one needs to change the contol points for the lines which trace the left and right boundaries of the arrow's body. This boils down to constructing a parallel curve of the Bezier curve describing the arrow's body.
I found a Review paper, see also this Stackexchange discussion. I'll post again if there is any progress.
inner sep
. This is especially significant for wide arrows, where the normal label position can be inside the arrow. \ar[Rightarrow, double distance=7pt]
has the same issue.--
instead of .. controls ..
.I would also value feedback concerning
Concerning your points:
Assuming this can be overcome, it's probably a good addition to PGF/TikZ itself, possibly as a separate library.
I agree that this would be a great addition, though I guess this general problem is much harder. Joins between different path sections is the first difficulty to come to my mind.
It should also be mentioned that the glitches you refer to are, in fact, glitches in your PDF renderer
I fully agree with respect to the vertical bar which shoudld not be visible. However, as to horizontal lines disappearing on certain zoom levels, it is my impression that any kind of rendering software necessarily has to distinguish "important" and "less important" features when rendering, especially at low resolutions. Naively rendering at higher resolution and downscaling will produce glitches in other situations, like thin lines becoming light gray. With that attitude, it makes perfect sense to prioritise the middle white line over the slightly wider black line, as the renderer has no way of knowing that the white line is "less important" than the black line in the back.
@psisquared2: sorry for the long delay. The updated arrows look very promising, and if the few remaining issues can be addressed, this would be very exciting to have in tikz-cd. I have a few comments/questions.
Features
shorten
behaviour of curved arrows in in TikZ is rather odd (I would argue broken), since it changes the arrow shape, rather than just retracting the start and end. It seems nRightArrow
has the same behaviour. I suppose it would be difficult/undesirable to change how this behaves to act more sensibly?hook
, harpoon
, and tail
? It should not be a high priority to support these, since they are not supported by Rightarrow
either (see https://github.com/astoff/tikz-cd/issues/1), but it would be an added bonus if they also worked.Issues
The cleanest solution (though apparently impossible without deeper modifications of pgf) would be to draw a separate invisible path with the same settings from the start to the tip and place the labels only.
I agree this sounds like the best solution, but I am not familiar enough with pgf to know how to achieve it.
We could also make the entire arrow more symmetric by adding a straight piece to the arrow's tail with the same length as the arrow's head.
Personally, I would be happier with the most aesthetic output, even if it doesn't exactly match Rightarrow
. Others may have different opinions on this, though.
Constant width I can share the approach used in https://github.com/varkor/quiver, where I had to deal with the same issue: perhaps it will be helpful. As you point out, for a given Bézier curve, a parallel curve is not necessarily also Bézier. This means ones either has to approximate the parallel curves with Bézier curves, or draw them some other way. My solution was to draw several Bézier curves, with identical control points, of different thicknesses: the outermost two lines are drawn as a single very thick black Bézier curve, then a thinner white Bézier curve is drawn on top of it, then a thinner black Bézier curve on top of that one, and so on. This means that each line is perfectly positioned. The naïve implementation will not deal correctly with opacity, but this can be addressed by masking instead of painting-over. (The source is here, in case it is helpful.)
Dear @varkor, thank you for the in-depth response.
I am going through an example implementation of parallel Bezier curves: interactive example, source code. Looks promising so far, but I'm not yet sure how hard it will be to get this working in LaTeX. I'll post here if there's any notable progress.
I suppose it would be difficult/undesirable to change how this behaves to act more sensibly?
While I think that the default behaviour is perfectly fine for straight arrows, I agree that it is far from ideal for curved arrows. However, to my knowledge, shortening a Bezier curve C(t), 0 <= t <= 1
by a given distance (like shorten <=2pt
) is computationally expensive: you would have to find t'
such that the arc length of C(t)
from 0
to t'
is equal to 2pt
, which involves numerical integration and solving non-linear equations numerically.
A different approach to shortening curved arrows would be to restrict the Bezier curve's parameter range (e.g. construct a curve C'(t), 0 <= t <= 1
equal to C(t), 0.1 <= t <= 0.85
), which is rather straightforward and computationally efficient (a simple application of de Casteljau's algorithm). I think we would need new parameters for that (like start time=.1, end time=.85
) and cannot work with shorten <
, since the latter is a length but we need a dimensionless parameter. Personally I'm not sure it is worth the effort, but if you deem it important I can definitely take a more thorough look.
Have you checked how n > 2 interacts with other arrow styles, such as hook, harpoon, and tail?
Right now the head and tail are hard-coded (my code is not even using pgf's Implies
, I hard-coded an arrow head that reproduces pgf's Implies
precisely). The code as-is glitches if you specify different heads or tails (though I would argue that the original Rightarrow
glitches just as badly or worse, as discussed in the issue you linked).
My solution was to draw several Bézier curves, with identical control points, of different thicknesses
The reason I started this project in the first place was to solve issues that stem from tikz/pgf doing exactly that; see the beginning of my original post. What I missed in tikz-cd was a straight arrow that does not produce the aforementioned glitches. Based on your feedback, I attempted to get the code to work with curved arrows as well. Going back to superimposing lines of different thickness kind of defeats this side project's purpose in my eyes. I see different ways of moving forward:
Rightarrow
and implement extra features like n-fold arrows, better shorten
options, etc. However, this would still be affected by the glitches.By the way, I can't believe I had not heard about quiver before! Would have saved me quite a bit of time.
Personally, I would be happier with the most aesthetic output, even if it doesn't exactly match Rightarrow. Others may have different opinions on this, though.
@astoff, what is your take on this?
tikz/scale=...
. I'll try to fix it.Please tell me if you have further ideas what options to test and how to break this code. I'm sure I've missed a bunch of options that could cause problems.
After a couple of busy months I finally found some time to look at this project again. I managed to fix all the issues discussed above. The code can be downloaded here.
The pink background is a regular Rightarrow
, so the new arrows perfectly cover the regular ones.
pgfbezieroffset.tex
, I expect it could be integrated into tikz/pgf proper without much issue.Offsetting tests.tex
.postaction
where I place the nodes on an invisible copy of the unshifted path.intersections
library is used. In principle one could precompute even more orders, but I don't expect many people to use arrows of order > 5.\pgfwarning
in such situations, which is something I could implement in the future.The pictures look nice, and I can have a look at the code (for whatever it's worth). But, like I said above, the right place for this is either PGF itself or else a dedicated package. This package is narrowly focused on comitative diagrams and your code has a broader range of uses.
Thank you for your input. I fully agree with respect to the code that offsets a given Bezier curve, which would be better off in pgf
. I will contact the maintainers and see if there is interest.
As for the nRightarrow
style, I still think that as of now it would make sense as a part of tikz-cd
for the following reasons:
tikz-cd
would cover at least 75 % of all use cases.tikz-cd
integration. While it could be generalised with some effort to a few other cases, both the generalisation and the reimplementation in tikz-cd
would be quite a lot of work, and the generalisation would have few additional uses. Even if I decide to publish this as a separate package, at the moment it would not be useful beyond tikz-cd
.tikz-cd
.tikz
style that that draws arbitrary paths in an n-fold way. However, such a solution would require a serious time investment (which I might not be able to make in the near future), I am not sure if it is possible at all, and even if it is, I am not sure if it will be stable enough for the tikz
maintainers to be integrated. In the meantime, an implementation in tikz-cd
would (as argued above) already cover most use cases.My idea would be to integrate this code as an experimental feature in tikz-cd
once it has been polished a bit. If you want, we can also wait whether pgf
decides to integrate the Bezier offsetting code before we integrate the feature.
I have managed to get the code working with quite general TikZ
paths, including those present in tikz-cd
. The code is now public at https://github.com/jonschz/tikz-nfold. Any testing would be appreciated, submission to CTAN will be done soon. Thank you again for the feedback!
@jonschz: awesome! I shall try to do some testing of the library with my use cases soon :)
This look really cool! I'll make sure to refer to it in the tikz-cd manual.
@jonschz By the way, submitting this directly to PGF instead of a separate package would have its pros and cons. I don't want to argue either way, but did you consider the option?
Thank you for the kind words!
submitting this directly to PGF instead of a separate package would have its pros and cons.
Given that they still have not responded to the code and suggestions I made in December, my priority is getting the code published while I have the time. I am very much open to the idea of this code getting integrated into pgf
, and I will likely submit it to them again at some point. For now, I think a separate package is the fastest way of getting this code out to interested users.
@jonschz: I've experimented with the library on some of the diagrams exported by https://github.com/varkor/quiver, and overall it seems to work really nicely. I've filed a few issues, as you've already noticed, but most of them are relatively minor. (I think the only one preventing me from using it at the moment is https://github.com/jonschz/tikz-nfold/issues/5.)
Once the library is contained in TeXLive and I can reasonably assume most users will have access to it, I plan to switch to nfold
for https://github.com/varkor/quiver, which will close a longstanding issue :) Thank you very much for all your work on this library!
Eventually I think it would be useful for tikz-cd to make use of nfold
, as this would make it a little more convenient for commutative diagrams (e.g. no need to specify both the Rightarrow
and nfold=n
parameters).
The problem
I have had several problems with the Rightarrow style, which have their root in the way
/tikz/double
works.\ar[Rightarrow]
:/tikz/double
draws a thick black line with a slightly less thick white line to give the impression of two thin black lines. On certain zoom levels, the slight vertical differences in the lower boundary are then rounded to the same value.My style
I have written a style
nRightarrow
which addresses these issues by drawing the arrow body using two thin lines. While it works well enough for my needs, it is not in a publishable state right now. I have the code and further details on Stackexchange. There are also links to other posts discussing the two problems above.The main question would be: Is there interest in adding such a style to tikz-cd in addition to the existing Rightarrow? If so, I would put in some effort to get the code into a publishable form.
Proof of concept code
Click to expand
````latex \documentclass{minimal} \usepackage{tikz} \usetikzlibrary{calc,cd} \newlength{\eqoffset} \makeatletter % relative coordinates: (0,0) is the arrow's tail, x points towards the head, % y points perpendicular, unit distance is \eqoffset \newcommand{\relptstart}[2]{($($(k0)!#1*\eqoffset+\pgf@shorten@start@additional!0:(k1)$)!#2*\eqoffset!90:(k1)$)} % (0,0) is the arrow's tip, rest is the same \newcommand{\relptend}[2]{($($(k1)!#1*\eqoffset-\pgf@shorten@end@additional -2*\eqoffset-.5*\pgflinewidth!180:(k0)$)!#2*\eqoffset!-90:(k0)$)} \tikzcdset{ nRightarrow/.style={line join=round, no head, /tikz/commutative diagrams/@shiftabletopath, execute at begin to = { % Do not use tikzcd@noda or tikzcd@x here, it causes interference. % Use new names instead \path (\tikztostart) -- (\tikztotarget) coordinate[pos=0] (k0) coordinate[pos=1] (k1); \pgfpointnormalised{\pgfpointdiff{\pgfpointanchor{k1}{center}}{\pgfpointanchor{k0}{center}}} \pgfgetlastxy{\kdx}{\kdy} \tikzset{ to path={ % arrow body % the .06 is from \pgftransformxshift{.06\pgfutil@tempdima} \relptstart{0}{1} -- \relptend{-.06}{1} { % correct vertical position, more central horizontal position %[xshift=-\kdy*\eqoffset, yshift=\kdx*\eqoffset] % matches original Rightarrow more closely [xshift=-\kdy*\eqoffset-\kdx*(\eqoffset+.25*\pgflinewidth), yshift=\kdx*\eqoffset-\kdy*(\eqoffset+.25*\pgflinewidth)] \tikztonodes} \relptstart{0}{-1} -- \relptend{-.06}{-1} % arrow tip % fake the round cap by using round joins and drawing the path twice with a turnaround at the caps \relptend{2}{0} % tip to top end .. controls \relptend{1}{0.05} and \relptend{-0.75}{1.25} .. \relptend{-1.4}{2.65} % top end back to tip .. controls \relptend{-0.75}{1.25} and \relptend{1}{0.05} .. \relptend{2}{0} % tip to bottom end .. controls \relptend{1}{-0.05} and \relptend{-0.75}{-1.25} .. \relptend{-1.4}{-2.65} % bottom end back to tip .. controls \relptend{-0.75}{-1.25} and \relptend{1}{-0.05} .. \relptend{2}{0} % Add a degenerate path segment at the end so shorten < and shorten > are not applied again (k1) }} }} } \makeatother \begin{document} \setlength{\eqoffset}{.225ex} \begin{tikzcd} a_1 \ar[dr, red, Rightarrow, shift={(0pt, 4pt)}, "l", "m"'] \ar[dr, nRightarrow, shift={(0pt, 4pt)}, green, opacity=.5, "l", "m"'] & a_2 \ar[dr, red, Rightarrow, shift left=7pt, shorten <=2pt, shorten >=3pt, "l"] \ar[dr, blue, shift left=7pt, nRightarrow, shorten <=2pt, shorten >=3pt, opacity=.5, "l"] \ar[dr, green, nRightarrow, shift left=7pt, shorten <=2pt, shorten >=3pt, opacity=.5, "l"] & a_3 & a_4 \ar[d, red, Rightarrow, shorten <=2pt, shorten >=3pt, "l", "m"'] \ar[d, green, nRightarrow, shorten <=2pt, shorten >=3pt, opacity=.5, "l", "m"'] \\ b_1 & b_2 & b_3 & b_4 \end{tikzcd} \end{document} ````The green and blue
nRightarrow
s are rendered on top ofRightarrow
s for comparison.Limitations and known issues
shift left
only works if specified beforenRightarrow
, not after. I think this has to do with the order in which severalexecute at begin to
statements are executed. Advice on fixing this would be greatly appreciated.Rightarrow
, as they are centred with respect to the arrow body, not the full arrow. There are two variations in the code above, the latter being closer toRightarrow
(and matching exactly if noshorten
ornear start
is enabled). I think the new label position is just as good or better, as the originalRightarrow
would sometimes place the labels too close to the arrow head for my taste.to path
specified by the user. I don't think that is a problem, as for such cases, you may still use the normalRightarrow
.As for code refactoring, I have thought of
\eqoffset
to a tikz keytikzcd@...
What else is there to be done?