我正在尝试实现与 PSTricks\nccircle
命令等效的效果,从而产生一个圆形的循环。
理想的做法是有一个/tikz/loop circle
以角度选项命名的命令,因为有命令/tikz/loop
,,/tikz/loop above
...
\begin{tikzpicture}
\node [draw] {Stuff} edge [loop circle, radius=10mm] node {ncircle} ();
\end{tikzpicture}
以下是我的研究概要:
红色圆圈应位于虚线圆圈的上方。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\tikzset{% TikZ equivalent to the PSTricks \nccircle command
circle angle/.initial={0},%
circle radius/.initial={10mm},%
}
\newcommand{\circleangle}{\pgfkeysvalueof{/tikz/circle angle}}% start angle
\newcommand{\circleradius}{\pgfkeysvalueof{/tikz/circle radius}}%
\tikzstyle{label}=[black, sloped, anchor=south, pos=0.5]% label style
\makeatletter
\newcommand{\calcHeight}[2]{
\pgfpointdiff{\pgfpointanchor{#1}{center}}{\pgfpointanchor{#2}{center}}
\pgfmathsetlengthmacro{\myheight}{sqrt(pow(\circleradius,2) - pow(0.5*\pgf@x,2) - pow(0.5*\pgf@y,2))}
}
\makeatother
\newcommand{\ncircle}[3][]{% \ncircle[options]{node A}{label}
\begin{tikzpicture}[remember picture,overlay,#1]
\coordinate (p1) at (#2.\circleangle) ;% starting point
\filldraw (p1) [blue] circle [radius=1pt];
\coordinate (p2) at (#2.center) ;% node center
\filldraw (p2) [green] circle [radius=1pt];
\calcHeight{p1}{p2}%
\coordinate (p3) at ($(p1)!0.5!(p2)!\myheight!90:(p1)$) ;% circle center
\filldraw (p3) [red] circle [radius=1pt];
\draw[dashed,green] (p3) circle [radius=\circleradius] ;
\pgfmathanglebetweenlines
{\pgfpointanchor{p3}{center}}{\pgfpointanchor{p2}{center}}
{\pgfpointanchor{p3}{center}}{\pgfpointanchor{p1}{center}}
\let\myresult\pgfmathresult
\draw[red, ->, >=stealth, thin, shorten <= 3pt, shorten >= 3pt]
(#2.\circleangle) %[rotate around={0.5*\myresult:(p3)}]
arc[start angle=\circleangle-90,delta angle=360-2*\myresult,radius=\circleradius]
node[label,rotate={0.*\myresult}]{#3} ;
\end{tikzpicture}}
\begin{tikzpicture}[remember picture,baseline]
\draw[help lines,step=1,dashed] (0,0) grid (4,4);
\node[draw,outer sep = 0pt,inner sep = 5mm] at (3,1) (NodeA) {Stuff};
\end{tikzpicture}
\ncircle[circle angle=60]{NodeA}{ncircle}
\end{document}
答案1
使用“交叉点”库的解决方案。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{shapes}
\usetikzlibrary{intersections}
\begin{document}
\newif\ifswap
\tikzset{% TikZ equivalent to the PSTricks \ncbar command
shortenA/.store in = \shortenA, shortenA = 0pt,% Shorten the path in the direction of A
shortenB/.store in = \shortenB, shortenB = 0pt,% Shorten the path in the direction of B
shorten/.style={shortenA=#1, shortenB=#1},
circle angle/.store in = \circleangle, circle angle = 0,% angle of circle
circle radius/.store in = \circleradius, circle radius = 7mm,% radius of circle
swap/.is if=swap,% permutation between internal and external arc
swap=false,
}
\newcommand{\ncircle}[3][]{% \ncircle[options]{same name path and name node}{label}
\begin{scope}[#1]
\coordinate (O) at ($(#2.center)+(\circleangle+90:\circleradius)$);
\path[name path=circle] (O) circle [radius=\circleradius];
\ifswap
\path[name intersections={of=#2 and circle, by={B,A}}];
\else
\path[name intersections={of=#2 and circle, by={A,B}}];
\fi
\pgfmathanglebetweenpoints{\pgfpointanchor{O}{center}}{\pgfpointanchor{A}{center}}
\pgfmathparse{\pgfmathresult+deg(\shortenA/\circleradius)}
\let\startangle\pgfmathresult
\pgfmathanglebetweenlines
{\pgfpointanchor{O}{center}}{\pgfpointanchor{A}{center}}
{\pgfpointanchor{O}{center}}{\pgfpointanchor{B}{center}}
\pgfmathparse{\pgfmathresult-deg((\shortenA+\shortenB)/\circleradius)}
\let\deltaangle\pgfmathresult
\draw[->, >=stealth, thin] ($(O)+(\startangle:\circleradius)$)
arc[start angle=\startangle,delta angle=\deltaangle,radius=\circleradius]
node[label,sloped]{#3} ;
\end{scope}}
\tikzstyle{label}=[draw,text=red,sloped,anchor=south,pos=0.5,inner sep =2pt]% label style
\begin{tikzpicture}
\draw[help lines,step=1,dashed] (0,0) grid (4,3);
\node[draw,ellipse,name path=NodeA,minimum width=2cm,align=center] at (3,1) (NodeA) {Stuff};
\ncircle[circle angle=70,circle radius=12mm,shorten=1pt,swap=false]{NodeA}{ncircle}
\end{tikzpicture}
\end{document}