4

I'm trying to make the image below. I want to fill in the grid points intersected by the circles. I'm able to make the grid and the arrows, the code for that is below. I'm completely lost on how to fill in the corresponding squares, is this possible?

enter image description here

\documentclass [10pt] {article}
\usepackage{tikz}
\usetikzlibrary{calc,patterns,through,intersections}

\begin{document}
\begin{tikzpicture}
    [detector_center/.style={circle, draw=black!50, fill=black!20, scale=0.2}, 
    square/.style={regular polygon,regular polygon sides=4}]
    % build main shape
    \draw (-3,-3) grid (3,3);
    \draw
        (0, 0) node[detector_center] (det_center) {}
        (0.5, -1.5) node (q_1) {}
        (-1.5, 2.2) node (q_2) {}
        (-2.5, -2.5) node (pixel_origin) {}
        (-2.5, -1.5) node (fs) {}
        (-1.5, -2.5) node (ss) {};

    % draw arrows and circles
    \node [draw, circle through=(q_1), name path=q1_circle] at (det_center) {};
    \node [draw, circle through=(q_2), name path=q2_circle] at (det_center) {};

    \draw [-stealth, thick] (det_center.center) -- (q_1.center);
    \draw [-stealth, thick] (det_center.center) -- (q_2.center);
    \draw [-stealth, blue, thick] (pixel_origin.center) -- (ss.center);
    \draw [-stealth, red, thick] (pixel_origin.center) -- (fs.center);

\end{tikzpicture}
\end{document}

Please let me know if I need to elaborate. Thanks!

P.S., I colored in the squares quickly with a photo editor, I'd like the full square to be filled.

EDIT: I should mention that I would like this to be automated. I do not want a fill statement for each individual grid cell, rather a method to automate filling each grid cell intersected by the circles.

6
  • 1
    Welcome to TSE. Please post a Minimal Working Example, instead of a code snippet. Dec 11, 2021 at 19:18
  • @JoséCarlosSantos, this is a fairly specific question and it is as minimal as I can make it without loss of information.
    – Knova
    Dec 11, 2021 at 19:24
  • 1
    All I am asking is that you turn your code into something that can be compiled. Only a few lines are missing. Dec 11, 2021 at 19:25
  • @JoséCarlosSantos, sorry for the misunderstanding. I've updated the code.
    – Knova
    Dec 11, 2021 at 19:30
  • 1
    I take it that you don't wish to fill the grid manually but rather do this in an automated way? Dec 11, 2021 at 19:43

2 Answers 2

3

Welcome to TeX.SE!!

This is an option using the ifthen package. For doing this we need to convert the numbers (radii) to integers but for precision I'm multiplying them by 100 (thus I preserve two decimal positions).

This way we only need to compare the radii of the circles with the squares corners distance to the origin.

The code:

\documentclass[tikz,border=2mm]{standalone}
\usepackage{ifthen}

\usetikzlibrary{calc,patterns,through,intersections}
\usetikzlibrary{shapes.geometric}

