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.

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

enter image description here

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?

share|improve this question
1  
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
add comment

2 Answers

up vote 4 down vote accepted

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:

enter image description here

Notes

  • Do not forget \makeatletter and \makeatother.
  • TikZ’s calc library probably offers a way that is easier to read and understand.
share|improve this answer
    
Perfect! Thank you, Qrrbrbirlbel. –  Cole Leahy May 14 '13 at 4:01
1  
@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
add comment

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:

enter image description here

share|improve this answer
    
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
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.