一组有序的三个点唯一地定义了一个圆弧,我希望能够在 TikZ 中绘制该圆弧。我知道arc
绘图命令,它根据给定的半径、两个角度和一个端点来完成工作,但为了做到这一点,我必须计算半径和圆弧上其他两个点的角度。我想我可以使用 PGF 数学库编写一些代码来自动执行此操作,但有没有更好的方法?或者有其他人已经将其制作成我可以重用的包/库?
答案1
使用如下代码绘制经过 (1,2),(3,4) 和 (2,4) 且从 (1,2) 逆时针到 (2,4) 的圆对应的圆弧。
\documentclass[a4paper]{article}
\usepackage{tkz-euclide}
\usetkzobj{all}
\begin{document}
\begin{tikzpicture}
\tkzDefPoint(1,2){A}\tkzDefPoint(3,4){B}\tkzDefPoint(2,4){C}
\tkzCircumCenter(A,B,C)\tkzGetPoint{O}
\tkzDrawArc(O,A)(C)
\end{tikzpicture}
\end{document}
答案2
请记住,我实际上并不了解 TikZ。我按照你说的做了:我使用 pgf math 计算出角度和半径的值,然后将其打包成一个简单的宏。
\documentclass[border=10]{standalone}
\usepackage{tikz}
\def\drawcirculararc(#1,#2)(#3,#4)(#5,#6){%
\pgfmathsetmacro\cA{(#1*#1+#2*#2-#3*#3-#4*#4)/2}%
\pgfmathsetmacro\cB{(#1*#1+#2*#2-#5*#5-#6*#6)/2}%
\pgfmathsetmacro\cy{(\cB*(#1-#3)-\cA*(#1-#5))/%
((#2-#6)*(#1-#3)-(#2-#4)*(#1-#5))}%
\pgfmathsetmacro\cx{(\cA-\cy*(#2-#4))/(#1-#3)}%
\pgfmathsetmacro\cr{sqrt((#1-\cx)*(#1-\cx)+(#2-\cy)*(#2-\cy))}%
\pgfmathsetmacro\cA{atan2(#1-\cx,#2-\cy)}%
\pgfmathsetmacro\cB{atan2(#5-\cx,#6-\cy)}%
\pgfmathparse{\cB<\cA}%
\ifnum\pgfmathresult=1
\pgfmathsetmacro\cB{\cB+360}%
\fi
\draw (#1,#2) arc (\cA:\cB:\cr);%
}
\begin{document}
\begin{tikzpicture}
\drawcirculararc(0,0)(1,0)(1,1);
\end{tikzpicture}
\end{document}
使用以下公式计算原点和半径并不难
r2 = (X我-X)2 + (是我-是)2
为我在 {1,2,3} 中。
宏假定点是按逆时针方向输入的。在某些情况下,它可能会失败,因为我没有对其进行广泛的测试。
我想我应该指出,圆心 ( \cx
, \cy
) 的计算取决于某些不为零的量。可以写下三个\cx
与 和相关的线性方程\cy
。其中任何两个都足以(当然)解决系统,因此有三种可能的选择。我没有检查,但我相信相关量不可能全部为零(除非你的点是共线的,但那样你就没有圆了)。
如果有人愿意,可以根据使用哪两个方程来概括\cx
和的计算\cy
,然后选择一个分母不为零的方程。由于有更好的解决方案,所以我没有费心,但我想如果有人真的关心的话我可以。
答案3
ext.topaths.arcthrough
我的图书馆tikz-ext
扩展包已根据该答案创建并提供了一个arc through
需要一个坐标的键(包括()
可能以+
或开头的++
)。
它避免了
tkz-euclide
或者使用分离路径的类似解决方案(这使得无法使用圆弧作为路径的一部分;- 该
calc
库而是使用 PGF 已经存在的宏\pgfpointlineattime
和\pgfpointintersectionofline
以及\pgfmathrotatepointaround
和\pgfmathanglebetweenpoints
。
作为参数,arc through
也接受clockwise
和counter clockwise
(默认)。
作为参数给出的点用于计算半径。圆弧不一定通过该点绘制,圆圈圆弧所在的位置经过该点。这样就可以绘制圆的其余部分,而无需给出另一个坐标。(这个名字arc on circle that goes through
可能更适合这个……)
坐标arc through center
在路径之后定义,可以供以后参考(arc through
当然,只要没有再次使用其他坐标)。
代码
\documentclass[tikz]{standalone}
\usetikzlibrary{ext.topaths.arcthrough}
\begin{document}
\begin{tikzpicture}
\coordinate[label=above right:$A$] (A) at ( 3, 1);
\coordinate[label=above:$B$] (B) at ( 1, 2);
\coordinate[label=below left:$C$] (C) at (-2,-2);
\draw[ultra thick, draw=green, fill=green!50]
(B) to[arc through={clockwise,(A)}] (C)
-- (arc through center) -- cycle;
\draw[ultra thick, draw=blue, fill=blue!50]
(B) to[arc through=(A)] (C)
-- (arc through center) -- cycle;
\foreach \p in {A,B,C, arc through center}
\fill[red] (\p) circle[radius=2pt];
\end{tikzpicture}
\end{document}
输出
答案4
我在浏览 TikZ/PGF 手册时偶然发现了这个\pgfpatharcto
命令。该命令以给定的半径(实际上是椭圆半径)从某个点到特定点绘制一条圆弧。因此,一旦确定了半径,就可以使用此命令绘制圆弧。当然,一旦计算出半径,角度的计算就不那么困难了,所以这不是一个很好的解决方案。此外,手册特别警告说,所涉及的计算\pgfpatharcto
不可靠。所以我发布这篇文章部分是为了强调这个\pgfpatharcto
命令,但主要是为了将解决方案重新定义为to
路径。
\documentclass{article}
\usepackage{tikz}
\makeatletter
\def\bc@save@ctrla#1{
\def\bc@ctrla{#1}}
\def\bc@save@target#1{
\def\bc@target{#1}}
\def\bc@save@start#1{
\def\bc@start{#1}}
\tikzset{%
arc between/.style={
to path={
\pgfextra{
\edef\bc@@target{(\tikztotarget)}
\tikz@scan@one@point\bc@save@target\bc@@target\relax
\edef\bc@@start{(\tikztostart)}
\tikz@scan@one@point\bc@save@start\bc@@start\relax
\pgfkeysgetvalue{/tikz/arc between/mid point}{\bc@@ctrla}
\tikz@scan@one@point\bc@save@ctrla\bc@@ctrla\relax
\bc@start
\edef\bc@sx{\the\pgf@x}
\edef\bc@sy{\the\pgf@y}
\bc@target
\edef\bc@tx{\the\pgf@x}
\edef\bc@ty{\the\pgf@y}
\bc@ctrla
\edef\bc@mx{\the\pgf@x}
\edef\bc@my{\the\pgf@y}
\pgfmathsetmacro{\bc@a}{veclen(\bc@mx - \bc@sx,\bc@my - \bc@sy)/1cm}
\pgfmathsetmacro{\bc@b}{veclen(\bc@tx - \bc@mx,\bc@ty - \bc@my)/1cm}
\pgfmathsetmacro{\bc@c}{veclen(\bc@sx - \bc@tx,\bc@sy - \bc@ty)/1cm}
\pgfmathsetmacro{\bc@s}{(\bc@a + \bc@b + \bc@c)/2}
\pgfmathsetmacro{\bc@r}{\bc@a * \bc@b * \bc@c/(4 * sqrt(\bc@s * (\bc@s - \bc@a) * (\bc@s - \bc@b) * (\bc@s - \bc@c)))}
\pgfpatharcto{\bc@r cm}{\bc@r cm}{0}{0}{0}{\bc@target}
}
},
arc between/.cd,
},
arc between/mid point/.initial={},
}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw (3,0) to[arc between, mid point={+(1,1)}] +(2,0);
\fill (3,0) circle[radius=2pt] +(1,1) circle[radius=2pt] +(2,0) circle[radius=2pt] ;
\end{tikzpicture}
\end{document}
此代码有几条注释。指定中点的键实际上是/tikz/arc between/mid point
。键/tikz/arc between
切换到子树/tikz/arc between
。这意味着任何后续键都是相对于此子树获取的。在正确的代码中,应该有一个 fall-through,以便任何 TikZ 键都传回树/tikz
。其次,这不会正确更新最后一个位置,因此在此命令后使用相对坐标将相对于起始位置。我不确定最好的解决方案。实际上,回到第一点。更好的方法是将中点指定为键的参数/tikz/arc between
。
结果: