# Tell TikZ not to draw paths with least one coordinate outside clipping region

Using Paul Gaborit's code for drawing subregions of Penrose tilings, I've created this image:

The code to produce this is:

\documentclass{article}
\usepackage[active,tightpage]{preview}
\usepackage{tikz}

\PreviewEnvironment{tikzpicture}
\usetikzlibrary{calc}
\pgfmathsetlengthmacro{\len}{10cm}
\pgfmathtruncatemacro{\recurs}{5}
\pgfmathsetmacro{\invphi}{2/(1+sqrt(5))} % phi = golden ratio = (1+sqrt(5))/2

\tikzset{
penrose line/.style={draw=black,line join=round},
penrose kite/.style={fill=teal,penrose line},
penrose dart/.style={fill=yellow,penrose line},
penrose common/.style={},
penrose path 1/.style={penrose common},
penrose path 2/.style={penrose common},
penrose path 3/.style={penrose common},
penrose rev path 1/.style={penrose common},
penrose rev path 2/.style={penrose common},
penrose rev path 3/.style={penrose common},
}

\newcommand\penrosedrawkite[3]{% ver = starting vertex, angle = direction of first edge, len = length of first edge
\path (#1)
+(#2+36:#3) coordinate (#1-b)
+(#2:#3) coordinate (#1-c)
+(#2-36:#3) coordinate (#1-d);
\path[penrose kite] (#1)
to[penrose path 1] (#1-b)
to[penrose rev path 2] (#1-c)
to[penrose path 2] (#1-d)
to[penrose rev path 1] (#1);
}

\newcommand\penrosekite[5]{% n = number of decompositions remaining, ver, angle, len, rot = sense of rotation (0 means anticlockwise, 1 means clockwise)
\ifnum#1=0 % i.e. if no decomposition cycles remain
\ifnum#5=1
\penrosedrawkite{#2}{#3}{#4}
\fi
\else % i.e. if at least one decomposition cycle remains
{
\edef\dep{#1}
\edef\ver{#2}
\edef\angle{#3}
\edef\len{#4}
\edef\rot{#5}
\pgfmathtruncatemacro{\n}{\dep-1}
\edef\namex{\ver\n}
\pgfmathsetlengthmacro{\newlen}{\len*\invphi}
\ifnum#5=1
\path (\ver) ++(\angle-36:\len) coordinate (\namex);
\pgfmathtruncatemacro{\newanglea}{mod(\angle+108,360)}
\penrosekite{\n}{\namex}{\newanglea}{\newlen}{1}
\penrosekite{\n}{\namex}{\newanglea}{\newlen}{0}
\penrosedart{\n}{\ver}{\angle}{\newlen}{1}
\else
\path (\ver) ++(\angle+36:\len) coordinate (\namex);
\pgfmathtruncatemacro{\newanglea}{mod(\angle-108,360)}
\penrosekite{\n}{\namex}{\newanglea}{\newlen}{0}
\penrosekite{\n}{\namex}{\newanglea}{\newlen}{1}
\penrosedart{\n}{\ver}{\angle}{\newlen}{0}
\fi
}
\fi
}

\newcommand\penrosedrawdart[3]{% ver, angle, len
\path (#1)
+(#2:#3) coordinate (#1-b)
+(#2-36:#3*\invphi) coordinate (#1-c)
+(#2-72:#3) coordinate (#1-d);
\path[penrose dart] (#1)
to[penrose path 3] (#1-b)
to[penrose path 2] (#1-c)
to[penrose rev path 2] (#1-d)
to[penrose rev path 3] (#1);
}

\newcommand\penrosedart[5]{% n, ver, angle, len, rot
\ifnum#1=0 % i.e. if no decomposition cycles remain
\ifnum#5=1
\penrosedrawdart{#2}{#3}{#4}
\fi
\else % i.e. if at least one decomposition cycle remains
{
\edef\dep{#1}
\edef\ver{#2}
\edef\angle{#3}
\edef\len{#4}
\edef\rot{#5}
\pgfmathtruncatemacro{\n}{\dep-1}
\edef\namex{\ver\n}
\pgfmathsetlengthmacro{\newlen}{\len*\invphi}
\path (\ver) ++(\angle:\len) coordinate (\namex);
\ifnum#5=1
\pgfmathsetmacro{\newanglea}{mod(\angle-144,360)}
\pgfmathsetmacro{\newangleb}{mod(\angle-36,360)}
\penrosedart{\n}{\namex}{\newanglea}{\newlen}{1}
\penrosekite{\n}{\ver}{\newangleb}{\newlen}{0}
\else
\pgfmathtruncatemacro{\newanglea}{mod(\angle+144,360)}
\pgfmathtruncatemacro{\newangleb}{mod(\angle+36,360)}
\penrosedart{\n}{\namex}{\newanglea}{\newlen}{0}
\penrosekite{\n}{\ver}{\newangleb}{\newlen}{1}
\fi
}
\fi
}

\begin{document}
\begin{tikzpicture}
\begin{scope}[yshift=-5.2*\len, rotate=342]
\foreach \level in {0,...,4}{
\begin{scope}[rotate=\level*72]
\coordinate (a) at (0,0);
\penrosekite{\recurs}{a}{0}{\len}{0}
\penrosekite{\recurs}{a}{0}{\len}{1}
\end{scope}
}
\draw[ultra thick,white] (0,0) circle (2.125in);
\end{scope}
\end{tikzpicture}
\end{document}


Now I'd like to modify this so that only those tiles are drawn whose vertices all lie within, say, 2.125 inches of the origin. (A white circle of that radius appears in the image above.) To do this, the natural idea is to modify the definition of the \penrosekite command by replacing the line

\penrosedrawkite{#2}{#3}{#4}


with some lines to the following effect: "If each vertex of the kite you're about to draw lies within 2.125 inches of the origin, then draw that kite, but otherwise don't draw it." Similarly for the command \penrosedart. I've tried to implement this idea in various ways, but I've failed. Is there an easy way?

-
Welcome to TeX.SX! A tip: If you indent lines by 4 spaces or enclose words in backticks , they'll be marked as code, as can be seen in my edit. You can also highlight the code and click the “code” button (with {} on it). You can also use this for using < and > (which otherwise needs to escaped in HTML to &lt; and &gt;). –  Qrrbrbirlbel May 14 '13 at 3:06
Thanks for the tips! I had some trouble formatting the code, so I just opted for the <pre> tag. Your edit looks much better. –  Cole Leahy May 14 '13 at 3:24

If one changes the definition of \penrosedrawkite (and similar \penrosedrawdart) to

\makeatletter
\newcommand\penrosedrawkite[3]{% ver = starting vertex, angle = direction of first edge, len = length of first edge
\pgfinterruptboundingbox % don't mess with my bounding box
\path (#1)
+(#2+36:#3) coordinate (#1-b)
+(#2:#3)    coordinate (#1-c)
+(#2-36:#3) coordinate (#1-d);
\endpgfinterruptboundingbox
\def\maxVeclen{0pt}%
\foreach \suffix in {,-b,-c,-d} {
\pgfextractx\pgf@xb{\pgfpointanchor{#1\suffix}{center}}%
\pgfextracty\pgf@yb{\pgfpointanchor{#1\suffix}{center}}%
\pgfmathparse{veclen(+\the\pgf@xb,+\the\pgf@yb)}%

\ifdim\pgfmathresult pt>\maxVeclen\xdef\maxVeclen{\pgfmathresult pt}\fi
}
\ifdim\maxVeclen<2.125in\relax
\path[penrose kite] (#1)
to[penrose path 1] (#1-b)
to[penrose rev path 2] (#1-c)
to[penrose path 2] (#1-d)
to[penrose rev path 1] (#1);
\fi
}
\makeatother


the code produces:

### Notes

• Do not forget \makeatletter and \makeatother.
• TikZ’s calc library probably offers a way that is easier to read and understand.
-
Perfect! Thank you, Qrrbrbirlbel. –  Cole Leahy May 14 '13 at 4:01
@ColeLeahy See my update and this bonus. –  Qrrbrbirlbel May 14 '13 at 12:18
Bonus indeed! Thanks again. My newfound knowledge is sure to be useful in other projects. –  Cole Leahy May 14 '13 at 17:31

Like in the Qrrbrbirlbel's answer, I propose to change the definition of \penrosedrawkite to:

\makeatletter
\newcommand\penrosedrawkite[3]{% ver = starting vertex, angle = direction of first edge, len = length of first edge
\pgfinterruptboundingbox % don't mess with my bounding box
\path (#1)
+(#2+36:#3) coordinate (#1-b)
+(#2:#3)    coordinate (#1-c)
+(#2-36:#3) coordinate (#1-d);
\endpgfinterruptboundingbox
\gdef\maxVeclen{0pt}%
\foreach \suffix in {,-b,-c,-d} {
\path let
\p1 = (#1\suffix.center),
\n1 = {veclen(\x1,\y1)},
\n{res} = {\n1 > \maxVeclen ? \n1 : \maxVeclen}
in
\pgfextra{
\xdef\maxVeclen{\n{res}}
};
}
\ifdim\maxVeclen<2.125in\relax
\path[penrose kite] (#1)
to[penrose path 1] (#1-b)
to[penrose rev path 2] (#1-c)
to[penrose path 2] (#1-d)
to[penrose rev path 1] (#1);
\fi
}
\makeatother


In this version, I don't use PGF macros but only TikZ macros (let): I think that this code is more readable.

The code produces:

-
It would be helpful to do such a check early on in \penrosekite/\penrosedirt` to stop the algorithm from going further away once it has reached the given distance. Can this be done or is the recursion not linear? –  Qrrbrbirlbel May 14 '13 at 12:28
Thank you, Paul. I agree that your TikZ-only code is more readable. –  Cole Leahy May 14 '13 at 17:37