Нарисуйте круговой путь к самому узлу в 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примерно половина inenr seps узлов в TikZ-CD)

    Если заполнение равно нулю, это определяет радиус таким образом, что окружность будет только касаться целевой координаты/узла.

  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}

Выход

введите описание изображения здесь

введите описание изображения здесь

Связанный контент