24

Suppose I have some code that draws a few circles. These circles overlap each other in such a way that they form one "group" -- there are no groups of circles completely separated from the rest. For instance:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\draw (3,1) circle[radius=1];
\draw (3,2) circle[radius=1.5];
\draw (1,2) circle[radius=0.7];
\draw (0.9,1.2) circle[radius=1.2];
\draw (1,0) circle[radius=0.8];
\end{tikzpicture}
\end{document}

circles

I would like to be able to draw only the "border" formed by these circles, without any of the other lines. It would be like drawing the border of the silhouette formed by all the circles. It would look something like this:

border

Now for that one, I just painted over the lines in Paint.NET with a brush - if you look closely you can see the imperfections. I would prefer to be able to do it in LaTeX directly. I understand that one option would be to manually calculate the position of the arcs and draw them in. However, it would be nice if there was a way for LaTeX to do the calculations for me and draw the border of the circles, without me having to solve a large amount of intersection equations. Is this possible?

25

I don't know tikz from a Polynesian mythological icon, so I am sure someone can do better.

I first draw the OP's original figure of black circles, and then redraw the same items as white filled circles of slightly smaller radius.

\documentclass{article}
\usepackage{tikz}
\newcommand\eps{.02}
\begin{document}
\begin{tikzpicture}
\draw (3,1) circle[radius=1];
\draw (3,2) circle[radius=1.5];
\draw (1,2) circle[radius=0.7];
\draw (0.9,1.2) circle[radius=1.2];
\draw (1,0) circle[radius=0.8];
\color{white}
\draw[fill=white] (3,1) circle[radius=1-\eps];
\draw[fill=white] (3,2) circle[radius=1.5-\eps];
\draw[fill=white] (1,2) circle[radius=0.7-\eps];
\draw[fill=white] (0.9,1.2) circle[radius=1.2-\eps];
\draw[fill=white] (1,0) circle[radius=0.8-\eps];
\end{tikzpicture}
\end{document}

enter image description here

I'll add that Ignasi provides good advice in the comments, to use

circle[radius=1cm-.5\pgflinewidth]

rather than my empirically derived value of \eps. In that way, the result will look good, regardless of any variations in preset line thickness.

  • 4
    I was going to post a similar solution but with circle[radius=1cm-.5\pgflinewidth]. Adding cm is necesary because \pgflinewidth already has units. – Ignasi Sep 10 '14 at 12:32
  • 2
    +1 for the Polynesian mythological icon (and that this works nicely for my purposes). – absinthe Sep 10 '14 at 12:33
  • @Ignasi Thanks for that tip to readers. As I said, I couldn't tell you what the tikz line width is in terms of such variables. – Steven B. Segletes Sep 10 '14 at 12:34
  • ​​​​​​​​​​​​​​​@Ignasi What would be the difference between using \eps as in this example verses .5\pgflinewidth? I'm not sure how they differ. – absinthe Sep 10 '14 at 12:35
  • @VonIlya My \eps was empirically derived through trial and error. By using the actual line width variable, Ignasi will get the right value regardless of how your line width is set prior to invocation. To see, this, make \eps larger in my solution, say 0.1, and see the result. – Steven B. Segletes Sep 10 '14 at 12:37
26

Pretty much exactly the same approach as Steven B. Segletes but more (possibly overly) concise. The thickness of the outline is half the value specified in the line width:

\documentclass[tikz,border=5]{standalone}
\begin{document}
\tikz\path [draw, line width=5pt, postaction={fill=white}]
   \foreach \p/\r in {(3,1)/1, (3,2)/1.5, (1,2)/.7, (.9,1.2)/1.2, (1,0)/.8}{
      \p circle [radius=\r]};
\end{document}

enter image description here

And here is a outline fading decoration which makes the inside of the resulting shape transparent. It is mostly proof-of-concept, and as it uses fadings may not work with some viewers. Also it exploits the nonzero rule for filling so its successful use is dependent on the direction of the paths being drawn. The line width is set using the amplitude key.

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{fadings,decorations,fit}
\pgfdeclaredecoration{outline fading}{final}{
\state{final}{%
  \pgftransformreset%
  \pgfnodealias{@}{current path bounding box}%
  \node [fit=(@), inner sep=\pgfdecorationsegmentamplitude] (@@) {};
  \let\outlinepath=\pgfdecoratedpath
  \pgfinterruptpicture%
    \begin{tikzfadingfrompicture}[name=.]
      \path [line width=\pgfdecorationsegmentamplitude*2, draw=transparent!0,
       postaction={fill=transparent, nonzero rule}] 
       \pgfextra{\pgfsetpath\outlinepath};
      \useasboundingbox (@@.south west) (@@.north east);
    \end{tikzfadingfrompicture}%
  \endpgfinterruptpicture%
  \fill [path fading=.,fit fading=false,fading transform={shift={(@@)}}] 
   (@@.south west) rectangle (@@.north east); 
}}
\begin{document}
\begin{tikzpicture}
 \draw [help lines] (-1,-1) grid (5,5);
  \path [decoration={outline fading, amplitude=2pt}, decorate]
    \foreach \p/\r in {(3,1)/1, (3,2)/1.5, (1,2)/.7, (.9,1.2)/1.2, (1,0)/.8}{
        \p circle [radius=\r]};
\end{tikzpicture}
\end{document}

enter image description here

  • 4
    (+1) for succinctness and I didn't realise that you could use postaction this way. Very useful! – cfr Sep 10 '14 at 13:52
  • Very impressive. If I could +1 again, I would ;). – cfr Sep 11 '14 at 14:47
19

Here's a solution using the magic of the shadows library:

\documentclass[tikz, border=10pt]{standalone}
\usetikzlibrary{shadows}    
\begin{document}
  \begin{tikzpicture}[
        general shadow/.default={shadow scale=1, draw=black, line width=1pt, fill=none, shadow xshift=0pt, shadow yshift=0pt},
        my shadow/.append style={fill=white, general shadow},
      ]
    \path [my shadow]
      (3,1) circle [radius=1]
      (3,2) circle [radius=1.5]
      (1,2) circle [radius=0.7]
      (0.9,1.2) circle [radius=1.2]
      (1,0) circle [radius=0.8];
  \end{tikzpicture}
\end{document}

magic shadow

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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