起初我以為這是我的pdf閱讀器的問題。例如,使用程式碼
\documentclass{article}
\usepackage{tikz-cd}
\begin{document}
\begin{tikzcd}
A & B
\arrow[Rightarrow, from=1-1, to=1-2]
\end{tikzcd}
\end{document}
結果Rightarrow
似乎包含兩條額外的小灰線:
該問題已在這個問題幾個月前,作者提供了一個複雜的新樣式nRightarrow
,似乎可以解決這個問題(Rightarrow
上、nRightarrow
下):
然而,對這種新風格的需求nRightarrow
似乎主要來自其他更複雜的問題。那麼我想知道,針對這兩條多餘的灰線的問題,目前是否有更簡單的解決方案?
nRightarrow
下面是一個 MWE,我在其中複製了連結問題的程式碼。
\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\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)
}}
}}
}
\setlength{\eqoffset}{.225ex}
\makeatother
\begin{document}
\begin{tikzcd}[column sep=large]
A & B
\arrow[Rightarrow, from=1-1, to=1-2]
\end{tikzcd}
\begin{tikzcd}[column sep=large]
A & B
\arrow[nRightarrow, from=1-1, to=1-2]
\end{tikzcd}
\end{document}
答案1
連結的問題源自於一個冗長的討論與 TikZ-CD 的作者討論如何重新實現平行線。代碼好像差不多達到 PGF 級別。
這裡沒有重新實現 PGF 繪製線條的方式,而是關於如何稍微改變 PGF 繪製線條的double
方式的概念證明double
- 要么通過延長內線
- 或透過縮短外線。
這遠非完美,但最適合
- 直線
- 由一段組成(一開始只有一個移動),
- 不是虛線並使用普通
rect
線帽。
此外,箭頭最好不要接觸繪製的節點。
該spath3
庫可以幫助使(不)縮短不會扭曲曲線,並且還可以幫助將其應用於具有多個段的路徑。
程式碼
\documentclass[tikz]{standalone}
\usepackage{tikz-cd}
\makeatletter
\def\pgf@double@cheat#1{%
\let\pgf@tips@mode\pgf@tips@mode@false
\pgfsetarrowsstart{}\pgfsetarrowsend{}%
\pgfsetshortenstart{#1}\pgfsetshortenend{#1}%
\pgf@prepare@end@of@path\pgf@prepare@start@of@path}
\pgfset{
shorten outer/.code=%
\pgfmathsetlength\pgfutil@tempdima{#1}%
\pgfkeyssetevalue{/pgf/shorten outer}{\the\pgfutil@tempdima},
shorten outer=+0pt,
unshorten inner/.code=%
\pgfmathsetlength\pgfutil@tempdima{#1}%
\pgfkeyssetevalue{/pgf/unshorten inner}{\the\pgfutil@tempdima},
unshorten inner=+0pt}
\usepackage{etoolbox}
\patchcmd{\pgf@stroke@inner@line}{\pgfsyssoftpath@invokecurrentpath}{%
\ifdim\pgfkeysvalueof{/pgf/unshorten inner}>0pt
\pgf@double@cheat{-\pgfkeysvalueof{/pgf/unshorten inner}}%
\fi\pgfsyssoftpath@invokecurrentpath}{}{\PatchFailed}
\patchcmd{\pgfusepath}{\fi\pgfsyssoftpath@invokecurrentpath\pgf@up@action}{%
\fi \ifdim\pgfinnerlinewidth>0pt
\ifdim\pgfkeysvalueof{/pgf/shorten outer}>0pt
\pgfgetpath\pgf@temppath
\pgf@double@cheat{\pgfkeysvalueof{/pgf/shorten outer}}\fi\fi
\pgfsyssoftpath@invokecurrentpath%
\ifdim\pgfinnerlinewidth>0pt
\ifdim\pgfkeysvalueof{/pgf/shorten outer}>0pt
\pgfsetpath\pgf@temppath\fi\fi\pgf@up@action}{}{\PatchFailed}
\makeatother
\newcommand*\everycell[1]{%
\draw[cd=Rightarrow,#1]node(A){$A$}node(B)at(2,0){$B$}(A)to(B);}
\begin{document}
\tikz[
cd/.code=\tikzcdset{#1}, anchor=base,
cd dbl/.style={cd={background color=green}},
cells={nodes={behind path, help lines, draw, shape=asymmetrical rectangle}},
column 1/.append style={anchor=base west, nodes=path only},
rows/.style args={#1 => #2}{row #1/.append style={#2}},
rows/.list={2 => unshorten inner = .05pt,
3 => shorten outer = .05pt,
4 => {cd dbl=green, unshorten inner = 2pt},
5 => {cd dbl=green, shorten outer = 2pt}}
]\matrix[column sep=\tabcolsep]{
\node{normal:}; & \everycell{} & \everycell{bend left} \\
\node{inner:}; & \everycell{} & \everycell{bend left} \\
\node{outer:}; & \everycell{} & \everycell{bend left} \\
\node{extreme inner:}; & \everycell{} & \everycell{bend left} \\
\node{extreme outer:}; & \everycell{} & \everycell{bend left} \\};
\begin{tikzcd}[unshorten inner=+0.01pt]
A & B
\arrow[Rightarrow, from=1-1, to=1-2]
\end{tikzcd}
\end{document}
輸出
在這種情況下,最好自己編譯並使用不同的縮放等級和不同的 PDF 檢視器/渲染器來查看輸出。不過,您可以點擊前兩張圖片來查看它的放大版本。
答案2
我寫tikz-nfold專門解決這個問題:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{cd}
\usetikzlibrary{nfold}
\begin{document}
\begin{tikzcd}
A & B
\arrow[Rightarrow, from=1-1, to=1-2, nfold]
\end{tikzcd}
\end{document}
順便說一句,作者tikz-cd
最近通知我這\usepackage{tikz-cd}
是一個遺留功能,儘管使用它並沒有什麼問題。