考虑一下这个MWE:
\documentclass[tikz,margin=1cm,12pt]{standalone}
\usetikzlibrary{calc,decorations,angles}
% Cheating Dash from https://tex.stackexchange.com/questions/133271/can-tikz-dashed-lines-emulate-pstricks-dashed-lines
\tikzset{
cheating dash/.code args={on #1 off #2}{
% Use csname so catcode of @ doesn't have do be changed.
\csname tikz@addoption\endcsname{%
\pgfgetpath\currentpath%
\pgfprocessround{\currentpath}{\currentpath}%
\csname pgf@decorate@parsesoftpath\endcsname{\currentpath}{\currentpath}%
\pgfmathparse{\csname pgf@decorate@totalpathlength\endcsname-#1}\let\rest=\pgfmathresult%
\pgfmathparse{#1+#2}\let\onoff=\pgfmathresult%
\pgfmathparse{max(floor(\rest/\onoff), 1)}\let\nfullonoff=\pgfmathresult%
\pgfmathparse{max((\rest-\onoff*\nfullonoff)/\nfullonoff+#2, #2)}\let\offexpand=\pgfmathresult%
\pgfsetdash{{#1}{\offexpand}}{0pt}}%
}
}
\begin{document}
\begin{tikzpicture}[line cap=rect]
\coordinate (A) at (1,1);
\coordinate (B) at ($(A)+(60:1)$);
\coordinate (C) at ($(A)+(0,1)$);
\coordinate (D) at ($(A)+(90-15:0.7)$);
\draw pic[draw=orange,angle radius=0.6cm] {angle=B--A--C};
\draw [gray,cheating dash=on 2pt off 2pt] (A) -- (B);
\draw [gray,cheating dash=on 2pt off 2pt] (A) -- (C);
\node[inner sep=2pt] at (0.5,2) (Theta) {$\vartheta$};
\draw[arrows=->] (Theta.east) -- (D);
\end{tikzpicture}
\end{document}
我知道解决这个问题的一种方法是在原始箭头下方绘制另一个白色箭头(线宽较大)。但我正在寻找不涉及此方法的解决方案。
我希望 TikZ 能够“检测”箭头的任何部分何时与虚线相交,并自动隐藏与其相交的虚线段。这样,所有剩余的虚线段都应为全长(因为它们不会被箭头覆盖)。
有没有办法做到这一点?
更新
作为为什么我不一定希望箭头后面有白色光晕/背景的示例,请考虑以下修改:\coordinate (D) at (1.15,1.6);
。箭头错过了破折号,因此不需要移除或覆盖破折号!
答案1
更优雅的代码:我删除了我的第一篇帖子,这已经以一种更优雅的方式完成了杰克的回答。这是我的第一个真正答案的一个稍微优雅的版本,我保留了这个版本,因为这个版本对于弯曲的虚线来说有一点意外起作用的机会,而这个版本则不行。这篇文章的优点是它更方便用户使用(但仍有很大的改进空间),并且不会意外地抹去其他线条。策略是“重新规划”虚线并将其存储为迷你路径。(是的,向这些虚线添加箭头等很简单,但添加这些箭头的方法要简单得多。)然后,此代码会找到箭头的交叉点并“抹去”有问题的虚线。
\documentclass[tikz,margin=1cm,12pt]{standalone}
\usetikzlibrary{calc,decorations,angles,decorations.markings,intersections}
\newcounter{minipath}
\setcounter{minipath}{0}
\makeatletter
% Cheating Dash from https://tex.stackexchange.com/questions/133271/can-tikz-dashed-lines-emulate-pstricks-dashed-lines
\tikzset{
cheating dash/.code args={on #1 off #2}{
% Use csname so catcode of @ doesn't have do be changed.
\csname tikz@addoption\endcsname{%
\pgfgetpath\currentpath%
\pgfprocessround{\currentpath}{\currentpath}%
\csname pgf@decorate@parsesoftpath\endcsname{\currentpath}{\currentpath}%
\pgfmathsetmacro{\rest}{\csname pgf@decorate@totalpathlength\endcsname-#1}%
\pgfmathsetmacro{\mylen}{\csname pgf@decorate@totalpathlength\endcsname}
\pgfmathsetmacro{\onoff}{#1+#2}%
\pgfmathsetmacro{\nfullonoff}{max(floor(\rest/\onoff), 1)}%
\pgfmathsetmacro{\offexpand}{max((\rest-\onoff*\nfullonoff)/\nfullonoff+#2,#2)}%
\pgfextra{\xdef\myoff{\offexpand}%
\xdef\myon{#1}%
\pgfmathtruncatemacro{\myN}{\nfullonoff+0.1}\xdef\myN{\myN}%
\xdef\mylen{\mylen}}% \typeout{\myon,\myoff,\mylen,\myN}
\pgfsetdash{{#1}{\offexpand}}{0pt}}%
}
}
\tikzset{% from https://tex.stackexchange.com/a/26386/121799
use path for main/.code={%
\tikz@addmode{%
\expandafter\pgfsyssoftpath@setcurrentpath\csname tikz@intersect@path@name@#1\endcsname
}%
},
use path for actions/.code={%
\expandafter\def\expandafter\tikz@preactions\expandafter{\tikz@preactions\expandafter\let\expandafter\tikz@actions@path\csname tikz@intersect@path@name@#1\endcsname}%
},
use path/.style={%
use path for main=#1,
use path for actions=#1,
}
}
\makeatother
% Note that this this works ONLY FOR STRAIGHT LINES
% in principle, one COULD generalize it to arbitrary curves using the
% tricks from bending library
\tikzset{store dashes/.style={postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step {\myon+\myoff*1pt}
with % \typeout{\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}}
{\pgfextra{\stepcounter{minipath}}
%\draw[blue,name path=minipath-\theminipath] (0,0) -- (\myon,0);
\path[name path=minipath-\theminipath] (0,0) -- (\myon,0);
}
}}}
\tikzset{wipe out dashes/.code={\foreach \X in {1,...,\theminipath}
{\path[name intersections={of={#1} and {minipath-\X}, name=x,
total=\n}]\pgfextra{\xdef\NumInt{\n}};
\ifnum\NumInt>0
\draw[use path=minipath-\X,white,line width=1.1\pgflinewidth];
\fi
}}}
\begin{document}
\begin{tikzpicture}[line cap=rect]
\coordinate (A) at (1,1);
\coordinate (B) at ($(A)+(60:1)$);
\coordinate (C) at ($(A)+(0,1)$);
\coordinate (D) at ($(A)+(90-15:0.7)$);
\draw pic[draw=orange,angle radius=0.6cm] {angle=B--A--C};
\draw [gray,cheating dash=on 2pt off 2pt,store dashes] (A) -- (B) coordinate[pos=0.9] (H);
\draw [gray,cheating dash=on 2pt off 2pt,store dashes] (A) -- (C);
\node[inner sep=2pt] at (0.5,2) (Theta) {$\vartheta$};
\path[name path global=myline] (Theta.east) -- (D);
\path[wipe out dashes=myline,postaction={use path=myline,arrows=->,draw}];
\end{tikzpicture}
\end{document}
历史:只是为了好玩:检测箭头路径是否真的与其中一个虚线相交。如果是,则删除虚线。它可以简化。此时最丑陋的事情是我需要知道虚线的长度。(原则上,也可以通过用白色重新绘制相应的小路径来避免这种情况,这会更加费力。完成,见上文。)
\documentclass[tikz,margin=1cm,12pt]{standalone}
\usetikzlibrary{calc,decorations,angles,decorations.markings,intersections}
\newcounter{minipath}
\setcounter{minipath}{0}
% Cheating Dash from https://tex.stackexchange.com/questions/133271/can-tikz-dashed-lines-emulate-pstricks-dashed-lines
\tikzset{
cheating dash/.code args={on #1 off #2}{
% Use csname so catcode of @ doesn't have do be changed.
\csname tikz@addoption\endcsname{%
\pgfgetpath\currentpath%
\pgfprocessround{\currentpath}{\currentpath}%
\csname pgf@decorate@parsesoftpath\endcsname{\currentpath}{\currentpath}%
\pgfmathsetmacro{\rest}{\csname pgf@decorate@totalpathlength\endcsname-#1}%
\pgfmathsetmacro{\mylen}{\csname pgf@decorate@totalpathlength\endcsname}
\pgfmathsetmacro{\onoff}{#1+#2}%
\pgfmathsetmacro{\nfullonoff}{max(floor(\rest/\onoff), 1)}%
\pgfmathsetmacro{\offexpand}{max((\rest-\onoff*\nfullonoff)/\nfullonoff+#2,#2)}%
\pgfextra{\xdef\myoff{\offexpand}%
\xdef\myon{#1}%
\pgfmathtruncatemacro{\myN}{\nfullonoff+0.1}\xdef\myN{\myN}%
\xdef\mylen{\mylen}}% \typeout{\myon,\myoff,\mylen,\myN}
\pgfsetdash{{#1}{\offexpand}}{0pt}}%
}
}
\tikzset{store dashes/.style={postaction={decorate},decoration={markings,
mark=between positions 0 and 1 step {\myon+\myoff*1pt}
with % \typeout{\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}}
{\pgfextra{\stepcounter{minipath}}
%\draw[blue,name path=minipath-\theminipath] (0,0) -- (\myon,0);
\path[name path=minipath-\theminipath] (0,0) -- (\myon,0);
}
}}}
\begin{document}
\begin{tikzpicture}[line cap=rect]
\coordinate (A) at (1,1);
\coordinate (B) at ($(A)+(60:1)$);
\coordinate (C) at ($(A)+(0,1)$);
\coordinate (D) at ($(A)+(90-15:0.7)$);
\draw pic[draw=orange,angle radius=0.6cm] {angle=B--A--C};
\draw [gray,cheating dash=on 2pt off 2pt,store dashes] (A) -- (B) coordinate[pos=0.9] (H);
\draw [gray,cheating dash=on 2pt off 2pt,store dashes] (A) -- (C);
\typeout{\theminipath}
\node[inner sep=2pt] at (0.5,2) (Theta) {$\vartheta$};
\path[name path=myline] (Theta.east) -- (D);
\foreach \X in {1,...,\theminipath}
{\fill[white] [name intersections={of={myline} and {minipath-\X}, name=x, total=\n}]
%\pgfextra{\typeout{\theminipath,\X,\n}}
\ifnum\n>0
\foreach \Y in {1,...,\n} { (x-\Y) circle(2pt)} %<- ugly: I need to know the length of the dash pattern here
\fi
;}
\draw[name path=myline,arrows=->] (Theta.east) -- (D);
\end{tikzpicture}
\end{document}
根据事情的进展,我可能会找到足够的动力来完善这段代码。目前,它只是表明在实践中这是可以做到的。