# What is the simplest way to align a line with a circle?

Is there a simple way with TikZ to align a line to a circle without manually specifying an arc to join two separate lines like in the example below?

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\filldraw[black] (0.5,0.5) circle (0.5);
\draw[-,thick,red] (-1,1) -- (0.5,1);
\draw[-,thick,red] (1,-1) -- (1,0.5);
\draw[-,thick,red] (1,0.5) arc (0:90:0.5);
\end{tikzpicture}
\end{document}


If possible the solution should be a single command producing the following behaviour:

1. Draw a circle C (specified by its center and radius)
2. Draw a line with three parts:
1. First part is the line segment from any point P to a point Q on the perimeter of C.
2. Second part is the arc of 90 degrees angle along the perimeter of C.
3. Third part is the line segment away from the arc.

In pseudo code:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\filldraw[black] (0.5,0.5) coordinate (C) circle (0.5);
\draw[-,thick,red] (-1,1) -- (0.5,1) arc (C,90) -- (1,0.5);
% The line above would draw a line to (0.5,1),
% an arc of 90 degrees around (C) and continue
% from there towards (1,0.5)
\end{tikzpicture}
\end{document}


The pseudo code above should result in the same image as above.

# Optional features

Even more convenient would be to allow arbitrary angles and to continue the line after the arc with the direction of the tangent at the exit point:

In pseudo code:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\filldraw[black] (0.5,0.5) coordinate (C) circle (0.5);
\draw[-,thick,red] (-1,1) -- (0.5,1) arc (C,45) -- (1cm);
% The line above would draw a line to (0.5,1),
% an arc of 45 degrees around (C) and continue a
% line of 1cm length from there
\end{tikzpicture}
\end{document}

-
I'm sure it's very possible, but the constraints you're working with aren't really clear from the question. What do you have to start with? A circular node? A circle specified by its centre and radius? A solution would probably boil down to defining a macro to draw the arc in an automated way. – Hammerite Jan 10 '14 at 20:52
Well, I don't have any constraints, but maybe just stick with the circle by center/radius like in the example code. A macro would be fine, although I thought of some syntax magic to bend a line according to point and radius or similar. – slash Jan 10 '14 at 20:59
So... given a circle C (specified by its centre and radius) and a point P outside the circle, draw a curve that has three parts; the first part is the line segment from P to the perimeter of C (at Q, say) that is tangent to C at Q (either choice will do, or provide a way to select one of the two choices); the second part is a quarter-circle arc as shown in the example; the third part is a line segment as shown in the example, of the same length as the first part? – Hammerite Jan 10 '14 at 21:20
Yes, that would be a more accurate description, I will change the question accordingly. The third part (line segment) would not necessarily have to be of the same length as line segment one. – slash Jan 10 '14 at 21:32

Option rounded corners can be used to draw an arc without specifying the more complex syntax of arc:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[x=1cm, y=1cm]
\filldraw[black] (0.5,0.5) circle (0.5);
\draw[-,thick,red]
(-1,1) [rounded corners=0.5cm] -- (1,1)
[sharp corners] -- (1,-1) -- (-1,-1)
;
\end{tikzpicture}
\end{document}


• Option sharp corners switches off the rounding on corners.

## Different x and y units

• Option rounded corners will not work, if the unit in x and y direction is different, because the rounding remains symmetrically.
• Also the unit must be explicitly specified in the example above.

Option rounded corners internally uses \pgfpoint, by using \pgfpointxy the two issues are addressed:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[x=2cm,y=1cm]
\filldraw[black] (0.5,0.5) circle (0.5);
\draw[-,thick,red]
(-1,1) \pgfextra{\pgfsetcornersarced{\pgfpointxy{.5}{.5}}} -- (1,1)
[sharp corners] -- (1,-1) -- (-1,-1)
;
\end{tikzpicture}
\end{document}


Or a better readability is achieved by defining a new option:

