6

I want to draw an invisible big circle filled with small visible circles. If more than a half of a small circle fits in the big circle, it should be plotted (even if it is outside the big circle.

If this is impossible it would be okay if the fill pattern won't be cutted at the edge of the border of the big circle leaving open small circles.

The code I have:

\documentclass[tikz, border=1pt]{standalone}
\usepackage[utf8]{inputenc}
\usetikzlibrary{patterns}

\pgfdeclarepatternformonly[/tikz/radius,\thickness,\size]{rings}
{\pgfpoint{-0.5*\size}{-0.5*\size}}
{\pgfpoint{0.5*\size}{0.5*\size}}
{\pgfpoint{\size}{\size}}
{
    \pgfsetlinewidth{\thickness}
    \pgfpathcircle\pgfpointorigin{\pgfkeysvalueof{/tikz/radius}}
    \pgfusepath{stroke}
}
\newdimen\thickness
\tikzset{
    radius/.initial=4pt,
    size/.store in=\size, size=20pt,
    thickness/.code={\thickness=#1},
    thickness=0.75pt
}

\begin{document}
\begin{tikzpicture}

\path[clip] (0,0) circle (3cm);
\path[pattern=rings, radius=2pt, size=9pt] (-3,-3) rectangle (3,3);

\end{tikzpicture}
\end{document}

What I get: What I get

What I want: What I want

5

This requires further tweaking and is probably not the most elegant way of doing this.

I used a conditionnal plotting to obtain (almost) what you want.

\documentclass[tikz, border=1pt]{standalone}
\usepackage[utf8]{inputenc}

\begin{document}
\begin{tikzpicture}

\foreach \k in {-10,-9,...,10}{
 \foreach \j in {-10,-9,...,10}{
        \pgfmathparse{ifthenelse(sqrt(pow(\k,2)+pow(\j,2))<10,1,0}%\pgfmathresult
    \draw[red,circle, radius=2pt] (\pgfmathresult*\k*4pt,\pgfmathresult*\j*4pt) circle (2pt);

    }
}

\end{tikzpicture}
\end{document}

enter image description here

Version 2 Thanks for the conditional statement @MaxSnippe, that's what I wanted to do. This gets quite close to the OPs question.

I defined 3 parameters: \radius: the radius of a small circle in pt, \lwidth: the line width of a small circle in pt, and \clipradius: the radius of the big circle for clipping in pt.

You can easily change the constraint if you want another clipping shape.

\documentclass[tikz, border=1pt]{standalone}
\usepackage[utf8]{inputenc}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}
% Lengths in pt
\pgfmathsetmacro{\radius}{4}
\pgfmathsetmacro{\lwidth}{1}
\pgfmathsetmacro{\clipradius}{10-0.5}

\foreach \k in {-10,-9,...,10}{
    \foreach \j in {-10,-9,...,10}{
        \pgfmathparse{ifthenelse(sqrt(pow(\k,2)+pow(\j,2))<\clipradius,1,0}
        \ifnum\pgfmathresult=1
            \draw[red,line width=\lwidth] (\k*2*\radius+\k*\lwidth pt,\j*2*\radius+\j*\lwidth pt) circle (\radius pt);
        \fi
    }
}

\end{tikzpicture}
\end{document}

enter image description here

Version 3 I added the surrounding circle and modified the test expression to match with it. Note that as requested, some the small circles are clipped only if their center is outside of the big circle

\documentclass[tikz, border=1pt]{standalone}
\usepackage[utf8]{inputenc}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro{\radius}{4}
\pgfmathsetmacro{\lwidth}{1}
\pgfmathsetmacro{\clipradius}{80}

\foreach \k in {-10,-9,...,10}{
    \foreach \j in {-10,-9,...,10}{

        \pgfmathparse{ifthenelse(sqrt(pow(\k*2*\radius+\k*\lwidth,2)+pow(\j*2*\radius+\j*\lwidth,2))<\clipradius,1,0}%\pgfmathresult
        \ifnum\pgfmathresult=1
            \draw[red,line width=\lwidth] (\k*2*\radius+\k*\lwidth pt,\j*2*\radius+\j*\lwidth pt) circle (\radius pt);
        \fi
    }
}
 \draw[blue,line width=\lwidth] (0,0) circle (\clipradius pt);

\end{tikzpicture}
\end{document}

enter image description here

  • 2
    This is already very good, but now every time \pgfmathresult is 0, the circle is drawn at (0,0). You could solve this for example by using opacity=\pgfmathresult or enclosing it in \ifnum\pgfmathresult=1 <drawing of the small circle> \fi. This way you can remove the \pgfmathresults from the coordinate specification. – Max Jul 19 '18 at 18:08
  • Note that veclen(\k,\j) will be a bit more efficient than sqrt(pow(\k,2)+pow(\j,2)) with mostly tolerable accuracy. – Mark Wibrow Jul 20 '18 at 8:09
  • @MarkWibrow, you are totally right, I just preferred a pure math expression for the OP to understand the behaviour, of the script – BambOo Jul 20 '18 at 8:33
4

Here's a simple way to do that with Metapost.

\documentclass[border=5mm]{standalone}
\usepackage{luatex85}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
beginfig(1);
  r = 10; R = 400;
  draw fullcircle scaled 2R withcolor red;
  for x=-R step 2r until R:
    for y=-R step 2r until R:
      if x++y <= R-r: 
        draw fullcircle scaled 2r shifted (x, y);
      fi
    endfor
  endfor
endfig;
\end{mplibcode}
\end{document}

This is wrapped up in luamplib so run it with lualatex (or adapt it for plain MP...).

Here's the output. Adjust big R and little r to suit. The red circle is only drawn to show we are not stepping outside the limit.

enter image description here

The expression x++y returns the Pythagorean sum of x and y. This gives us the distance from (x,y) to the origin. We draw a circle when this distance is less than the big radius minus the little radius.

Or you can (as the OP asked) draw the circles if more than half of them fit, by changing the if condition to x++y<R:

if x++y < R: 
   draw fullcircle scaled 2r shifted (x, y);
fi

to produce this:

enter image description here

You can of course get rid of the red circle when you are happy with the result...

  • I see two possible improvements here, change x++y <= R-r: by x++y <= R-r: to fit the OP's question * it should be plotted (even if it is outside the big circle)* and also, in the question, the small circles a tangent to one another, not overlapping. Hope this helps – BambOo Jul 21 '18 at 8:46
  • @BambOo thanks for that, I'd missed the precise specification in the OP. But I think you meant to write x++y<R in the second part of your suggestion. – Thruston Jul 21 '18 at 15:51
  • Yes, a small glitch in the matrix – BambOo Jul 22 '18 at 6:24

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.