在 tikz-cd 中繪製到節點本身的圓形路徑

在 tikz-cd 中繪製到節點本身的圓形路徑

我想在交換圖中畫出一個指向自身的節點的圓形箭頭。到目前為止我能達成的目標如下:

在此輸入影像描述

有什麼方法可以讓循環看起來很像真正的圓嗎?

下面是 MWE。

\documentclass{article}
\usepackage{tikz-cd}
\begin{document}

\begin{tikzcd}[column sep=large]
    C & D
    \arrow["{F}", bend left = 30, from=1-1, to=1-2]
    \arrow["{G}", bend left = 30, from=1-2, to=1-1]
    \arrow[""{name=0, anchor=center, inner sep=0}, "{G} \,\circ\, {F}", from=1-1, to=1-1, out=-145, in=145, loop, distance=4em]
    \arrow[""{name=1, anchor=center, inner sep=0}, "{F} \,\circ\, {G}", from=1-2, to=1-2, out=35, in=-35, loop, distance=4em]
    \arrow["\theta", shorten <=3pt, shorten >=3pt, Rightarrow, from=0, to=1-1]
    \arrow["\phi"', shorten <=3pt, shorten >=3pt, Rightarrow, from=1, to=1-2]
\end{tikzcd}

\end{document}

答案1

如手冊第 3.2 節所述tikz-cd,可以使用它to path來調整路徑。為了找到合適的圓弧起始角度和終止角度,可以使用calc函式庫測量節點。雙箭頭也是透過 繪製的to path。這些路徑的結構是水平的。為了保留邊緣標籤,必須加入\tikztonodes的參數to path

\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}
\def\myradius{1.5em}
\begin{tikzcd}[column sep=large]
    C & D
    \arrow["{F}", bend left = 30, from=1-1, to=1-2]
    \arrow["{G}", bend left = 30, from=1-2, to=1-1]
    \arrow["{G} \,\circ\, {F}","\mathstrut"{name=0, anchor=center, inner sep=0}, from=1-1, to=1-1,to path={%
        let \p1=($(\tikztostart.north)-(\tikztostart.south)$),\n1={scalar(asin(0.5*\y1/\myradius))} in 
        (\tikztostart.south)arc[start angle=-\n1,end angle=-360+\n1,radius=\myradius]\tikztonodes (\tikztotarget)}]
    \arrow["{F} \,\circ\, {G}","\mathstrut"{name=1, anchor=center, inner sep=0}, from=1-2, to=1-2,to path={%
    let \p1=($(\tikztostart.north)-(\tikztostart.south)$),\n1={scalar(asin(0.5*\y1/\myradius))} in 
    (\tikztostart.north)arc[start angle=180-\n1,end angle=-180+\n1,radius=\myradius]\tikztonodes (\tikztotarget)}]
    \arrow["\theta", shorten <=3pt, shorten >=3pt, Rightarrow, from=0, to=1-1, to path={(\tikztostart|-\tikztotarget) -- (\tikztotarget)\tikztonodes}]
    \arrow["\phi"', shorten <=3pt, shorten >=3pt, Rightarrow, from=1, to=1-2, to path={(\tikztostart|-\tikztotarget) -- (\tikztotarget)\tikztonodes}]
\end{tikzcd}

\end{document}

在此輸入影像描述

答案2

以下是已接受答案稍作修改的版本。在水平箭頭中,我將箭頭與 的高度對齊,\tikztostart而不是\tikztotarget使其更高。然而,為了正確獲得箭頭的終點,我手動向座標添加了 3pt 的水平移動,這在程式碼中看起來相當難看。

在此輸入影像描述

\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{calc}
\begin{document}

\begin{tikzcd}[column sep=large]
    C & D
    \arrow["{F}", bend left = 30, from=1-1, to=1-2]
    \arrow["{G}", bend left = 30, from=1-2, to=1-1]
    \arrow["{G} \,\circ\, {F}","\mathstrut"{name=0, anchor=center, inner sep=0}, from=1-1, to=1-1,
        to path={let \p1=($(\tikztostart.north)-(\tikztostart.south)$),\n1={scalar(asin(0.5*\y1/1.5em))} in
            (\tikztostart.south) arc[start angle=-\n1,end angle=-360+\n1,radius=1.5em]\tikztonodes (\tikztotarget)}]
    \arrow["{F} \,\circ\, {G}","\mathstrut"{name=1, anchor=center, inner sep=0}, from=1-2, to=1-2,
        to path={let \p1=($(\tikztostart.north)-(\tikztostart.south)$),\n1={scalar(asin(0.5*\y1/1.5em))} in
            (\tikztostart.north) arc[start angle=180-\n1,end angle=-180+\n1,radius=1.5em]\tikztonodes (\tikztotarget)}]
    \arrow["\theta", shorten <=3pt, shorten >=3pt, Rightarrow, from=0, to=1-1, to path={(\tikztostart) -- ($(\tikztotarget|-\tikztostart)+(-3pt,0)$) \tikztonodes }]
    \arrow["\phi"', shorten <=3pt, shorten >=3pt, Rightarrow, from=1, to=1-2, to path={(\tikztostart) -- ($(\tikztotarget|-\tikztostart)+(3pt,0)$) \tikztonodes }]
\end{tikzcd}

\end{document}

答案3

TikZ-CD 使用 的 ,asymmetrical rectangle其中心錨點不在真正的垂直中心,而是axis_height在基線上方固定距離( ),以便同一行的節點之間的箭頭像數學模式箭頭一樣繪製。 (這也導致它們總是水平的。)

在此程式碼中,繪製圓弧段,使其穿過起點的中心(並且不接觸北錨點或南錨點)。為此,使用spath3和庫。intersections對水平/垂直以外的任何方向進行數學計算涉及太多數學,我無法弄清楚。從技術上講,該spath3函式庫僅用於刪除位於起始節點內部的圓段,可透過了解交點來確定適當的起始角度和結束角度。

我在 TikZ-CD 中添加了兩種使用該circle around rect node樣式的方法:

  1. circle = <padding><padding>預設為.5ex,大約是 TikZ-CD 中節點 inenr seps 的一半)

    如果填充為零,則以圓恰好接觸目標座標/節點的方式決定半徑。

  2. circle to = <angle>圍繞起始座標繪製一個圓,該圓「指向」方向<angle>且直徑為circle to distance

程式碼

\documentclass[tikz]{standalone}
\usepackage{tikz-cd}
\usetikzlibrary{calc, intersections, spath3}
\tikzset{
  circle around rect node/.style n args={3}{insert path={%
    % #1 = node name, #2 = angle, #3 = distance
    (#1.center) edge[
      path only, spath/save global=carn@circle,
      to path={arc[start angle={(180-(#2))}, delta angle=360, radius={(#3)/2}]}](#1)
    (#1.south west) edge[
      path only, spath/save global=carn@rect,
      to path={rectangle(\tikztotarget)}](#1.north east)
    [spath/.cd,
      split at intersections with={carn@circle}{carn@rect},
      remove components={carn@circle}{1,3},
      use=carn@circle]}}}
\tikzcdset{
  circle to distance/.initial=3em,
  circle to/.style={to path={
    [circle around rect node/.expanded={\tikztostart}{#1}
      {\pgfkeysvalueof{/tikz/commutative diagrams/circle to distance}}]
    \tikztonodes}},
  circle/.default=.5ex,
  circle/.style={
    execute at begin to={%
      \path[path only](\tikztostart)
        --coordinate[at end](tikzcd@circleend)(\tikztotarget);},
    to path={
      let \p{tikzcd@diff} = ($(tikzcd@circleend)-(\tikztostart)$) in
      [circle around rect node/.expanded={\tikztostart}
                                         {atan2(\y{tikzcd@diff},\x{tikzcd@diff})}
                                         {veclen(\p{tikzcd@diff})+(#1)}]
      \tikztonodes}}}
\tikzset{
  cd/.code=\tikzcdset{#1},
  cd node/.style={font=,cd=every cell,name={#1}}}
\begin{document}

\begin{tikzcd}[
  column sep=large, bend angle=30,
%  /tikz/column 1/.append style={cd={column sep=normal}},
%  /tikz/column 3/.append style={cd={column sep=normal}},
]
  G \circ F \arrow[r, "\theta", Rightarrow]
& C         \arrow[r, "F", bend left]
            \arrow[l, circle]
& D         \arrow[l, "G", bend left]
            \arrow[r, circle]
& F \circ G \arrow[l, "\phi"', Rightarrow]
\end{tikzcd}

\begin{tikzcd}[column sep=large, bend angle=30]
  C \arrow[r, "F", bend left]
    \arrow[circle to=180, "G \circ F"' cd node=GF]
    \arrow[Rightarrow, shorten <=.8ex, from=GF, "\theta"]
& D \arrow[l, "G", bend left]
    \arrow[circle to=  0, "F \circ G"' cd node=FG]
    \arrow[Rightarrow, shorten <=.8ex, from=FG, "\phi"']
\end{tikzcd}

\begin{tikzpicture}
\node[draw] (A) {A};
\foreach[count=\i] \ang in {0, 45, ..., 359}
  \draw[red!\i0!blue, circle around rect node={A}{\ang}{1cm}];
\end{tikzpicture}
\end{document}

輸出

在此輸入影像描述

在此輸入影像描述

相關內容