\documentclass{article}
\usepackage{tikz}
\tikzoption{circle corner}{\pgfsetcornersarced{\pgfpointxy{#1}{#1}}}
\begin{document}
\begin{tikzpicture}[x=2cm,y=1cm]
\filldraw[black] (0.5,0.5) circle (0.5);
\draw[-,thick,red]
(-1,1) [circle corner=0.5] -- (1,1)
[sharp corners] -- (1,-1) -- (-1,-1)
;
\end{tikzpicture}
\end{document}


-

A recommended solution with PSTricks.

## Still version

With pst-eucl:

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-eucl}
\psset{PointName=none,PointSymbol=none,linewidth=3\pslinewidth}
\begin{document}
\begin{pspicture}[showgrid](9,7)
\pstGeonode(4,4){O}(1,2){A}(8,1){B}
\pstMiddleAB{A}{O}{A'}
\pstMiddleAB{B}{O}{B'}
\psset{linecolor=red}
\psline(A)(M2)
\psline(B)(N1)
\psarc[origin={O}](O){2}{(N1)}{(M2)}
\end{pspicture}
\end{document}


With pstricks-add (shorter):

\documentclass[pstricks,border=12pt]{standalone}
\psset{dimen=medusa,linewidth=3\pslinewidth}
\begin{document}
\begin{pspicture}[showgrid](9,7)
\pnodes(4,4){O}(1,2){A}(8,1){B}
\pscircle(O){2}
\psCircleTangents(A)(O){2}
\pnodes(CircleT2){M}
\psCircleTangents(B)(O){2}
\pnodes(CircleT1){N}
\psset{linecolor=red}
\psline(A)(M)
\psline(B)(N)
\psarc[origin={O}](O){2}{(N)}{(M)}
\end{pspicture}
\end{document}


## Animated version

With pst-eucl:

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-eucl}
\psset{PointName=none,PointSymbol=none,linewidth=3\pslinewidth}
\begin{document}
\multido{\r=0.0+.5}{18}{%
\begin{pspicture}[showgrid](9,7)
\pstGeonode(4,4){O}(1,2){A}(\r,1){B}
\pstMiddleAB{A}{O}{A'}
\pstMiddleAB{B}{O}{B'}
\psset{linecolor=red}
\psline(A)(M2)
\psline(B)(N1)
\psarc[origin={O}](O){2}{(N1)}{(M2)}
\end{pspicture}}
\end{document}


With pstricks-add (shorter):

\documentclass[pstricks,border=12pt]{standalone}
\psset{dimen=medusa,linewidth=3\pslinewidth}
\begin{document}
\multido{\r=0.0+.5}{18}{%
\begin{pspicture}[showgrid](9,7)
\pnodes(4,4){O}(1,2){A}(\r,1){B}
\pscircle(O){2}
\psCircleTangents(A)(O){2}
\pnodes(CircleT2){M}
\psCircleTangents(B)(O){2}
\pnodes(CircleT1){N}
\psset{linecolor=red}
\psline(A)(M)
\psline(B)(N)
\psarc[origin={O}](O){2}{(N)}{(M)}
\end{pspicture}}
\end{document}


## Notes:

For multiple invocation of \psCircleTangents, the output node(s) CircleT1 and/or CircleT2 must be saved or buffered or backed up in temporary node(s) first before the next call of \psCircleTangents because \psCircleTangents outputs the tangent points with the same names.

-

Here is a TikZ solution via three new to path:

1. cw wrap around wraps around the circle in clockkwise direction.
2. acw wrap around wraps around the circle in anticlockkwise direction.
3. wrap around chooses the better direction between clockwise and anticlockkwise.

The parameters are the same for these three options: {centerbyradius}. An error occurs when no solution exists.

Examples of use (a and b are the start and end points):

\draw (a) to[wrap around=c by 1cm] (b);
\draw (a) to[cw wrap around=c by 1cm] (b);
\draw (a) to[acw wrap around=c by 1cm] (b);


Some results (orange: clockwise, lime: anticlockwise, black: best):

The code:

\documentclass[tikz]{standalone}
\usetikzlibrary{calc}

\makeatletter
\tikzset{
cw wrap around/.style args={#1 by #2}{
to path={
let
\p1=(\tikztostart), \p2=(\tikztotarget), \p3=(#1),
\n1={veclen(\x3-\x1,\y3-\y1)}, \n2={veclen(\x3-\x2,\y3-\y2)}, \n3={#2},
\n{test}={((\n1 < \n3)||(\n2 < \n3))?1:0}
in
\pgfextra{
\pgfmathtruncatemacro\val{\n{test}}
\ifnum\val=1 %
\fi
\pgfinterruptpath
\node[line width=0,circle,minimum size=2*\n3,inner sep=0] (cir) at (#1) {};
\coordinate (i1) at (tangent cs:node=cir,point={(\p1)},solution=1);
\coordinate (i2) at (tangent cs:node=cir,point={(\p2)},solution=2);
\endpgfinterruptpath
}
let \p{i1}=(i1), \p{i2}=(i2) in
\pgfextra{
\pgfmathsetmacro\angstart{atan2(\y{i1}-\y1,\x{i1}-\x1)-90}
\pgfmathsetmacro\angend{atan2(\y{i2}-\y2,\x{i2}-\x2)+90}
\pgfmathsetmacro\angend{\angend<\angstart?\angend+360:\angend}
\pgfmathsetmacro\angend{\angend>\angstart+360?\angend-360:\angend}
}
-- (i1) arc[start angle=\angstart,end angle=\angend,radius=\n3] --(\p2)
},
},
acw wrap around/.style args={#1 by #2}{
to path={
let
\p1=(\tikztostart), \p2=(\tikztotarget), \p3=(#1),
\n1={veclen(\x3-\x1,\y3-\y1)}, \n2={veclen(\x3-\x2,\y3-\y2)}, \n3={#2},
\n{test}={((\n1 < \n3)||(\n2 < \n3))?1:0}
in
\pgfextra{
\pgfmathtruncatemacro\val{\n{test}}
\ifnum\val=1 %
\fi
\pgfinterruptpath
\node[line width=0,circle,minimum size=2*\n3,inner sep=0] (cir) at (#1) {};
\coordinate (i1) at (tangent cs:node=cir,point={(\p1)},solution=2);
\coordinate (i2) at (tangent cs:node=cir,point={(\p2)},solution=1);
\endpgfinterruptpath
}
let \p{i1}=(i1), \p{i2}=(i2) in
\pgfextra{
\pgfmathsetmacro\angstart{atan2(\y{i1}-\y1,\x{i1}-\x1)+90}
\pgfmathsetmacro\angend{atan2(\y{i2}-\y2,\x{i2}-\x2)-90}
\pgfmathsetmacro\angend{\angend>\angstart?\angend-360:\angend}
\pgfmathsetmacro\angend{\angend<\angstart-360?\angend+360:\angend}
}
-- (i1) arc[start angle=\angstart,end angle=\angend,radius=\n3] --(\p2)
},
},
wrap around/.style args={#1 by #2}{
to path={
let
\p1=(\tikztostart), \p2=(\tikztotarget), \p3=(#1),
\n1={veclen(\x3-\x1,\y3-\y1)}, \n2={veclen(\x3-\x2,\y3-\y2)}, \n3={#2},
\n{test}={((\n1 < \n3)||(\n2 < \n3))?1:0}
in
\pgfextra{
\pgfmathtruncatemacro\val{\n{test}}
\ifnum\val=1 %
\fi
\pgfinterruptpath
\node[line width=0,circle,minimum size=2*\n3,inner sep=0] (cir) at (#1) {};
\coordinate (i1cw) at (tangent cs:node=cir,point={(\p1)},solution=1);
\coordinate (i1acw) at (tangent cs:node=cir,point={(\p1)},solution=2);
\coordinate (i2cw) at (tangent cs:node=cir,point={(\p2)},solution=2);
\coordinate (i2acw) at (tangent cs:node=cir,point={(\p2)},solution=1);
\endpgfinterruptpath
}
let
\p{i1cw}=(i1cw), \p{i2cw}=(i2cw),
\p{i1acw}=(i1acw), \p{i2acw}=(i2acw)
in
\pgfextra{
% acw
\pgfmathsetmacro\angstartacw{atan2(\y{i1acw}-\y1,\x{i1acw}-\x1)+90}
\pgfmathsetmacro\angendacw{atan2(\y{i2acw}-\y2,\x{i2acw}-\x2)-90}
\pgfmathsetmacro\angendacw{\angendacw>\angstartacw?\angendacw-360:\angendacw}
\pgfmathsetmacro\angendacw{\angendacw<\angstartacw-360?\angendacw+360:\angendacw}
% cw
\pgfmathsetmacro\angstartcw{atan2(\y{i1cw}-\y1,\x{i1cw}-\x1)-90}
\pgfmathsetmacro\angendcw{atan2(\y{i2cw}-\y2,\x{i2cw}-\x2)+90}
\pgfmathsetmacro\angendcw{\angendcw<\angstartcw?\angendcw+360:\angendcw}
\pgfmathsetmacro\angendcw{\angendcw>\angstartcw+360?\angendcw-360:\angendcw}
% test
\pgfmathtruncatemacro\difftest{(\angendcw-\angstartcw<\angstartacw-\angendacw)?1:0}
\ifnum\difftest=1 %
% choice: cw
\pgfinterruptpath
\coordinate (i1) at (i1cw);
\coordinate (i2) at (i2cw);
\endpgfinterruptpath
\pgfmathsetmacro\angstart{\angstartcw}
\pgfmathsetmacro\angend{\angendcw}
\else
% choice: acw
\pgfinterruptpath
\coordinate (i1) at (i1acw);
\coordinate (i2) at (i2acw);
\endpgfinterruptpath
\pgfmathsetmacro\angstart{\angstartacw}
\pgfmathsetmacro\angend{\angendacw}
\fi
}
-- (i1) arc[start angle=\angstart,end angle=\angend,radius=\n3] --(\p2)
},
},
}
\makeatother

\begin{document}
\foreach \i in {1,...,36}{
\begin{tikzpicture}
\pgfmathsetmacro\rnda{rnd*360}
\pgfmathsetmacro\rndb{rnd*360}
\pgfmathsetmacro\rndc{rnd*4mm}
% \pgfmathsetmacro\rnda{\i}
% \pgfmathsetmacro\rndb{0}
% \pgfmathsetmacro\rndc{1cm}
\coordinate (a) at (\rnda:2cm);
\coordinate (b) at (\rndb:2cm);
\coordinate (c) at (0,0);

\draw[orange,line width=.8pt] (a) to[cw wrap around={c by \radius pt}] (b);
\draw[lime,line width=.8pt] (a) to[acw wrap around={c by \radius pt}] (b);
\draw[black] (a) to[wrap around={c by \radius pt}] (b);

\path circle(2cm);
\end{tikzpicture}
}
\end{document}

-

Perhaps not as versatile as the other answers, but just another way of doing things. It requires TikZ 3.0.0:

\documentclass[tikz,border=0.125cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{math}
\begin{document}
\tikzset{x=1pt,y=1pt}
\tikzmath{%
coordinate \p,\q,\c;
for \y in {-60,-50,...,70,60,...,-50}{
\p1 = (60,\y);
\p2 = (0,-60);
\c = (10,10);
\r = 20;
for \i in {1,2}{
\l{\i} = veclen(\py{\i}-\cy, \px{\i}-\cx);
\a{\i} = atan2(\py{\i}-\cy, \px{\i}-\cx);
\b{\i} = acos(\r/\l{\i});
};
\s = \a1+\b1;
\t = \a2-\b2;
if \t<\s then {
\t = \t + 360;
};
{
\begin{tikzpicture}
\useasboundingbox (-10,-60) rectangle (60,70);
\draw [red] (\p1) -- ($(\c)+(\s:\r)$) arc (\s:\t:\r) -- (\p2);
\end{tikzpicture}
};
};
}
\end{document}


-

We can do this neatly in Metapost as well. The fullcircle path defined by plain Metapost has 8 (more or less) evenly spaced points around it. Point 0 corresponds to 3 o'clock, point 2 to 12 o'clock, and so on. The direction macro provides you with the tangent vector.

beginfig(1);
path C; C = fullcircle scaled 20;
a = 0.4; b = 2.6;
z0 = point a of C - 20*(unitvector direction a of C);
z1 = point b of C + 20*(unitvector direction b of C);
fill C withcolor .7white;
drawarrow z0 -- subpath (a,b) of C -- z1 withcolor .637 red;
endfig;


Vary a and b in this example to get the angle you desire.

a=0.4 and b=2.6 produces this:

a=0 and b=2 produces this:

a=1 and b=7 this:

and so on.

If you prefer to wrap around an ellipse, try something like C = fullcircle xscaled 20 yscaled 10.

-