Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have the following figure

enter image description here

I would like to draw portions of circles between some of the red points. More explicitly, I would like to go from ac1 to ab1 and then to ac2 following circle A, then go to bc1 following circle C and to ab2 following circle B and back to ac1 following circle A.

There is probably a solution using the arc operation, but this would require computing the angles for every portion of circle, which can get tedious. Is there a simple way to do that ?

(I was thinking maybe drawing circles with \clip, but I can't figure out how to do it)

Here is my example code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,intersections}

\begin{document}

\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (-1,-1);
\coordinate (c) at (1,-1);

\draw[name path=circleA] (a) circle (1.5cm);
\draw[name path=circleB] (b) circle (1.5cm);
\draw[name path=circleC] (c) circle (1.5cm);

\fill [red, name intersections={of=circleA and circleB,name=intAB}]
(intAB-1) circle (2pt) node[above left] {ab1}
(intAB-2) circle (2pt) node[below right] {ab2};
\fill [red, name intersections={of=circleA and circleC,name=intAC}]
(intAC-1) circle (2pt) node[above right] {ac1}
(intAC-2) circle (2pt) node[below left] {ac2};
\begin{scope}
\clip (a) circle (1.5cm);
\fill [red, name intersections={of=circleB and circleC,name=intBC}]
(intBC-1) circle (2pt) node[below] {bc1}
(intBC-2) circle (2pt) node {bc2};
\end{scope}

\node (A) at ($(a)+(0,1)$) {$A$};
\node (B) at ($(b)+(-1,0)$) {$B$};
\node (C) at ($(c)+(1,0)$) {$C$};
\end{tikzpicture}

\end{document}
share|improve this question
    
Clips are certainly an easy way to do this, how "clean" do you want the joins to be? –  Andrew Stacey Sep 14 '12 at 15:16
    
In the final document I may not draw the intersection points, so it would be nice if the joints were clean enough so that the line appears continuous. –  Corentin Sep 14 '12 at 15:34
    
In which case clipping is not the best option. That's useful to know. –  Andrew Stacey Sep 14 '12 at 15:42
    
@AndrewStacey With \pgfpatharcto the joints are perfectly clean, so from a practical point of view I am happy with this solution. However, if you have another method with clips, even if joints do not match so well, I would be glad to have a look at the difference and learn something new.. –  Corentin Sep 14 '12 at 21:21
    
Always worth learning! If no-one else beats me to it (and, everyone else, please do!) then I'll add a clip solution next time I'm on a "proper" computer. –  Andrew Stacey Sep 14 '12 at 22:43
add comment

3 Answers

up vote 15 down vote accepted

enter image description here

Here's a solution that uses the nodes that you have defined and the commands

\pgfpointanchor{<node>}{<anchor>}
\pgfpathmoveto{<coordinate>}
\pgfpatharcto{<x-radius>}{<y-radius>}{<rotation>}{<large arc flag>}{<counterclockwise flag>}{<target point>}

The idea is to use \pgfpointanchor to get the coordinates of one the points of intersection. You then use pgfpathmoveto to move there, and then use \pgfpatharcto to draw an arc to the other point of intersection (which you find the coordinates of using \pgfpointanchor again). All of these commands are detailed in the pgf manual.

The new piece I have added to your code is:

