我很好奇,如何选择路径的起点?当我的用户从 到 绘制路径时,我试图生成此类A
图片B
:
但是,如果我(\tikztostart.west)
指定路径应该从西边开始,那么如果用户不能再\path (A.center) to[myC] (B.center)
强制节点从中心开始(我猜它会评估为A.center.west
不存在)。
知道如何让它工作吗?另外,我很好奇:在某些库中,例如使用时in=40
,它们设法以任意角度从节点的边界开始...如何以编程方式获取此坐标?[编辑看起来\pgfpointshapeborder{}{}
这样做很有用?TODO:请阅读手册“基础层”部分中的更多内容]
奖金:我为什么不能这样做\ifnum\y2>0
?
平均能量损失
\documentclass[]{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}
Problem: need to specify \verb|.west|:
\begin{tikzcd}[
myC/.style={
to path={ let \p1=(\tikztostart|-\tikztotarget), \p2=($(\p1)-(\tikztostart)$), \n1={veclen(\x2,\y2)} in arc[start angle=180+90,end angle=90,radius=\n1/2] -- (\tikztotarget) \tikztonodes}
},
]
|[]| & |[alias=B,draw,circle]| B\\
|[alias=A,circle,draw]|A & |[alias=C,draw,circle]| C
\arrow[-,from=A.west,to=B.west,myC]
\arrow[-,from=C.west,to=B.west,myC]
\end{tikzcd}
Problem: can't force start at center.
\begin{tikzcd}[
myC/.style={
to path={ (\tikztostart.west) let \p1=(\tikztostart.west|-\tikztotarget.west), \p2=($(\p1)-(\tikztostart.west)$), \n1={veclen(\x2,\y2)} in arc[start angle=180+90,end angle=90,radius=\n1/2] -- (\tikztotarget.west) \tikztonodes}
},
]
|[]| & & |[alias=B,draw,circle]| B\\
|[alias=A,circle,draw]|A & |[alias=C,draw,circle]| C
\arrow[-,from=A,to=B,myC]
% this fails:
%\arrow[-,from=C.center,to=B,myC]
\end{tikzcd}
Bonus: how to make \verb|\ifnum\y2>0| work?
% \begin{tikzcd}[
% myC/.style={
% to path={ let \p1=(\tikztostart|-\tikztotarget), \p2=($(\p1)-(\tikztostart)$), \n1={veclen(\x2,\y2)} in \ifnum\y2>0 \abc>0 arc[start angle=180+90,end angle=90,radius=\n1/2] \else arc[start angle=90,end angle=180+90,radius=\n1/2] \fi -- (\tikztotarget) \tikztonodes}
% },
% ]
% |[]| & |[alias=B,draw,circle]| B\\
% |[alias=A,circle,draw]|A & |[alias=C,draw,circle]| C
% \arrow[-,from=A.west,to=B.west,myC]
% \arrow[-,from=B.west,to=C.west,myC]
% \end{tikzcd}
\end{document}
编辑
我设法使用以下方法完成了奖励部分\pgfextra{\pgfmathparse{\y2>0}}\ifnum\pgfmathresult=1 ... \else ... \fi
:
\begin{tikzcd}[
myC/.style={
to path={ let \p1=(\tikztostart|-\tikztotarget), \p2=($(\p1)-(\tikztostart)$), \n1={veclen(\x2,\y2)} in \pgfextra{\pgfmathparse{\y2>0}}\ifnum\pgfmathresult=1 arc[start angle=180+90,end angle=90,radius=\n1/2] \else arc[start angle=90,end angle=180+90,radius=\n1/2] \fi -- (\tikztotarget) \tikztonodes}
},
]
|[]| & |[alias=B,draw,circle]| B\\
|[alias=A,circle,draw]|A & |[alias=C,draw,circle]| C
\arrow[-,from=A.west,to=B.west,myC]
\arrow[-,from=B.west,to=C.west,myC]
\end{tikzcd}
但最初的问题仍未得到解决。
编辑2
检查了 tikz 的源代码后,我发现允许\iftikz@shapeborder
做这样的事情......但不幸的是,我认为它不起作用,\tikztotarget
因为它不接受任何参数......知道如何检查输入和输出的信息吗?
答案1
非常简单,无论是图还是代码。
\documentclass[tikz,border=5mm]{standalone}
\begin{document}
\begin{tikzpicture}
\def\a{1.5}
\path[nodes={circle,draw,minimum size=6mm}]
(0,0) node (A) {$A$}
(\a,\a) node (B) {$B$}
(\a,0) node (C) {$C$}
;
\draw[->] (B.west) --+(180:\a) arc(90:270:\a/2);
\draw[->] (B.west) arc(90:270:\a/2);
\end{tikzpicture}
\end{document}
答案2
在检查了 tikz 的源代码后,似乎他们测试一个节点是否是一个形状\pgfutil@ifundefined{pgf@sh@ns@#1}
(但这是有记录的无处,所以不知道它是否可以安全使用...请告诉我!)
以下是测试方法(样式尚不完善...)。另外,请注意,\pgfpointshapeborder
可用于确定与给定线交叉的节点边界上的点。
\documentclass[]{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}
\makeatletter
\def\ifPgfpointOrCoordinate#1#2#3{%
\pgfutil@ifundefined{pgf@sh@ns@#1}{%
#2%
}{%
#3%
}%
}
\makeatother
\begin{tikzcd}[
myC/.style={
to path={
\pgfextra{ %% <- we will use def... so need to "exit" a few seconds pgf
% Test if tikztostart is a point or a coordinate, and define StartPoint accordingly.
\ifPgfpointOrCoordinate{\tikztostart}{%
\def\StartPoint{\tikztostart}%
}{%
\def\StartPoint{\tikztostart.west}%
}}%
% (\StartPoint) -- (\tikztotarget) \tikztonodes}%%
(\StartPoint) let \p1=(\StartPoint|-\tikztotarget), \p2=($(\p1)-(\StartPoint)$), \n1={veclen(\x2,\y2)} in arc[start angle=180+90,end angle=90,radius=\n1/2] -- (\tikztotarget) \tikztonodes}
},%
]
|[]| & & |[alias=B,draw,circle]| B \\
|[alias=A,circle,draw]|A & & |[alias=C,draw,circle]| C \\
|[]| & |[alias=D,draw,circle]| D & \\
\arrow[-,from=A,to=B,myC]
\arrow[-,from=D.center,to=C.south,myC]
\end{tikzcd}
\end{document}
编辑 这是样式的完整版本(保留箭头提示,并允许任意放置节点),如果您知道更好的方法,请告诉我。
\documentclass[]{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}
\makeatletter
\def\ifPgfpointOrNode#1#2#3{%
\pgfutil@ifundefined{pgf@sh@ns@#1}{%
#2%
}{%
#3%
}%
}
\makeatother
\begin{tikzcd}[
myC/.style={
to path={
\pgfextra{ %% <- we will use def... so need to "exit" a few seconds pgf
% Test if tikztostart is a point or a node, and define StartPoint accordingly.
\ifPgfpointOrNode{\tikztostart}{%
\def\StartPoint{\tikztostart}%
}{%
\def\StartPoint{\tikztostart.west}%
}%
% Test if tikztostart is a point or a node, and define StartPoint accordingly.
\ifPgfpointOrNode{\tikztotarget}{%
\def\TargetPoint{\tikztotarget}%
}{%
\def\TargetPoint{\tikztotarget.west}%
}%
}%
(\StartPoint) % <- the path starts at StartPoint
%%% Get x coordinate of left-most point
let \p1=(\StartPoint),
\p2=(\TargetPoint),
\n1={min(\x1,\x2)}, % coordinate of the most left part
\n3={abs(\y1-\y2)/2} % Radius of circle
in % Warning: no comma after last line before in
%%%% We go on the left if needed (we check that we do move, otherwise we break the arrows tip if
%%%% we stay on place
%%%% First go to the left if needed
\pgfextra{%
%% We check if we are moving or not (required to preserve arrow tip direction)
\pgfmathapproxequalto{\x1}{\n1}%
}%
\ifpgfmathcomparison\else -- (\n1,\y1)\fi
%%%% Version 1:
\pgfextra{
\pgfmathparse{
ifthenelse(\y1<\y2,%
"arc[start angle=180+90,end angle=90,radius=\n3]",%
"arc[start angle=90,end angle=180+90,radius=\n3]"%
)%
}
}
\pgfmathresult
%%%% Version 2
% %% We start the arc
% \pgfextra{% Do math outside of the path construction
% \pgfmathparse{\y1<\y2}% \ifnum can only evaluate integers. Use pgfmathparse instead.
% }%
% \ifnum\pgfmathresult=1 %
% arc[start angle=180+90,end angle=90,radius=\n3]%
% \else%
% arc[start angle=90,end angle=180+90,radius=\n3]%
% \fi
%%%% Then go to the right if needed
\pgfextra{%
%% We check if we are moving or not (required to preserve arrow tip direction)
\pgfmathapproxequalto{\x2}{\n1}%
}%
\ifpgfmathcomparison\else -- (\TargetPoint)\fi
\tikztonodes}
},%
]
|[]| & & |[alias=B,draw,circle]| B \\
|[alias=A,circle,draw]|A & & & |[alias=C,draw,circle]| C \\
|[]| & |[alias=D,draw,circle]| D & \\
\arrow[<-latex,from=A,to=B,myC]
\arrow[<-,from=C.south,to=D.center,myC]
\arrow[<->,from=C,to=B.south,myC]
\end{tikzcd}
\end{document}