varkor / quiver

A modern commutative diagram editor for the web.
https://q.uiver.app
MIT License
2.37k stars 78 forks source link

Bug with `curve` when distance is too small #179

Open drewheard opened 9 months ago

drewheard commented 9 months ago

The following looks rather horrible:

\documentclass{article} \usepackage{quiver} \usepackage{tikz-cd} \usepackage{amsmath} \usetikzlibrary{nfold} \DeclareMathOperator{\Spaces}{Spaces}

\usepackage[english]{babel}

% Set page size and margins % Replace letterpaper' witha4paper' for UK/EU standard size \usepackage[letterpaper,top=2cm,bottom=2cm,left=3cm,right=3cm,marginparwidth=1.75cm]{geometry}

% Useful packages \usepackage{amsmath} \usepackage{graphicx} \usepackage[colorlinks=true, allcolors=blue]{hyperref}

\title{Your Paper} \author{You}

\begin{document}

% https://q.uiver.app/#q=WzAsMixbMCwwLCJhIl0sWzEsMCwiYiJdLFsxLDAsImciLDAseyJjdXJ2ZSI6LTF9XSxbMCwxLCJmIiwwLHsiY3VydmUiOi0xfV0sWzMsMiwiIiwwLHsibGV2ZWwiOjEsInN0eWxlIjp7Im5hbWUiOiJhZGp1bmN0aW9uIn19XV0= [\begin{tikzcd}[ampersand replacement=\&] {\Spaces} \& {\Spaces{\le n}} \arrow[""{name=0, anchor=center, inner sep=0}, "\Omega^n+", curve={height=-6pt}, from=1-2, to=1-1] \arrow[""{name=1, anchor=center, inner sep=0}, "\Sigma^n_+", curve={height=-6pt}, from=1-1, to=1-2] \arrow["\dashv"{anchor=center, rotate=-90}, draw=none, from=1, to=0] \end{tikzcd}] \end{document}`

Presumably there is a bug in quiver.sty?

varkor commented 9 months ago

Could you put your code in a code block, so I can copy it properly, and could you include a screenshot of what the diagram looks like for you?

drewheard commented 9 months ago

Sure.

\documentclass{article}
\usepackage{quiver}
\usepackage{tikz-cd}
\usepackage{amsmath}
\usetikzlibrary{nfold}
\DeclareMathOperator{\Spaces}{Spaces}

\usepackage[english]{babel}

% Set page size and margins
% Replace `letterpaper' with `a4paper' for UK/EU standard size
\usepackage[letterpaper,top=2cm,bottom=2cm,left=3cm,right=3cm,marginparwidth=1.75cm]{geometry}

% Useful packages
\usepackage{amsmath}
\usepackage{graphicx}
\usepackage[colorlinks=true, allcolors=blue]{hyperref}

\title{Your Paper}
\author{You}

\begin{document}

% https://q.uiver.app/#q=WzAsMixbMCwwLCJhIl0sWzEsMCwiYiJdLFsxLDAsImciLDAseyJjdXJ2ZSI6LTF9XSxbMCwxLCJmIiwwLHsiY3VydmUiOi0xfV0sWzMsMiwiIiwwLHsibGV2ZWwiOjEsInN0eWxlIjp7Im5hbWUiOiJhZGp1bmN0aW9uIn19XV0=
\[\begin{tikzcd}[ampersand replacement=\&]
    {\Spaces} \& {\Spaces_{\le n}}
    \arrow[""{name=0, anchor=center, inner sep=0}, "\Omega^n_+", curve={height=-6pt}, from=1-2, to=1-1]
    \arrow[""{name=1, anchor=center, inner sep=0}, "\Sigma^n_+", curve={height=-6pt}, from=1-1, to=1-2]
    \arrow["\dashv"{anchor=center, rotate=-90}, draw=none, from=1, to=0]
\end{tikzcd}\]
\end{document}

The output is as follows: Untitled

It can be fixed by making the spacer a little larger.

varkor commented 9 months ago

@drewheard: thanks. Here's a minimised version of the issue:

\documentclass{article}
\usepackage{quiver}

\begin{document}

\[\begin{tikzcd}
    XXXXXXXXX & XXXXXXXXX
    \arrow[curve, from=1-1, to=1-2]
\end{tikzcd}\]

\end{document}

Produces:

image

This does look like an issue with the curve command in the quiver.sty package, thanks. I'll look into it.

For now, it can be addressed by increasing the spacing a little, as you pointed out.

user202729 commented 2 months ago