% new bit
\pgfsetlinewidth{2pt}
% path between ac1 and ab1
\pgfsetstrokecolor{blue}
\pgfpathmoveto{\pgfpointanchor{intAC-1}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{1}{\pgfpointanchor{intAB-1}{south}}
\pgfusepath{stroke}
% path between ab1 and ac2
\pgfsetstrokecolor{red}
\pgfpathmoveto{\pgfpointanchor{intAB-1}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{1}{\pgfpointanchor{intAC-2}{south}}
\pgfusepath{stroke}
% path between ac2 and bc1
\pgfsetstrokecolor{green}
\pgfpathmoveto{\pgfpointanchor{intAC-2}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{0}{\pgfpointanchor{intBC-1}{south}}
\pgfusepath{stroke}
% path between bc1 and ab2
\pgfsetstrokecolor{yellow}
\pgfpathmoveto{\pgfpointanchor{intBC-1}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{0}{\pgfpointanchor{intAB-2}{south}}
\pgfusepath{stroke}
% path between ab2 and ac1
\pgfsetstrokecolor{orange}
\pgfpathmoveto{\pgfpointanchor{intAB-2}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{1}{\pgfpointanchor{intAC-1}{south}}
\pgfusepath{stroke}

Note that some of the paths are traversed clockwise, and some counter clockwise, determined by the 5th argument to \pgfpatharcto

Here's the complete MWE

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,intersections}

\begin{document}

\begin{tikzpicture}
\coordinate (a) at (0,0);
\coordinate (b) at (-1,-1);
\coordinate (c) at (1,-1);

\draw[name path=circleA] (a) circle (1.5cm);
\draw[name path=circleB] (b) circle (1.5cm);
\draw[name path=circleC] (c) circle (1.5cm);

\fill [red, name intersections={of=circleA and circleB,name=intAB}]
(intAB-1) circle (2pt) node[above left] {ab1}
(intAB-2) circle (2pt) node[below right] {ab2};
\fill [red, name intersections={of=circleA and circleC,name=intAC}]
(intAC-1) circle (2pt) node[above right] {ac1}
(intAC-2) circle (2pt) node[below left] {ac2};
\begin{scope}
\clip (a) circle (1.5cm);
\fill [red, name intersections={of=circleB and circleC,name=intBC}]
(intBC-1) circle (2pt) node[below] {bc1}
(intBC-2) circle (2pt) node {bc2};
\end{scope}
% new bit
\pgfsetlinewidth{2pt}
% path between ac1 and ab1
\pgfsetstrokecolor{blue}
\pgfpathmoveto{\pgfpointanchor{intAC-1}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{1}{\pgfpointanchor{intAB-1}{south}}
\pgfusepath{stroke}
% path between ab1 and ac2
\pgfsetstrokecolor{red}
\pgfpathmoveto{\pgfpointanchor{intAB-1}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{1}{\pgfpointanchor{intAC-2}{south}}
\pgfusepath{stroke}
% path between ac2 and bc1
\pgfsetstrokecolor{green}
\pgfpathmoveto{\pgfpointanchor{intAC-2}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{0}{\pgfpointanchor{intBC-1}{south}}
\pgfusepath{stroke}
% path between bc1 and ab2
\pgfsetstrokecolor{yellow}
\pgfpathmoveto{\pgfpointanchor{intBC-1}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{0}{\pgfpointanchor{intAB-2}{south}}
\pgfusepath{stroke}
% path between ab2 and ac1
\pgfsetstrokecolor{orange}
\pgfpathmoveto{\pgfpointanchor{intAB-2}{south}}
\pgfpatharcto{1.5cm}{1.5cm}{0}{0}{1}{\pgfpointanchor{intAC-1}{south}}
\pgfusepath{stroke}

\node (A) at ($(a)+(0,1)$) {$A$};
\node (B) at ($(b)+(-1,0)$) {$B$};
\node (C) at ($(c)+(1,0)$) {$C$};
\end{tikzpicture}

\end{document}
share|improve this answer
    
Thanks a lot for your answer, this is what I was looking for. I wasn't aware of the command \pgfpatharcto, which is very useful indeed. –  Corentin Sep 14 '12 at 21:13
add comment

Even though cmhughes has already shown us his version with \pgfpatharcto I want to add a version that TikZ-ifies the \pgfpatharcto command under the new path operator arc to.

The code has been originally developed for another question on TeXwelt.de (German). The only difference is that it uses arc to instead of arc*.

With this operator, the required arc can be drawn (and filled) with

\draw (intAC-1) arc to [arc large] (intAC-2)
                arc to [arc cw]    (intBC-1)
                arc to [arc cw]    (intAB-2)
                arc to []          (intAC-1) -- cycle;

The options

  • arc large and arc small (<large arc flag>) as well as
  • arc cw and arc ccw (<counterclockwise flag>)

correspond to the flags of \pgfpatharcto (argument #4 and #5).

The third argument is used for rotation and can be set with arc rotation (initially 0).

As the precision of \pgfpatharcto is rather bad, the joined close (-- cycle) doesn’t look so good with the default miter line join (but only at 6400 % zoom), I’d use line join=round where this imperfection disappears.

The path operator arc to misses a proper timer (the function that places nodes “along” the path), as a substitute it uses the timer of a straight line (--). The [ ] are mandatory (as can be seen at the fourth occurrence of arc to).

Code

\documentclass[tikz,convert=false]{standalone}
\tikzset{
  arc/ccw/.initial=1,
  arc/large/.initial=0,
  arc ccw/.style={/tikz/arc/ccw=1},
  arc cw/.style={/tikz/arc/ccw=0},
  arc large/.style={/tikz/arc/large=1},
  arc small/.style={/tikz/arc/large=0},
  arc rotation/.initial=0
}
\usetikzlibrary{intersections}
\makeatletter
\def\tikz@arcA rc{\pgfutil@ifnextchar t%
  {\tikz@flush@moveto\tikz@arcB@opt}%  -> our new "arc to"
  {\tikz@flush@moveto\tikz@arc@cont}}% -> our old "arc"
\def\tikz@arcB@opt to#1[#2]{%
  \def\tikz@arcB@options{#2}
  \tikz@do@@arcB}
\def\tikz@do@@arcB{%
  \pgfutil@ifnextchar n{\tikz@collect@label@onpath\tikz@do@@arcB}
    {\pgfutil@ifnextchar c{\tikz@collect@coordinate@onpath\tikz@do@@arcB}
      {\tikz@scan@one@point\tikz@do@arcB}}}
\def\tikz@do@arcB#1{%
  \edef\tikz@timer@start{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}
  \tikz@make@last@position{#1}%
  \edef\tikz@timer@end{\noexpand\pgfqpoint{\the\tikz@lastx}{\the\tikz@lasty}}%
  \iftikz@shapeborder
    \edef\tikz@moveto@waiting{\tikz@shapeborder@name}%
  \fi
  \begingroup
    \tikzset{every arc/.try}%
    \expandafter\tikzset\expandafter{\tikz@arcB@options}%
    \pgfmathparse{\pgfkeysvalueof{/tikz/x radius}}%
    \let\tikz@arc@x\pgfmathresult
    \ifpgfmathunitsdeclared
      \edef\tikz@arc@x{\tikz@arc@x pt}%
    \else
      \pgf@process{\pgfpointxy{\tikz@arc@x}{0}}%
      \pgfmathveclen@{\pgf@x}{\pgf@y}%
      \edef\tikz@arc@x{\pgfmathresult pt}%
    \fi
    \pgfmathparse{\pgfkeysvalueof{/tikz/y radius}}%
    \let\tikz@arc@y\pgfmathresult
    \ifpgfmathunitsdeclared
      \edef\tikz@arc@y{\tikz@arc@y pt}%
    \else
      \pgf@process{\pgfpointxy{0}{\tikz@arc@y}}%
      \pgfmathveclen@{\pgf@x}{\pgf@y}%
      \edef\tikz@arc@y{\pgfmathresult pt}%
    \fi
    \pgfpatharcto{\tikz@arc@x}{\tikz@arc@y}
                 {\pgfkeysvalueof{/tikz/arc rotation}}{\pgfkeysvalueof{/tikz/arc/large}}
                 {\pgfkeysvalueof{/tikz/arc/ccw}}{#1}%
  \endgroup
  \let\tikz@timer=\tikz@timer@line
  \tikz@scan@next@command
}
\makeatother
\begin{document}
\begin{tikzpicture}[radius=1.5]
\draw[name path=circleA] ( 0, 0) coordinate (a) circle [];
\draw[name path=circleB] (-1,-1) coordinate (b) circle [];
\draw[name path=circleC] ( 1,-1) coordinate (c) circle [];

\fill [red, name intersections={of=circleA and circleB,name=intAB}]
     (intAB-1) circle (2pt) node[above left]  {ab1}
     (intAB-2) circle (2pt) node[below right] {ab2};
\fill [red, name intersections={of=circleA and circleC,name=intAC}]
     (intAC-1) circle (2pt) node[above right] {ac1}
     (intAC-2) circle (2pt) node[below left]  {ac2};
\fill [red, name intersections={of=circleB and circleC,name=intBC}]
     (intBC-1) circle (2pt) node[above]       {bc1};


\node (A) at ([shift={((0,1)} ]a) {$A$};
\node (B) at ([shift={((-1,0)}]b) {$B$};
\node (C) at ([shift={((1,0)} ]c) {$C$};

\draw[
  thick,
  line join=round,
  draw=blue,
  fill opacity=.5,
  fill=blue!50
] (intAC-1) arc to [arc large] (intAC-2)
            arc to [arc cw]    (intBC-1)
            arc to [arc cw]    (intAB-2)
            arc to []          (intAC-1) -- cycle;
\end{tikzpicture}
\end{document}

Output

enter image description here

share|improve this answer
add comment

Edit: a new version with better jonctions...

This is not the first question that asks how to draw an arc between two points on a circle with known center. So I decided to create two new styles to meet this need. Here is an example of use:

\draw (a) to[clockwise arc centered at=c] (b);

This command draws an arc starting at a, ending at b, and centered at c (in fact, ending is on a line through c and b if b is not on the circle centered at c and that goes through a).

There are two styles: clockwise arc centered at and anticlockwise arc centered at.

(Due to rounding errors, always use line join=round to get better connections between some arcs.)

Here's your answer (I slightly modified the code of your MWE) using both styles:

enter image description here

\documentclass[margin=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,intersections}

\tikzset{
  anticlockwise arc centered at/.style={
    to path={
      let \p1=(\tikztostart), \p2=(\tikztotarget), \p3=(#1) in
      \pgfextra{
        \pgfmathsetmacro{\anglestart}{atan2(\x1-\x3,\y1-\y3)}
        \pgfmathsetmacro{\angletarget}{atan2(\x2-\x3,\y2-\y3)}
        \pgfmathsetmacro{\angletarget}%
        {\angletarget < \anglestart ? \angletarget+360 : \angletarget}
        \pgfmathsetmacro{\radius}{veclen(\x1-\x3,\y1-\y3)}
      }
      arc(\anglestart:\angletarget:\radius pt) -- (\tikztotarget)
    },
  },
  clockwise arc centered at/.style={
    to path={
      let \p1=(\tikztostart), \p2=(\tikztotarget), \p3=(#1) in
      \pgfextra{
        \pgfmathsetmacro{\anglestart}{atan2(\x1-\x3,\y1-\y3)}
        \pgfmathsetmacro{\angletarget}{atan2(\x2-\x3,\y2-\y3)}
        \pgfmathsetmacro{\angletarget}%
        {\angletarget > \anglestart ? \angletarget - 360 : \angletarget}
        \pgfmathsetmacro{\radius}{veclen(\x1-\x3,\y1-\y3)}
      }
      arc(\anglestart:\angletarget:\radius pt)  -- (\tikztotarget)
    },
  },
}

\begin{document}
\begin{tikzpicture}
  % 3 centers (a, b, c)
  \coordinate (a) at (0,0);
  \coordinate (b) at (-1,-1);
  \coordinate (c) at (1,-1);

  % 3 circles
  \draw[name path=circleA] (a) circle (1.5cm);
  \draw[name path=circleB] (b) circle (1.5cm);
  \draw[name path=circleC] (c) circle (1.5cm);

  % label of circles
  \node (A) at ($(a)+(0,1)$) {$A$};
  \node (B) at ($(b)+(-1,0)$) {$B$};
  \node (C) at ($(c)+(1,0)$) {$C$};

  % intersections of circles (A) and (B)
  \path [name intersections={of=circleA and circleB,name=AB}];
  % show them
  \fill[red] (AB-1) circle (2pt) node[above left] {AB-1};
  \fill[red] (AB-2) circle (2pt) node[below right] {AB-2};

  % intersections of circles (A) and (C)
  \path [name intersections={of=circleA and circleC,name=AC}];
  % show them
  \fill[red] (AC-1) circle (2pt) node[above right] {AC-1};
  \fill[red] (AC-2) circle (2pt) node[below left] {AC-2};

  % intersections of circles (B) and (C)
  \path[name intersections={of=circleB and circleC,name=BC}];
  % show them
  \fill[red] (BC-1) circle (2pt) node[above] {BC-1};
  \fill[red] (BC-2) circle (2pt) node[below] {BC-2};


  \draw[line join=round,orange,fill=orange,fill opacity=.5,line width=1pt]
  (AC-2)
  to[clockwise arc centered at=a] (AB-2)
  to[anticlockwise arc centered at=b] (BC-1)
  to[anticlockwise arc centered at=c] (AC-2);

\end{tikzpicture}
\end{document}
share|improve this answer
    
I like this, nice work :) –  cmhughes Sep 14 '12 at 21:59
    
Very elegant, thank you very much ! –  Corentin Sep 14 '12 at 22:04
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.