An ordered set of three points uniquely defines a circular arc, and I'd like to be able to draw that arc in TikZ. I know about the arc
drawing command, which does the job given a radius, two angles, and one endpoint, but in order to do that I would have to calculate the radius and the angles from the other two points on the arc. I suppose I could whip up some code to do that automatically using the PGF math library, but is there a better way? Or has anyone else already made this into a package/library I could reuse?
-
6an ordered set of three distinct, non colinear points...– SeamusMay 24, 2011 at 11:01
-
2@Seamus: an ordered set of 3 non colinear points should be enough.– kiss my armpitMar 19, 2013 at 21:29
7 Answers
Use the following code to draw the arc corresponding to the circle through (1,2), (3,4) and (2,4) and going anticlockwise from (1,2) to (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}
-
-
2Ah.
tkz-euclide
requires tikz 2.10. The version in the debian repos is 2.00...– SeamusMay 31, 2011 at 11:53 -
2@Seamus Debian is also stuck on TeX Live 2009 and doesn't include
tlmgr
. For a while, Debian was stuck on TeX Live 2007. For this reason Debian TeX packages are not recommended, unless you can live with waiting two years between major updates.– SharpieMay 31, 2011 at 16:54
Keep in mind that I don't actually know TikZ. I did what you said: I used pgf math to work out the values for the angles and the radius and then packaged it up into a simple macro.
\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}
It isn't terribly hard to work out the origin and the radius using
r2 = (xi - x)2 + (yi - y)2
for i in {1,2,3}.
The macro assumes that the points are entered counterclockwise. It probably fails in some cases, since I didn't test it very extensively.
I guess I should point out that that the computation of the center of the circle, (\cx
,\cy
) depends on some quantities not being zero. One can write down three linear equations relating \cx
and \cy
. Any two of them suffice for solving (of course) the system so there are three possible choices. I didn't check, but I believe it's impossible for the relevant quantities to all be zero (unless your points are colinear, but then you don't have a circle).
If one were so inclined, one could generalize the computation of \cx
and \cy
depending on which two equations are used and then just pick one for which the denominators are not zero. Since there's a better solution, I didn't bother, but I guess I could if someone actually cares.
-
3You can simplify things a bit by using
\pgfmathsetmacro{\cx}{...}
instead of\pgfmathparse{...}\let\cx\pgfmathresult
. Apr 17, 2011 at 10:10 -
@Matthew: Thanks. I've updated it. Using
\pgfmathresult
over and over seemed really clumsy. I'm glad there's a better way.– TH.Apr 17, 2011 at 10:21 -
@Matthew: cool, I didn't know you could do that! Thanks for the tip.– David ZApr 17, 2011 at 21:46
-
@TH. As much as I like this idea, it draws the circle in the wrong location for e.g.
\drawcirculararc(0,0)(1,0)(1,1)
.– David ZApr 17, 2011 at 22:01 -
@David: Yeah. I failed to solve the simple equations correctly last night so the center of the circle is wrong.– TH.Apr 17, 2011 at 22:44
The ext.topaths.arcthrough
library from my tikz-ext
ensions package has been created from this answer and provied a arc through
key that expects one coordinate (including the ()
as it may preceeded with +
or ++
).
It avoids
tkz-euclide
or similar solutions that uses a separated path (which makes it impossible to use the arc as part of a path;- the
calc
library and instead uses PGF’s already present macros\pgfpointlineattime
and\pgfpointintersectionofline
as well as\pgfmathrotatepointaround
and\pgfmathanglebetweenpoints
.
As an argument, arc through
also accepts clockwise
and counter clockwise
(default).
The point that is given as an argument is used to calculate the radius. The arc is not necessary drawn through this point, the circle on which the arc lies goes through this point.
This makes it possible to draw the rest of said circle without the need to give another coordinate. (The name arc on circle that goes through
would probably be a better name for this …)
The coordinate arc through center
is defined after the to path and can be used for later reference (as long as no other arc through
is used again, of course).
This solution uses the same calculation algorithm as the one in JLDiaz’ answer.
Code
\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}
Output
-
2In my opinion this is the best answer. Your code will definitely go a long way in my documents. Jan 27, 2020 at 21:16
Edit: The original code didn't work with TikZ 3.00
since atan2(x,y)
has been redefined: its first and second arguments have to be switched. This edit fixes this.
Just for completeness, a tikz
solution which does not use tikz-euclide
, but instead does all the calculations through calc
library and let..in
syntax. Macro \arcThroughThreePoints
requires the three coordinates to be given in counter-clockwise order.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand{\arcThroughThreePoints}[4][]{
\coordinate (middle1) at ($(#2)!.5!(#3)$);
\coordinate (middle2) at ($(#3)!.5!(#4)$);
\coordinate (aux1) at ($(middle1)!1!90:(#3)$);
\coordinate (aux2) at ($(middle2)!1!90:(#4)$);
\coordinate (center) at ($(intersection of middle1--aux1 and middle2--aux2)$);
\draw[#1]
let \p1=($(#2)-(center)$),
\p2=($(#4)-(center)$),
\n0={veclen(\p1)}, % Radius
\n1={atan2(\x1,\y1)}, % angles
\n2={atan2(\x2,\y2)},
\n3={\n2>\n1?\n2:\n2+360}
in (#2) arc(\n1:\n3:\n0);
}
\begin{document}
\begin{tikzpicture}
\coordinate (A) at (3,1);
\coordinate (B) at (1,2);
\coordinate (C) at (-2,-2);
\arcThroughThreePoints{A}{B}{C};
\foreach \p in {A,B,C,center}
\fill[red] (\p) circle(2pt);
\end{tikzpicture}
\end{document}
Edit: With TikZ 3.00
and later, the previous code is now:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand{\arcThroughThreePoints}[4][]{
\coordinate (middle1) at ($(#2)!.5!(#3)$);
\coordinate (middle2) at ($(#3)!.5!(#4)$);
\coordinate (aux1) at ($(middle1)!1!90:(#3)$);
\coordinate (aux2) at ($(middle2)!1!90:(#4)$);
\coordinate (center) at ($(intersection of middle1--aux1 and middle2--aux2)$);
\draw[#1]
let \p1=($(#2)-(center)$),
\p2=($(#4)-(center)$),
\n0={veclen(\p1)}, % Radius
\n1={atan2(\y1,\x1)}, % angles
\n2={atan2(\y2,\x2)},
\n3={\n2>\n1?\n2:\n2+360}
in (#2) arc(\n1:\n3:\n0);
}
\begin{document}
\begin{tikzpicture}
\coordinate (A) at (3,1);
\coordinate (B) at (1,2);
\coordinate (C) at (-2,-2);
\arcThroughThreePoints{A}{B}{C};
\foreach \p in {A,B,C,center}
\fill[red] (\p) circle(2pt);
\end{tikzpicture}
\end{document}
I guess this answer does not qualifies as "the easiest way", as the title of the question requests, but it shows some nifty tricks.
I was browsing in the TikZ/PGF manual when I came across the \pgfpatharcto
command. This draws an arc from a point to a specific point, with a given radius (actually, elliptical radii). So once the radius has been figured out then this command can be used to draw the arc. Of course, once one has computed the radius then the angles aren't all that difficult to compute either so this isn't a great solution. Moreover, the manual specifically warns that the computations involved in \pgfpatharcto
are unreliable. So I'm posting this partly to highlight the \pgfpatharcto
command but mostly to recast the solution as a to
path.
\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}
There are a couple of comments on this code. The key for specifying the mid point is actually /tikz/arc between/mid point
. The key /tikz/arc between
switches to the subtree /tikz/arc between
. This means that any subsequent keys are taken relative to this subtree. In Proper Code, there ought to be a fall-through so that any TikZ keys are passed back to the /tikz
tree. Secondly, this doesn't update the last position properly, so using relative coordinates after this command will be relative to the starting position. I'm not sure of the best solution to that. Actually, back on that first point. A better method would be to specify the mid point as an argument to the /tikz/arc between
key.
Result:
-
Am I missing something or is this a terribly complicated way of getting the radius? Can't you just get the distance between the centre of the circle and any of the points and use this as the radius? And the centre of the circle is just the intersection of the perpendicular bisectors of the lines between the points... This could be done with
calc
andintersection
much more easily, surely...– SeamusMay 31, 2011 at 14:56 -
@Seamus: Depends what you mean by "complicated". I suspect that the computations needed by
calc
andintersection
to find that radius would be as complicated. Part of the point of this (and I'll admit there isn't much point) is that it is self-contained and does no more than strictly necessary. Computing the centre is unnecessary, ergo: don't do it. May 31, 2011 at 16:59 -
@Seamus: I should also make it clear that this is another of my "If the other answers weren't there, I wouldn't have posted this.". There's a great comment by Dima on one of my old answers, I should look it up and put it somewhere for all to see so that they understand me better! May 31, 2011 at 17:01
-
OK fair enough. But still I think
pgfarcto
is cool enough that it deserves a nice simple demonstration...– SeamusMay 31, 2011 at 18:03 -
@Seamus: In that case, you should ask a question that will lead to a nice simple demonstration of it ...! May 31, 2011 at 18:26
Just another simpler solution with PSTricks.
\documentclass[pstricks,border=3pt]{standalone}
\usepackage{pst-eucl}
\begin{document}
\pspicture(5,5)
\pstGeonode[PosAngle={-135,45,90}](1,2){A}(3,4){B}(2,4){C}
\pstCircleABC[DrawCirABC=false]{A}{B}{C}{O}
\pstArcnOAB{O}{A}{B}
\endpspicture
\end{document}
-
1
-
They usually don't do that because it could spark a wave of hate from you to him (you could make a series of downvoting on all his questions). Mar 20, 2013 at 5:49
-
8I couldn't say whether this is a reason for downvoting, but the question did ask for a solution in TikZ.– David ZJul 3, 2013 at 2:15
Here a code with the last version 4.25. I don't completely agree with Qrrbrbirlbel's statement: With
tkz-euclide or similar solutions that uses a separated path (which makes it impossible to use the arc as part of a path;
This is only partially true. There is nothing to prevent you from using tkz-euclide
in order to get the center of the arc, to calculate the radius OA and the start and end angles. Then you can draw what you want with TikZ
if necessary!
\documentclass{standalone}
\usepackage{tkz-euclide}
\begin{document}
\begin{tikzpicture}
\tkzDefPoint(1,2){A}\tkzDefPoint(3,4){B} \tkzDefPoint(2,4){C}
\tkzDefTriangleCenter[circum](A,B,C) \tkzGetPoint{O}
\tkzDrawArc[delta=0](O,A)(C)
\tkzFillSector[green!10](O,A)(C)
\tkzDrawSector(O,A)(C)
\tkzDrawPoints(O,A,B,C)
\end{tikzpicture}
\begin{tikzpicture}
\tkzDefPoint(1,2){A}\tkzDefPoint(3,4){B} \tkzDefPoint(2,4){C}
\tkzDefTriangleCenter[circum](A,B,C) \tkzGetPoint{O}
\tkzDrawArc[delta=0](O,C)(A)
\tkzFillSector[red!10](O,C)(A)
\tkzDrawSector(O,C)(A)
\tkzDrawPoints(O,A,B,C)
\end{tikzpicture}
\end{document}