Tikz:“\tikztostart”,如何区分节点和坐标,并获取节点边界 X 角的坐标

Tikz:“\tikztostart”,如何区分节点和坐标,并获取节点边界 X 角的坐标

我很好奇,如何选择路径的起点?当我的用户从 到 绘制路径时,我试图生成此类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}

相关内容