You can easily see where the bug is by drawing out the control points. (I mean assume you come up with how to draw the control points, which is not very trivial given you're limited to use a path specification. Use a colored node suffices.)

\tikzset{curve/.style={settings={#1},to path={
            node (__quiver_control1) at ($(\tikztostart)!\pv{pos}!(\tikztotarget)!\pv{height}!270:(\tikztotarget)$) [red, fill, circle, inner sep=1pt] {}
            node (__quiver_control2) at ($(\tikztostart)!1-\pv{pos}!(\tikztotarget)!\pv{height}!270:(\tikztotarget)$) [blue, fill, circle, inner sep=1pt] {}
            (\tikztostart)
    .. controls (__quiver_control1.center) and (__quiver_control2.center)
.. (\tikztotarget)\tikztonodes}}}

Looking at the result, the problem is that the partway modifier computes the distance between the center of the nodes, instead of between the arrow endpoints as it should.

The bug comes directly from the answer https://tex.stackexchange.com/questions/556893/curve-of-fixed-height-between-two-nodes-in-tikz-cd/556902#556902 .

The only way I can think of to compute the actual distance between two nodes is the following: (draw a line between two nodes, draw nodes, then retrieve coordinate of nodes)

%! TEX program = pdflatex
\documentclass{article}
\usepackage{quiver}

\begin{document}

% A TikZ style for curved arrows of a fixed height, due to AndréC.
\tikzset{curve/.style={settings={#1},to path={
      \pgfextra
        \edef\quiverTmpStart{\tikztostart}
        \edef\quiverTmpTarget{\tikztotarget}
        \begin{pgfinterruptpath}
            \draw[gray] (\quiverTmpStart) -- (\quiverTmpTarget)
            node (__quiver_p1) [at start, shape=coordinate] {}
            node (__quiver_p2) [at end, shape=coordinate] {}
              ;
        \end{pgfinterruptpath}
      \endpgfextra
      (\tikztostart)
      .. controls ($(__quiver_p1)!\pv{pos}!(__quiver_p2)!\pv{height}!270:(__quiver_p2)$)
      and ($(__quiver_p1)!1-\pv{pos}!(__quiver_p2)!\pv{height}!270:(__quiver_p2)$)
    .. (\tikztotarget)\tikztonodes}
},
    settings/.code={\tikzset{quiver/.cd,#1}
        \def\pv##1{\pgfkeysvalueof{/tikz/quiver/##1}}},
    quiver/.cd,pos/.initial=0.35,height/.initial=0}

\[\begin{tikzcd}
    XXXX & XXXXXXXXX
    \arrow[curve={height=3pt}, from=1-1, to=1-2]
\end{tikzcd}\]

\end{document}

While it isn't necessary to copy the \tikztostart,\tikztotarget it seems safer to safeguard against future changes of the library.

Technically https://tex.stackexchange.com/questions/550153/how-to-get-the-length-of-an-arbitrary-path-in-tikz allows getting the length too. But that's not sufficient, we want to know what's the gap of each node.

Of course, in real code change \draw[gray] to \path.

Side note: if you zoom in enough you will see the arrow is not exactly symmetric. I think that's the right behavior anyway.

Or do you prefer this instead?

%! TEX program = pdflatex
\documentclass{article}
\usepackage{quiver}

\begin{document}

% A TikZ style for curved arrows of a fixed height, due to AndréC.
\tikzset{curve/.style={settings={#1},to path={
      \pgfextra
        \edef\quiverTmpStart{\tikztostart}
        \edef\quiverTmpTarget{\tikztotarget}
        \begin{pgfinterruptpath}
            \draw[gray] (\quiverTmpStart) -- (\quiverTmpTarget)
            node (__quiver_p1) [at start, shape=coordinate] {}
            node (__quiver_p2) [at end, shape=coordinate] {}
              ;
        \end{pgfinterruptpath}
      \endpgfextra
      (__quiver_p1)
      .. controls ($(__quiver_p1)!\pv{pos}!(__quiver_p2)!\pv{height}!270:(__quiver_p2)$)
      and ($(__quiver_p1)!1-\pv{pos}!(__quiver_p2)!\pv{height}!270:(__quiver_p2)$)
    .. (__quiver_p2)\tikztonodes}
},
    settings/.code={\tikzset{quiver/.cd,#1}
        \def\pv##1{\pgfkeysvalueof{/tikz/quiver/##1}}},
    quiver/.cd,pos/.initial=0.35,height/.initial=0}

\[\begin{tikzcd}
    XXXX & XXXXXXXXX
    \arrow[curve={height=3pt}, from=1-1, to=1-2]
\end{tikzcd}\]

\end{document}

Side note: naming the style curve seems dangerous, as the user may inadvertently also define a style named curve and will be puzzled why quiver code break. Better name it quiver-curve or something (although that would breaks all backwards compatibility now?)