\tikzset
{
  my fill/.style={fill=#1,fill opacity=0.2},
}

\begin{document}
\begin{tikzpicture}
   [detector_center/.style={circle, draw=black!50, fill=black!20, scale=0.2}, 
    square/.style={regular polygon,regular polygon sides=4}]
  \def\n{3} % grid width
  % build main shape
  \draw (-\n,-\n) grid (\n,\n);
  \draw
        (0, 0) node[detector_center] (det_center) {}
        (0.5, -1.5) node (q_1) {}
        (-1.5, 2.2) node (q_2) {}
        (-2.5, -2.5) node (pixel_origin) {}
        (-2.5, -1.5) node (fs) {}
        (-1.5, -2.5) node (ss) {};

  % draw arrows and circles
  \node [draw, circle through=(q_1), name path=q1_circle] at (det_center) {};
  \node [draw, circle through=(q_2), name path=q2_circle] at (det_center) {};
  \draw [-stealth, thick] (det_center.center) -- (q_1.center);
  \draw [-stealth, thick] (det_center.center) -- (q_2.center);
  \draw [-stealth, blue, thick] (pixel_origin.center) -- (ss.center);
  \draw [-stealth, red,  thick] (pixel_origin.center) -- (fs.center);

  \pgfmathtruncatemacro\outr{100*sqrt(1.5*1.5+2.2*2.2)}           % outer circle radius
  \pgfmathtruncatemacro\innr{100*sqrt(0.5*0.5+1.5*1.5)}           % inner circle radius  
  \foreach\i in{1,...,\n} \foreach\j in {1,...,\n}
  {
    \pgfmathtruncatemacro\minr{100*sqrt(\i*\i+\j*\j-2*\i-2*\j+2)} % minimum radius
    \pgfmathtruncatemacro\maxr{100*sqrt(\i*\i+\j*\j)}             % maximum radius
    \ifthenelse{\minr<\outr \AND \maxr>\outr}
    {%
      \foreach\a in {-1,1} \foreach\b in {-1,1}
      \fill[my fill=cyan] (\i*\a,\j*\b) rectangle ++ (-\a,-\b);
     }{}
    \ifthenelse{\minr<\innr \AND \maxr>\innr}
    {%
      \foreach\a in {-1,1} \foreach\b in {-1,1}
      \fill[my fill=orange] (\i*\a,\j*\b) rectangle ++ (-\a,-\b);
     }{}
    }
\end{tikzpicture}
\end{document}

And the ouptut: enter image description here

4
  • Brilliant! This worked great. Is there a way to call the macro as a function whose parameters are the circle radius and the number of grid points? i.e., I changed my grid to a \draw (-4,-4) grid (4,4);, meaning the loop goes over {0,1,2,3}.
    – Knova
    Dec 11, 2021 at 20:11
  • @kkarpos, yes with some minor changes. See my edit. Dec 11, 2021 at 20:22
  • hmmm... that doesn't seem to run for me. I'm getting an undefined control sequence error. Is there a ; missing?
    – Knova
    Dec 11, 2021 at 20:30
  • Sorry ignore that, I missed the \n function definition in the beginning.
    – Knova
    Dec 11, 2021 at 20:34
4

This approach uses the intersections library. It takes probably a bit longer to compile than the other solution:

\documentclass[border=1mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc, patterns, through, intersections}

\begin{document}
\begin{tikzpicture}
    [detector_center/.style={circle, draw=black!50, fill=black!20, scale=0.2}, 
    square/.style={regular polygon, regular polygon sides=4}]
    
    % build main shape
    \draw (-3,-3) grid (3,3);
    \draw
        (0, 0) node[detector_center] (det_center) {}
        (0.5, -1.5) node (q_1) {}
        (-1.5, 2.2) node (q_2) {}
        (-2.5, -2.5) node (pixel_origin) {}
        (-2.5, -1.5) node (fs) {}
        (-1.5, -2.5) node (ss) {};

    % draw arrows and circles
    \node[draw, circle through=(q_1), name path=q1_circle] at (det_center) {};
    \node[draw, circle through=(q_2), name path=q2_circle] at (det_center) {};

    \draw[-stealth, thick] (det_center.center) -- (q_1.center);
    \draw[-stealth, thick] (det_center.center) -- (q_2.center);
    \draw[-stealth, blue, thick] (pixel_origin.center) -- (ss.center);
    \draw[-stealth, red, thick] (pixel_origin.center) -- (fs.center);
    
    % for every section of the grid (except the last) ...
    \foreach \y in {-3,...,2} {
        \foreach \x in {-3,...,2} {
    % ... create a path describing a square,
            \path[name path=s-\x-\y] (\y,\x) rectangle ({\y+1},{\x+1});
    % count the intersections of this path with the circle
            \path[name intersections={of=q1_circle and s-\x-\y, total=\t}]
    % and store the number of intersections in a macro that can be accessed globally;
                \pgfextra{\xdef\interseccount{\t}};
    % check whether the number of intersections stored in this macro is larger than zero
            \ifnum\interseccount>0\relax
    % and finally draw the square if yes.
                \fill[orange, opacity=.25] (\y,\x) rectangle ({\y+1},{\x+1});
            \fi
        }    
    }
    
    % do the same for the other circle
    \foreach \y in {-3,...,2} {
        \foreach \x in {-3,...,2} {
            \path[name path=s-\x-\y] (\y,\x) rectangle ({\y+1},{\x+1});
            \path[name intersections={of=q2_circle and s-\x-\y, total=\t}]
                \pgfextra{\xdef\interseccount{\t}};
            \ifnum\interseccount>0\relax
                \fill[cyan, opacity=.25] (\y,\x) rectangle ({\y+1},{\x+1});
            \fi
        }    
    }

\end{tikzpicture}
\end{document}

enter image description here

What does it do? For every sector of the grid it creates a path that describes the grid sector (a square). It then counts the number of intersections of the circle with this path and stores this number in a macro. Then, if this number is larger than zero, it draws a filled square.

For larger grids, you would need to adjust the numbers in the four \foreach macros. For example for (-4,-4) grid (4,4) it would be {-4,...,3} and for (-10,-10) grid (10,10) it would be {-10,...,9}.


Funny side node

As @Juan Castaño pointed out, the above code also works with more complicated curves:

\documentclass[border=1mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc, intersections, hobby}

\begin{document}
\begin{tikzpicture}
    
    \draw (-3,-3) grid (3,3);
    \path[draw, name path=strange curve, use Hobby shortcut, closed=true] (-1.6,1.6) .. (2.5,1.5) .. (0.6,-0.6) .. (-1.5,-2.5);
    
    \foreach \y in {-3,...,2} {
        \foreach \x in {-3,...,2} {
            \path[name path=s-\x-\y] (\y,\x) rectangle ({\y+1},{\x+1});
            \path[name intersections={of=strange curve and s-\x-\y, total=\t}]
                \pgfextra{\xdef\interseccount{\t}};
            \ifnum\interseccount>0\relax
                \fill[red, opacity=.25] (\y,\x) rectangle ({\y+1},{\x+1});
            \fi
        }    
    }

\end{tikzpicture}
\end{document}

enter image description here

6
  • Thanks, Jasper! I marked the other answer as accepted because it led me to learning about macros.
    – Knova
    Dec 11, 2021 at 20:16
  • 1
    This answer led me to learn more about the intersections library! So, it is fine for me =) You may upvote both answers if they are helpful for you. Dec 11, 2021 at 20:17
  • 1
    I would, but I need 2 more reputation points to upvote... lol
    – Knova
    Dec 11, 2021 at 20:19
  • 1
    Very good approach (+1), I like the idea of counting the intersections!! Dec 11, 2021 at 20:28
  • 1
    Yes, probably. But if the circles were more complicated curves, your approach will still work. Dec 11, 2021 at 20:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .