% \iffalse meta-comment %<*internal> \iffalse % %<*readme> ---------------------------------------------------------------- penrose --- TikZ library for producing tiling patterns E-mail: loopspace@mathforge.org Released under the LaTeX Project Public License v1.3c or later See http://www.latex-project.org/lppl.txt ---------------------------------------------------------------- This package is for the creation of Penrose and similar tilings. % %<*internal> \fi \def\nameofplainTeX{plain} \ifx\fmtname\nameofplainTeX\else \expandafter\begingroup \fi % %<*install> \input l3docstrip.tex \keepsilent \askforoverwritefalse \preamble ---------------------------------------------------------------- tilings --- TikZ library for producing tilings E-mail: loopspace@mathforge.org Released under the LaTeX Project Public License v1.3c or later See http://www.latex-project.org/lppl.txt ---------------------------------------------------------------- \endpreamble \postamble Copyright (C) 2014-2023 by Andrew Stacey This work may be distributed and/or modified under the conditions of the LaTeX Project Public License (LPPL), either version 1.3c of this license or (at your option) any later version. The latest version of this license is in the file: http://www.latex-project.org/lppl.txt This work is "maintained" (as per LPPL maintenance status) by Andrew Stacey. This work consists of the files penrose_code.dtx penrose.tex and the derived files penrose.ins penrose_code.pdf penrose.pdf tikzlibrarytilings.code.tex tikzlibrarytilings.penrose.code.tex tikzlibrarytilings.polykite.code.tex tikzlibrarypenrose.code.tex README.txt \endpostamble \usedir{tex/latex/penrose} \generate{ \file{tikzlibrarytilings.code.tex}{\from{\jobname.dtx}{tilings}} } \generate{ \file{tikzlibrarytilings.penrose.code.tex}{\from{\jobname.dtx}{penrose}} } \generate{ \file{tikzlibrarytilings.polykite.code.tex}{\from{\jobname.dtx}{polykite}} } \generate{ \file{tikzlibrarypenrose.code.tex}{\from{\jobname.dtx}{penrosedep}} } % %\endbatchfile %<*internal> \usedir{source/latex/penrose} \generate{ \file{\jobname.ins}{\from{\jobname.dtx}{install}} } \nopreamble\nopostamble \usedir{doc/latex/penrose} \generate{ \file{README.txt}{\from{\jobname.dtx}{readme}} } \ifx\fmtname\nameofplainTeX \expandafter\endbatchfile \else \expandafter\endgroup \fi % %<*driver> \documentclass{l3doc} \usepackage[scale=.8]{geometry} \usepackage[T1]{fontenc} \usepackage{lmodern} \usepackage{tikz} \usepackage{amsmath} %\usepackage{trace} \usetikzlibrary{penrose} %\traceoff %\usepackage[numbered]{hypdoc} \definecolor{lstbgcolor}{rgb}{0.9,0.9,0.9} \usepackage{listings} \lstloadlanguages{[LaTeX]TeX} \lstset{breakatwhitespace=true,breaklines=true,language=TeX} \usepackage{fancyvrb} \newenvironment{example} {\VerbatimEnvironment \begin{VerbatimOut}[gobble=2]{example.out}} {\end{VerbatimOut} \begin{center} % \setlength{\parindent}{0pt} \fbox{\begin{minipage}{.9\linewidth} \lstset{breakatwhitespace=true,breaklines=true,language=TeX,basicstyle=\small} \lstinputlisting[]{example.out} \end{minipage}} \fbox{\begin{minipage}{.9\linewidth} \input{example.out} \end{minipage}} \end{center} } \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \CheckSum{2944} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{1.0}{2014/05/07}{Converted to DTX file} % \changes{1.2}{2019/02/23}{Added general tile creation code} % \changes{1.4}{2021/01/22}{Adapted to latest version of spath3} % \changes{1.6}{2023/03/22}{Included aperiodical hat} % \changes{1.8}{2023/05/11}{LMS systems for aperiodical tiles} % \changes{2.0}{2023/06/01}{Major version change for CTAN} % % \DoNotIndex % { % \begingroup, % \catcode, % \active, % \csname, % \endcsname, % }% % % % \providecommand*{\url}{\texttt} % \GetFileInfo{tikzlibrarytilings.code.tex} % \title{The \textsf{Tilings} package: code} % \author{Andrew Stacey\texorpdfstring{\\ \url{loopspace@mathforge.org}}{}} % \date{\fileversion~from \filedate} % % % \maketitle % % \tableofcontents % % \begin{documentation} % % \section{Introduction} % % This is a TikZ library for drawing tiles, such as Penrose tiles (kite/dart, rhombus, and pentagon versions) and the aperiodical polykite tiles. % It provides two methods of drawing: one in which an automatic pattern is built, and one where the tiles can be placed ``by hand''. % The tiles can be shaped and (hopefully!) still fit together. % For full user documentation, see the \Verb+tilings.pdf+ file. % % % \end{documentation} % % \begin{implementation} % % \section{Implementation} % % % \iffalse %<*tilings> % \fi % % \begin{macrocode} %<@@=tilings> % \end{macrocode} % % \subsection{Initialisation} % % % We use the \Verb+spath3+ library for manipulating the paths that will make up the tiles. % % \begin{macrocode} \ProvidesExplFile {tikzlibrarytilings.code.tex} {2023/06/01} {2.0} {TikZ pics for tilings such as Penrose tiles} \RequirePackage{tikz} \usetikzlibrary{spath3} % \end{macrocode} % Now we move in to the realm of \LaTeX3. % \begin{macrocode} \ExplSyntaxOn % \end{macrocode} % % Start with some basic paths (lines) for the sides of the tiles so that we know that we have well-defined tiles at the outset. % These are globally defined as we will frequently want to define them in one tikzpicture and use them in another. % % \begin{macrocode} \tl_new:N \g_@@_side_a_tl \tl_new:N \g_@@_side_b_tl \tl_new:N \g_@@_side_c_tl \tl_new:N \g_@@_side_d_tl \tl_new:N \g_@@_side_e_tl \tl_new:N \g_@@_side_A_tl \tl_new:N \g_@@_side_B_tl \tl_new:N \g_@@_side_C_tl \tl_new:N \g_@@_side_D_tl \tl_new:N \g_@@_side_E_tl \tl_new:c {g_@@_side_1_tl} \tl_new:c {g_@@_side_2_tl} \tl_new:c {g_@@_side_3_tl} \tl_gset:Nn \g_@@_side_a_tl { \pgfsyssoftpath@movetotoken{0pt}{0pt} \pgfsyssoftpath@linetotoken{1pt}{0pt} } \tl_gset_eq:NN \g_@@_side_b_tl \g_@@_side_a_tl \tl_gset_eq:NN \g_@@_side_c_tl \g_@@_side_a_tl \tl_gset_eq:NN \g_@@_side_d_tl \g_@@_side_a_tl \tl_gset_eq:NN \g_@@_side_e_tl \g_@@_side_a_tl \tl_gset_eq:NN \g_@@_side_A_tl \g_@@_side_a_tl \tl_gset_eq:NN \g_@@_side_B_tl \g_@@_side_a_tl \tl_gset_eq:NN \g_@@_side_C_tl \g_@@_side_a_tl \tl_gset_eq:NN \g_@@_side_D_tl \g_@@_side_a_tl \tl_gset_eq:NN \g_@@_side_E_tl \g_@@_side_a_tl \tl_gset_eq:cN {g_@@_side_1_tl} \g_@@_side_a_tl \tl_gset_eq:cN {g_@@_side_2_tl} \g_@@_side_a_tl \tl_gset_eq:cN {g_@@_side_3_tl} \g_@@_side_a_tl % \end{macrocode} % % \begin{variable}{\l_@@_tmpa_fp, \l_@@_tmpb_fp, \l_@@_tmpc_fp, \l_@@_saved_x_fp, \l_@@_saved_y_fp, \l_@@_tmpa_str, \l_@@_tmpb_str, \l_@@_tmpa_seq, \l_@@_tmpa_tl, \l_@@_tmpb_tl, \l_@@_tmpc_tl, \l_@@_tmpd_tl, \l_@@_tmpa_int, \l_@@_tmpb_int, \l_@@_xa_dim, \l_@@_ya_dim, \l_@@_xb_dim, \l_@@_yb_dim, \g_@@_xa_dim, \g_@@_ya_dim, \g_@@_xb_dim, \g_@@_yb_dim, \l_@@_tmpa_prop, \l_@@_cw_bool, \l_@@_update_saved_bool, \l_@@_relative_bool, \g_@@_output_tl} % We need a few temporary variables to hold intermediate calculations. % % \begin{macrocode} \fp_new:N \l_@@_tmpa_fp \fp_new:N \l_@@_tmpb_fp \fp_new:N \l_@@_tmpc_fp \fp_new:N \l_@@_saved_x_fp \fp_new:N \l_@@_saved_y_fp \str_new:N \l_@@_tmpa_str \str_new:N \l_@@_tmpb_str \seq_new:N \l_@@_tmpa_seq \tl_new:N \l_@@_tmpa_tl \tl_new:N \l_@@_tmpb_tl \tl_new:N \l_@@_tmpc_tl \tl_new:N \l_@@_tmpd_tl \tl_new:N \l_@@_tmp_tile_path_tl \tl_new:N \l_@@_action_lms_tl \tl_new:N \l_@@_parameters_lms_tl \int_new:N \l_@@_tmpa_int \int_new:N \l_@@_tmpb_int \fp_new:N \l_@@_xa_fp \fp_new:N \l_@@_ya_fp \fp_new:N \l_@@_xb_fp \fp_new:N \l_@@_yb_fp \dim_new:N \l_@@_xa_dim \dim_new:N \l_@@_ya_dim \dim_new:N \l_@@_xb_dim \dim_new:N \l_@@_yb_dim \dim_new:N \g_@@_xa_dim \dim_new:N \g_@@_ya_dim \dim_new:N \g_@@_xb_dim \dim_new:N \g_@@_yb_dim \prop_new:N \l_@@_tmpa_prop \bool_new:N \l_@@_cw_bool \bool_new:N \l_@@_update_saved_bool \bool_new:N \l_@@_relative_bool \bool_new:N \l_@@_edge_bool \str_const:Nn \c_@@_colon_str {:} \str_const:Nn \c_@@_comma_str {,} \fp_const:Nn \c_@@_cm_fp {\dim_to_fp:n {1cm}} \tl_new:N \g_@@_output_tl \fp_new:N \g_@@_output_a_fp \fp_new:N \g_@@_output_b_fp \prop_new:N \g_@@_tilenames_prop \regex_const:Nn \c_@@_anchor_regex {\s\w+\Z} \cs_generate_variant:Nn \seq_set_split:Nnn {NVV} \cs_generate_variant:Nn \regex_extract_once:NnNTF {NVNTF} \cs_generate_variant:Nn \tl_if_eq:nnT {nVT} \cs_generate_variant:Nn \tl_if_in:NnT {NVT} \cs_generate_variant:Nn \prop_item:Nn {cV} \cs_generate_variant:Nn \tl_if_head_is_group_p:n {V} % \end{macrocode} % \end{variable} % % \subsection{Helpful Error Messages} % % \begin{macrocode} \msg_new:nnn { tilings }{ not baked } { Tile~ #1~ has~ not~ been~ baked. } \msg_new:nnn { tilings }{ no tile } { Tile~ #1~ has~ not~ been~ defined. } \msg_new:nnn { tilings }{ no side } { Tile~ side~ #1~ has~ not~ been~ defined,~ using~ default. } \msg_new:nnn { tilings }{ tile no edge } { Tile~ #1~ doesn't~ have~ an~ edge~ labelled~ #2; ~ available~ edges~ are~ #3.} \msg_new:nnn { tilings }{ no edge } { Either~ tile~ #1~ doesn't~ exist ~ or~ it~ doesn't~ have~ an~ edge~ labelled~ #2.} % \end{macrocode} % % \subsection{Creating the Tiles} % % \begin{macro}[internal]{\@@_normalise_path:Nn} % When defining the path for a side, we normalise so that it starts at the origin and ends at \Verb+(1pt,0pt)+. % \begin{macrocode} \cs_new_nopar:Npn \@@_normalise_path:Nn #1#2 { % \end{macrocode} % Get the initial point of the path and convert to floating point. % \begin{macrocode} \group_begin: \spath_initialpoint:Nn \l_@@_tmpa_tl {#2} \fp_set:Nn \l_@@_tmpa_fp {\tl_head:N \l_@@_tmpa_tl} \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} \fp_set:Nn \l_@@_tmpb_fp {\tl_head:N \l_@@_tmpa_tl} % \end{macrocode} % Get the final point of the path, and compute the difference of the final and initial points. % % The resulting numbers, say \(a\) and \(b\), will be put into a matrix to rotate and scale the path. % The formula for the matrix is: %^^A % \[ % \frac{1}{a^2 + b^2} % \begin{bmatrix} a & b \\ -b & a \end{bmatrix} % \] % % \begin{macrocode} \spath_finalpoint:Nn \l_@@_tmpa_tl {#2} \fp_set:Nn \l_@@_tmpa_fp {\tl_head:N \l_@@_tmpa_tl - \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} \fp_set:Nn \l_@@_tmpb_fp {\tl_head:N \l_@@_tmpa_tl - \l_@@_tmpb_fp} % \end{macrocode} % Now compute the square of the length of the path for scaling. % \begin{macrocode} \fp_set:Nn \l_@@_tmpc_fp {\l_@@_tmpa_fp^2 + \l_@@_tmpb_fp^2} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_tmpa_fp/\l_@@_tmpc_fp} \fp_set:Nn \l_@@_tmpb_fp {\l_@@_tmpb_fp/\l_@@_tmpc_fp} \fp_set:Nn \l_@@_tmpc_fp {-\l_@@_tmpb_fp} % \end{macrocode} % Now construct the matrix. % \begin{macrocode} \tl_set:Nx \l_@@_tmpb_tl { {\fp_use:N \l_@@_tmpa_fp} {\fp_use:N \l_@@_tmpc_fp} % swapped {\fp_use:N \l_@@_tmpb_fp} % swapped {\fp_use:N \l_@@_tmpa_fp} } % \end{macrocode} % Get the initial point back again for the translation part. % \begin{macrocode} \spath_initialpoint:Nn \l_@@_tmpa_tl {#2} % \end{macrocode} % But we need to premultiply by the matrix because of how the transformations are applied. % \begin{macrocode} \fp_set:Nn \l_@@_tmpa_fp { (-1) * \l_@@_tmpa_fp * \tl_head:N \l_@@_tmpa_tl + (-1) * \l_@@_tmpb_fp * \tl_tail:N \l_@@_tmpa_tl } \fp_set:Nn \l_@@_tmpb_fp { (-1) * \l_@@_tmpa_fp * \tl_tail:N \l_@@_tmpa_tl + \l_@@_tmpb_fp * \tl_head:N \l_@@_tmpa_tl } % \end{macrocode} % Finally, we apply the transformation to the path. % \begin{macrocode} \tl_put_right:Nx \l_@@_tmpb_tl { {\fp_to_dim:N \l_@@_tmpa_fp} {\fp_to_dim:N \l_@@_tmpb_fp} } \spath_transform:NnV \l_@@_tmpa_tl {#2} \l_@@_tmpb_tl \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmpa_tl \group_end: \tl_set_eq:NN #1 \g_@@_output_tl \tl_gclear:N \g_@@_output_tl } \cs_generate_variant:Nn \@@_normalise_path:Nn {NV, cn, cV} \cs_new_protected_nopar:Npn \@@_normalise_path:N #1 { \@@_normalise_path:NV #1#1 } \cs_generate_variant:Nn \@@_normalise_path:N {c} % \end{macrocode} % \end{macro} % % \begin{function}{\SetTilingPath} % This sets the path corresponding to a particular side to the current path, and normalises it. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_tiling_path:n #1 { \group_begin: \pgfsyssoftpath@getcurrentpath\l_@@_tmpa_tl \@@_normalise_path:N \l_@@_tmpa_tl \tl_gset_eq:cN {g_@@_side_#1_tl} \l_@@_tmpa_tl \group_end: } \NewDocumentCommand \SetTilingPath { m } { \@@_set_tiling_path:n {#1} } % \end{macrocode} % \end{function} % % \begin{macro}[internal]{\tikz_scan_point:n} % This is a wrapper around \Verb+\tikz@scan@one@point+ to make it easier to use with \LaTeX3 variables. % \begin{macrocode} \cs_new_nopar:Npn \tikz_scan_point:n #1 { \tikz@scan@one@point\pgfutil@firstofone#1\relax } \cs_generate_variant:Nn \tikz_scan_point:n {V} % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\tikz_node_if_defined:TF} % This extracts the code that tests if a node is defined. % \begin{macrocode} \prg_new_conditional:Npnn \tikz_node_if_defined:n #1 {p,T,F,TF} { \tl_if_exist:cTF {pgf@sh@ns@\use:c{tikz@pp@name}{#1}} { \prg_return_true: }{ \tl_if_exist:cTF {pgf@sh@ns@not yet positionedPGFINTERNAL\use:c{tikz@pp@name}{#1}} { \pgf_return_true: } { \prg_return_false: } } } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_keys_get:Nn,\pgfkeys_get:n} % This is a wrapper around \Verb+\pgfkeysgetvalue+ to make it easier to use with \LaTeX3 variables. % \begin{macrocode} \cs_new_nopar:Npn \@@_keys_get:Nn #1#2 { \pgfkeysgetvalue{/tikz/tiling/#2}{#1} } \cs_new_nopar:Npn \@@_keys_get:n #1 { \pgfkeysvalueof{/tikz/tiling/#1} } \cs_new_nopar:Npn \@@_tikz_keys_get:Nn #1#2 { \pgfkeysgetvalue{/tikz/#2}{#1} } \cs_new_nopar:Npn \@@_tikz_keys_get:n #1 { \pgfkeysvalueof{/tikz/#1} } \cs_new_nopar:Npn \@@_pgf_keys_get:Nn #1#2 { \pgfkeysgetvalue{#2}{#1} } \cs_new_nopar:Npn \@@_pgf_keys_get:n #1 { \pgfkeysvalueof{#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_make_tile:nnn} % This builds the tile path from its pieces. % The arguments are the name of the tile, the descriptions of the sides, and a token list of the coordinates. % \begin{macrocode} \cs_new_nopar:Npn \@@_make_tile:nnn #1#2#3 { % \end{macrocode} % Get the first coordinate and initialise the path with a move to this point. % \begin{macrocode} \group_begin: \tl_set:Nn \l_@@_tmpa_tl {#3} \tl_set:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl} \tl_set:Nn \l_@@_tmpa_tl {\pgfsyssoftpath@movetotoken} \tl_put_right:Nx \l_@@_tmpa_tl { { \fp_to_dim:n {(\tl_item:Nn \l_@@_tmpb_tl {1}) * \c_@@_cm_fp} } { \fp_to_dim:n {(\tl_item:Nn \l_@@_tmpb_tl {2}) * \c_@@_cm_fp} } } \tl_set_eq:NN \l_@@_tmp_tile_path_tl \l_@@_tmpa_tl % \end{macrocode} % Now we have our path initialised, we can start appending the side paths according to the specification in the second argument. % % We append the initial coordinate to the end of the list to make a closed cycle. % \begin{macrocode} \tl_set:Nn \l_@@_tmpa_tl {#3} \tl_put_right:Nx \l_@@_tmpa_tl {{\tl_head:N \l_@@_tmpa_tl}} % \end{macrocode} % Now we walk through the description of the sides, adding the specified paths to our tile path. % \begin{macrocode} \tl_map_inline:nn {#2} { % \end{macrocode} % Clone the path for this side. % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl {\tl_head:n {##1}} \tl_if_exist:cF {g_@@_side_ \tl_use:N \l_@@_tmpc_tl _tl} { \msg_error:nnx { tilings }{ no side } { \tl_use:N \l_@@_tmpc_tl } \tl_gset_eq:cc {g_@@_side_ \tl_use:N \l_@@_tmpc_tl _tl} {g_@@_side_a_tl} } \tl_set_eq:Nc \l_@@_tmpd_tl {g_@@_side_ \tl_use:N \l_@@_tmpc_tl _tl} % \end{macrocode} % Strip off the next coordinate, and convert it to a point. % \begin{macrocode} \tl_set:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl} \tl_set:Nx \l_@@_tmpa_tl {\tl_tail:N \l_@@_tmpa_tl} % \end{macrocode} % Store the resulting coordinate. % \begin{macrocode} \fp_set:Nn \l_@@_tmpa_fp { \tl_item:Nn \l_@@_tmpb_tl {1} } \fp_set:Nn \l_@@_tmpb_fp { \tl_item:Nn \l_@@_tmpb_tl {2} } % \end{macrocode} % Now get the next coordinate. % \begin{macrocode} \tl_set:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl} % \end{macrocode} % We want the difference between the two coordinates. % \begin{macrocode} \fp_set:Nn \l_@@_tmpa_fp {\tl_item:Nn \l_@@_tmpb_tl {1} - \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpb_fp {\tl_item:Nn \l_@@_tmpb_tl {2} - \l_@@_tmpb_fp} % \end{macrocode} % This is converted into a transformation matrix. % \begin{macrocode} \fp_set:Nn \l_@@_tmpc_fp {-\l_@@_tmpb_fp} \tl_set:Nx \l_@@_tmpb_tl { {\fp_to_dim:n { \l_@@_tmpa_fp * \c_@@_cm_fp }} {\fp_to_dim:n { \l_@@_tmpb_fp * \c_@@_cm_fp }}% not swapped {\fp_to_dim:n { \l_@@_tmpc_fp * \c_@@_cm_fp }}% not swapped {\fp_to_dim:n { \l_@@_tmpa_fp * \c_@@_cm_fp }} {0} {0} } % \end{macrocode} % The transformation is applied to the cloned path. % \begin{macrocode} \spath_transform:NV \l_@@_tmpd_tl \l_@@_tmpb_tl % \end{macrocode} % And this is welded to the tile path. % \begin{macrocode} \spath_weld:NV \l_@@_tmp_tile_path_tl \l_@@_tmpd_tl } % \end{macrocode} % At the end we close the path. % \begin{macrocode} \spath_close:N \l_@@_tmp_tile_path_tl \tl_gset_eq:NN \g_@@_output_tl \l_@@_tmp_tile_path_tl \group_end: \tl_gclear_new:c {g_@@_tile_#1_tl} \tl_gset_eq:cN {g_@@_tile_#1_tl} \g_@@_output_tl \tl_gclear:N \g_@@_output_tl } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_make_tile:nn} % A wrapper around the above which allows us to specify the second two arguments as two items in a token list. % \begin{macrocode} \cs_new_nopar:Npn \@@_make_tile:nn #1#2 { \@@_make_tile:nnn {#1} #2 } \cs_generate_variant:Nn \@@_make_tile:nn {nV} % \end{macrocode} % \end{macro} % % \subsection{Specifying the Tiles} % % The tile specifications are contained in a \Verb+prop+. % \begin{macrocode} \prop_new:N \g_@@_tiles_prop % \end{macrocode} % % \begin{macro}[internal]{\@@_add_coordinate:Nnn, \@@_add_coordinate:w} % Process a coordinate through \Verb+fp+ and adds it to a token list. % \begin{macrocode} \cs_new_nopar:Npn \@@_add_coordinate:Nnn #1#2#3 { \group_begin: \fp_set:Nn \l_@@_tmpa_fp {#2} \fp_set:Nn \l_@@_tmpb_fp {#3} \bool_if:NT \l_@@_relative_bool { \fp_add:Nn \l_@@_tmpa_fp {\l_@@_saved_x_fp} \fp_add:Nn \l_@@_tmpb_fp {\l_@@_saved_y_fp} } \fp_gset_eq:NN \g_@@_output_a_fp \l_@@_tmpa_fp \fp_gset_eq:NN \g_@@_output_b_fp \l_@@_tmpb_fp \group_end: \tl_put_right:Nx #1 { {{\fp_use:N \g_@@_output_a_fp}{\fp_use:N \g_@@_output_b_fp}} } \bool_if:NT \l_@@_update_saved_bool { \fp_set_eq:NN \l_@@_saved_x_fp \g_@@_output_a_fp \fp_set_eq:NN \l_@@_saved_y_fp \g_@@_output_b_fp } \fp_gzero:N \g_@@_output_a_fp \fp_gzero:N \g_@@_output_b_fp } % \end{macrocode} % Wrapper around the add coordinate command to split at a comma. % \begin{macrocode} \cs_new_nopar:Npn \@@_add_xy_coordinate:w #1#2,#3 \q_stop { \@@_add_coordinate:Nnn #1 {#2}{#3} } % \end{macrocode} % % Wrapper around the add coordinate command to split at a colon. % \begin{macrocode} \cs_new_nopar:Npn \@@_add_rth_coordinate:w #1#2:#3 \q_stop { \@@_add_coordinate:Nnn #1 {(#3) * cosd(#2)}{(#3) * sind(#2)} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_transform_side_to_axis:Nnn} % Apply a transformation to make a given side lie on the x-axis. % Second argument is the tile, third is the side, first is whether to reverse the side. % \begin{macrocode} \cs_new_nopar:Npn \@@_transform_side_to_axis:Nnn #1#2#3 { % \end{macrocode} % Get our tile data, checking if the tile exists. % \begin{macrocode} \group_begin: \prop_get:NnNTF \g_@@_tiles_prop {#2} \l_@@_tmpa_tl { % \end{macrocode} % Start with the edge list. % % Initialise the counter. % \begin{macrocode} \int_zero:N \l_@@_tmpb_int \int_incr:N \l_@@_tmpb_int % \end{macrocode} % Get the path type list. % % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl} % \end{macrocode} % % Iterate through the path type list, looking for the requested path. % \begin{macrocode} \bool_set_false:N \l_@@_edge_bool \tl_map_inline:Nn \l_@@_tmpc_tl { \str_if_eq:nnT {##1} {#3} { \bool_set_true:N \l_@@_edge_bool \tl_map_break: } \int_incr:N \l_@@_tmpb_int } \bool_if:NTF \l_@@_edge_bool { % \end{macrocode} % Get the coordinate list. % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpa_tl} % \end{macrocode} % Strip off the outer braces. % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl {\tl_item:Nn \l_@@_tmpc_tl {1}} % \end{macrocode} % Add the first coordinate at the end. % \begin{macrocode} \tl_put_right:Nx \l_@@_tmpc_tl {{\tl_item:Nn \l_@@_tmpc_tl {1}}} % \end{macrocode} % Get the coordinates for this edge. % \begin{macrocode} \tl_set:Nx \l_@@_tmpa_tl {\tl_item:Nn \l_@@_tmpc_tl {\int_use:N \l_@@_tmpb_int}} \tl_set:Nx \l_@@_tmpb_tl {\tl_item:Nn \l_@@_tmpc_tl {\int_use:N \l_@@_tmpb_int + 1}} % \end{macrocode} % Possibly swap the ends. % \begin{macrocode} \bool_if:NT #1 { \tl_set:NV \l_@@_tmpc_tl \l_@@_tmpa_tl \tl_set:NV \l_@@_tmpa_tl \l_@@_tmpb_tl \tl_set:NV \l_@@_tmpb_tl \l_@@_tmpc_tl } % \end{macrocode} % Get the coordinates of the first point, which will be the origin of the transformation. % \begin{macrocode} \fp_set:Nn \l_@@_xa_fp {\tl_item:Nn \l_@@_tmpb_tl {1}} \fp_set:Nn \l_@@_ya_fp {\tl_item:Nn \l_@@_tmpb_tl {2}} % \end{macrocode} % Get the coordinates of the second point and adjust relative to the first. % \begin{macrocode} \fp_set:Nn \l_@@_xb_fp {\tl_item:Nn \l_@@_tmpa_tl {1} - \l_@@_xa_fp} \fp_set:Nn \l_@@_yb_fp {\tl_item:Nn \l_@@_tmpa_tl {2} - \l_@@_ya_fp} % \end{macrocode} % And normalise the vector along it. % \begin{macrocode} % \fp_set:Nn \l_@@_xb_fp {\l_@@_xb_fp / \c_@@_cm_fp} % \fp_set:Nn \l_@@_yb_fp {\l_@@_yb_fp / \c_@@_cm_fp} \fp_set:Nn \l_@@_tmpa_fp {(\l_@@_xb_fp)^2 + (\l_@@_yb_fp)^2} \fp_set:Nn \l_@@_xb_fp { \l_@@_xb_fp / \l_@@_tmpa_fp} \fp_set:Nn \l_@@_yb_fp { \l_@@_yb_fp / \l_@@_tmpa_fp} % \end{macrocode} % Now rotate so that the \(x\)--axis lies along the edge. % \begin{macrocode} \tl_gset:Nx \g_@@_output_tl { \exp_not:N \pgftransformtriangle { \exp_not:N \pgfpoint{0pt}{0pt} } { \exp_not:N \pgfpoint {\fp_to_dim:N \l_@@_xb_fp}{\fp_to_dim:n {-\l_@@_yb_fp}} } { \exp_not:N \pgfpoint {\fp_to_dim:N \l_@@_yb_fp}{\fp_to_dim:N \l_@@_xb_fp} } \exp_not:N \pgftransformshift { \exp_not:N \pgfpoint { \fp_to_dim:n {-\l_@@_xa_fp * \c_@@_cm_fp} } { \fp_to_dim:n {-\l_@@_ya_fp * \c_@@_cm_fp} } } } } { \msg_error:nnxxx {tilings} {tile no edge} {#2} {#3} {\tl_use:N \l_@@_tmpc_tl } \tl_gclear:N \g_@@_output_tl } } { \msg_error:nnn {tilings} {no tile} {#2} \tl_gclear:N \g_@@_output_tl } \group_end: \tl_use:N \g_@@_output_tl \tl_gclear:N \g_@@_output_tl } % \end{macrocode} % \end{macro} % % \begin{macrocode} \cs_generate_variant:Nn \@@_transform_side_to_axis:Nnn {Nnx,NnV,NVV} % \end{macrocode} % % \begin{macro}[internal]{\@@_translate_vertex_to_origin:Nnn} % Apply a transformation to make a given vertex sit at the origin. % Second argument is the tile, third is the side, first is a boolean to determine whether to use the start or end. % \begin{macrocode} \cs_new_nopar:Npn \@@_translate_vertex_to_origin:Nnn #1#2#3 { % \end{macrocode} % Get our tile data, checking if the tile exists. % \begin{macrocode} \group_begin: \prop_get:NnNTF \g_@@_tiles_prop {#2} \l_@@_tmpa_tl { % \end{macrocode} % Start with the edge list. % % Initialise the counter. % \begin{macrocode} \int_zero:N \l_@@_tmpb_int \int_incr:N \l_@@_tmpb_int % \end{macrocode} % Get the path type list. % % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl} % \end{macrocode} % % Iterate through the path type list, looking for the requested path. % \begin{macrocode} \bool_set_false:N \l_@@_edge_bool \tl_map_inline:Nn \l_@@_tmpc_tl { \str_if_eq:nnT {##1} {#3} { \bool_set_true:N \l_@@_edge_bool \tl_map_break: } \int_incr:N \l_@@_tmpb_int } \bool_if:NTF \l_@@_edge_bool { % \end{macrocode} % Get the coordinate list. % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpa_tl} % \end{macrocode} % Strip off the outer braces. % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl {\tl_item:Nn \l_@@_tmpc_tl {1}} % \end{macrocode} % Add the first coordinate at the end. % \begin{macrocode} \tl_put_right:Nx \l_@@_tmpc_tl {{\tl_item:Nn \l_@@_tmpc_tl {1}}} % \end{macrocode} % Get the coordinates for this edge. % \begin{macrocode} \tl_set:Nx \l_@@_tmpa_tl {\tl_item:Nn \l_@@_tmpc_tl {\int_use:N \l_@@_tmpb_int}} \tl_set:Nx \l_@@_tmpb_tl {\tl_item:Nn \l_@@_tmpc_tl {\int_use:N \l_@@_tmpb_int + 1}} % \end{macrocode} % Possibly swap the ends. % \begin{macrocode} \bool_if:NT #1 { \tl_set:NV \l_@@_tmpc_tl \l_@@_tmpa_tl \tl_set:NV \l_@@_tmpa_tl \l_@@_tmpb_tl \tl_set:NV \l_@@_tmpb_tl \l_@@_tmpc_tl } % \end{macrocode} % Get the coordinates of the first point, which will be the origin of the transformation. % \begin{macrocode} \fp_set:Nn \l_@@_xa_fp {\tl_item:Nn \l_@@_tmpb_tl {1}} \fp_set:Nn \l_@@_ya_fp {\tl_item:Nn \l_@@_tmpb_tl {2}} % \end{macrocode} % Shift to place the selected vertex at the origin. % \begin{macrocode} \tl_gset:Nx \g_@@_output_tl { \exp_not:N \pgftransformshift { \exp_not:N \pgfpoint { \fp_to_dim:n {-\l_@@_xa_fp * \c_@@_cm_fp} } { \fp_to_dim:n {-\l_@@_ya_fp * \c_@@_cm_fp} } } } } { \msg_error:nnxxx {tilings} {tile no edge} {#2} {#3} {\tl_use:N \l_@@_tmpc_tl } \tl_gclear:N \g_@@_output_tl } } { \msg_error:nnn {tilings} {no tile} {#2} \tl_gclear:N \g_@@_output_tl } \group_end: \tl_use:N \g_@@_output_tl \tl_gclear:N \g_@@_output_tl } % \end{macrocode} % \end{macro} % % \begin{macrocode} \cs_generate_variant:Nn \@@_translate_vertex_to_origin:Nnn {Nnx,NnV,NVV} % \end{macrocode} % % \begin{macro}[internal]{\TransformAlongSide} % Make this available outside the \LaTeX3 environment. % The starred version allows for reversing the side. % \begin{macrocode} \DeclareDocumentCommand \TransformAlongSide {s m m} { % \end{macrocode} % Store the star % \begin{macrocode} \IfBooleanTF {#1} { \bool_set_true:N \l_@@_cw_bool } { \bool_set_false:N \l_@@_cw_bool } \@@_transform_side_to_axis:Nnx \l_@@_cw_bool {#2}{#3} } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_coordinates_at_vertices:n} % This places TikZ coordinates at the vertices of the tile. % \begin{macrocode} \cs_new_nopar:Npn \@@_coordinates_at_vertices:n #1 { \group_begin: % \end{macrocode} % Get our tile data % \begin{macrocode} \prop_get:NnN \g_@@_tiles_prop {#1} \l_@@_tmpa_tl % \end{macrocode} % Start with the edge list % \begin{macrocode} \tl_set:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpa_tl} % \end{macrocode} % Get the coordinate list % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpa_tl} % \end{macrocode} % Strip off the outer braces % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl {\tl_item:Nn \l_@@_tmpc_tl {1}} % \end{macrocode} % Add the first coordinate at the end % \begin{macrocode} \tl_put_right:Nx \l_@@_tmpc_tl {{\tl_item:Nn \l_@@_tmpc_tl {1}}} % \end{macrocode} % Get the first coordinate % \begin{macrocode} \tl_set:Nx \l_@@_tmpa_tl {\tl_head:N \l_@@_tmpc_tl} \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} % \end{macrocode} % Iterate through the edge list, placing coordinates % \begin{macrocode} \tl_map_inline:Nn \l_@@_tmpb_tl { \tl_set:Nx \l_@@_tmpd_tl { \exp_not:N \coordinate (-edge~ ##1~ start)~ at ( \tl_item:Nn \l_@@_tmpa_tl {1}, \tl_item:Nn \l_@@_tmpa_tl {2} ); } \tl_use:N \l_@@_tmpd_tl \tl_set:Nx \l_@@_tmpa_tl {\tl_head:N \l_@@_tmpc_tl} \tl_set:Nx \l_@@_tmpc_tl {\tl_tail:N \l_@@_tmpc_tl} \tl_set:Nx \l_@@_tmpd_tl { \exp_not:N \coordinate (-edge~ ##1~ end)~ at ( \tl_item:Nn \l_@@_tmpa_tl {1}, \tl_item:Nn \l_@@_tmpa_tl {2} ); } \tl_use:N \l_@@_tmpd_tl } \group_end: } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\CoordinatesAtVertices} % User-accessible wrapper around the above. % \begin{macrocode} \DeclareDocumentCommand \CoordinatesAtVertices {m} { \@@_coordinates_at_vertices:n {#1} } % \end{macrocode} % \end{macro} % % % \begin{macrocode} \tikzset{ transform~ to~ tile/.code~ args={#1~ along~ #2}{% \group_begin: \tl_if_in:nnTF {#1} {back} { \tikzset{ tiling/alignment~ set~ location=#1, tiling/alignment~ direction={backwards} } } { \tikzset{ tiling/alignment~ location=#1, tiling/alignment~ direction={forewards} } } \tl_if_in:nnTF {#2} {using} { \tikzset{ tiling/alignment~ set~ edges=#2, } } { \tikzset{ tiling/alignment~ edge=#2, } } \tikz_scan_point:n { (\@@_keys_get:n {alignment~ location} -edge~ \@@_keys_get:n {alignment~ edge}~ start) } \dim_set_eq:Nc \l_@@_xa_dim {pgf@x} \dim_set_eq:Nc \l_@@_ya_dim {pgf@y} \tikz_scan_point:n { (\@@_keys_get:n {alignment~ location} -edge~ \@@_keys_get:n {alignment~ edge}~ end) } \dim_set_eq:Nc \l_@@_xb_dim {pgf@x} \dim_set_eq:Nc \l_@@_yb_dim {pgf@y} \@@_keys_get:Nn \l_@@_tmpb_tl {alignment~ direction} \tl_if_eq:NnTF \l_@@_tmpb_tl {forewards} { \dim_gset_eq:NN \g_@@_xa_dim \l_@@_xa_dim \dim_gset_eq:NN \g_@@_ya_dim \l_@@_ya_dim \dim_gset_eq:NN \g_@@_xb_dim \l_@@_xb_dim \dim_gset_eq:NN \g_@@_yb_dim \l_@@_yb_dim } { \dim_gset_eq:NN \g_@@_xa_dim \l_@@_xb_dim \dim_gset_eq:NN \g_@@_ya_dim \l_@@_yb_dim \dim_gset_eq:NN \g_@@_xb_dim \l_@@_xa_dim \dim_gset_eq:NN \g_@@_yb_dim \l_@@_ya_dim } \dim_gsub:Nn \g_@@_xb_dim {\g_@@_xa_dim} \dim_gsub:Nn \g_@@_yb_dim {\g_@@_ya_dim} \dim_gset:Nn \g_@@_xb_dim {\g_@@_xb_dim * \dim_ratio:nn {1pt}{1cm}} \dim_gset:Nn \g_@@_yb_dim {\g_@@_yb_dim * \dim_ratio:nn {1pt}{1cm}} \group_end: % \end{macrocode} % We store the initial points in \Verb+\pgf@xa+ and \Verb+\pgf@ya+ but we want \Verb+\pgf@xb+ and \Verb+\pgf@yb+ to be a vector along the edge. % \begin{macrocode} % \end{macrocode} % We shift to the start of the edge. % \begin{macrocode} \pgftransformshift{\pgfpoint{\g_@@_xa_dim}{\g_@@_ya_dim}} % \end{macrocode} % Now rotate so that the \(x\)--axis lies along the edge. % \begin{macrocode} \pgftransformtriangle {\pgfpoint{0pt}{0pt}} {\pgfpoint{\g_@@_xb_dim}{\g_@@_yb_dim}} {\pgfpoint{-\g_@@_yb_dim}{\g_@@_xb_dim}} }, align~ with/.code~ args={#1~ along~ #2}{% \tl_if_in:nnTF {#1} {back} { \tikzset{ tiling/alignment~ set~ location=#1, tiling/alignment~ direction={backwards} } } { \tikzset{ tiling/alignment~ location=#1, tiling/alignment~ direction={forewards} } } \tl_if_in:nnTF {#2} {using} { \tikzset{ tiling/alignment~ set~ edges=#2, } } { \tikzset{ tiling/alignment~ edge=#2, } } \tikz_node_if_defined:nTF { \@@_keys_get:n {alignment~ location} -edge~ \@@_keys_get:n {alignment~ edge}~ start } { \tikzset{ tiling/alignment~ start/.expanded={ (\@@_keys_get:n {alignment~ location} -edge~ \@@_keys_get:n {alignment~ edge}~ start) }, tiling/alignment~ end/.expanded={ (\@@_keys_get:n {alignment~ location} -edge~ \@@_keys_get:n {alignment~ edge}~ end) }, } } { \@@_keys_get:Nn \l_@@_tmpa_tl {alignment~ location} \tl_set:Nx \l_@@_tmpa_tl {\tl_use:N \l_@@_tmpa_tl} \prop_get:NVNTF \g_@@_tilenames_prop \l_@@_tmpa_tl \l_@@_tmpb_tl { \prop_get:NVN \g_@@_tiles_prop \l_@@_tmpb_tl \l_@@_tmpc_tl \msg_error:nnxxx { tilings }{ tile no edge } { \tl_use:N \l_@@_tmpa_tl \c_space_tl (type~ \tl_use:N \l_@@_tmpb_tl) } {\@@_keys_get:n {alignment~ edge} } { \tl_item:Nn \l_@@_tmpc_tl {1} } } { \msg_error:nnx { tilings }{ no tile } {\@@_keys_get:n {alignment~ location} } } } }, tiling/.is~ family, tiling/alignment~ set~ location/.code~ args={#1~ back}{ \tikzset{ tiling/alignment~ location=#1, } }, tiling/alignment~ set~ edges/.code~ args={#1~ using~ #2}{ \tikzset{ tiling/alignment~ edge=#1, tiling/alignment~ new~ edge=#2 } }, align~ between/.code~ args={#1~ and~ #2~ using~ #3}{ \tikzset{ tiling/alignment~ start={#1}, tiling/alignment~ end={#2}, } \str_set:Nn \l_@@_tmpa_str {#3} \str_set:Nx \l_@@_tmpb_str {\str_tail:N \l_@@_tmpa_str} \tikzset{ tiling/alignment~ new~ edge/.expanded={\str_use:N \l_@@_tmpb_str} } \str_set:Nx \l_@@_tmpa_str {\str_head:N \l_@@_tmpa_str} \str_set:Nx \l_@@_tmpb_str {\str_lowercase:f { \l_@@_tmpa_str}} \str_if_eq:NNT \l_@@_tmpa_str \l_@@_tmpb_str { \str_set:Nx \l_@@_tmpb_str {\str_uppercase:f { \l_@@_tmpa_str}} } \tikzset{ tiling/alignment~ edge/.expanded={\str_use:N \l_@@_tmpb_str}, } }, tiling/alignment~ location/.initial={}, tiling/alignment~ edge/.initial=a, tiling/alignment~ new~ edge/.initial={}, tiling/alignment~ direction/.initial={forewards}, tiling/alignment~ start/.initial={}, tiling/alignment~ end/.initial={}, tiling/anchor/.initial={}, % \end{macrocode} % Default clipping style. % \begin{macrocode} every~ tile~ clip/.style={clip} } % \end{macrocode} % % \begin{function}{\DefineTile} % This is the user function for defining a tile. % \begin{macrocode} \DeclareDocumentCommand \DefineTile { s m m m } { % \end{macrocode} % Clear the temporary variable. % \begin{macrocode} \tl_clear:N \l_@@_tmpa_tl % \end{macrocode} % The 3rd parameter is a list of coordinates at vertices, iterate through them and add them to the list. % \begin{macrocode} \int_zero:N \l_@@_tmpa_int \fp_zero:N \l_@@_saved_x_fp \fp_zero:N \l_@@_saved_y_fp \tl_map_inline:nn {#4} { \str_set:Nn \l_@@_tmpa_str {##1} \str_if_eq:VnTF \l_@@_tmpa_str {+} { \int_incr:N \l_@@_tmpa_int } { \int_case:nn {\l_@@_tmpa_int} { {0} { \bool_set_false:N \l_@@_relative_bool \bool_set_true:N \l_@@_update_saved_bool } {1} { \bool_set_true:N \l_@@_relative_bool \bool_set_false:N \l_@@_update_saved_bool } {2} { \bool_set_true:N \l_@@_relative_bool \bool_set_true:N \l_@@_update_saved_bool } } \str_if_in:NnTF \l_@@_tmpa_str {:} { \seq_set_split:NVV \l_@@_tmpa_seq \c_@@_colon_str \l_@@_tmpa_str \@@_add_coordinate:Nnn \l_@@_tmpa_tl { (\seq_item:Nn \l_@@_tmpa_seq {2}) * cosd (\seq_item:Nn \l_@@_tmpa_seq {1}) } { (\seq_item:Nn \l_@@_tmpa_seq {2}) * sind (\seq_item:Nn \l_@@_tmpa_seq {1}) } } { \seq_set_split:NVV \l_@@_tmpa_seq \c_@@_comma_str \l_@@_tmpa_str \@@_add_coordinate:Nnn \l_@@_tmpa_tl { (\seq_item:Nn \l_@@_tmpa_seq {1}) } { (\seq_item:Nn \l_@@_tmpa_seq {2}) } } \int_zero:N \l_@@_tmpa_int } } % \end{macrocode} % Now we make a list of the edge types (from the 2nd parameter), using a prop to keep track of whether an edge is repeated. % \begin{macrocode} \prop_clear:N \l_@@_tmpa_prop \tl_map_inline:nn {#3} { \prop_if_in:NnTF \l_@@_tmpa_prop {##1} { \prop_put:Nnn \l_@@_tmpa_prop {##1} {1} } { \prop_put:Nnn \l_@@_tmpa_prop {##1} {0} } } % \end{macrocode} % Having established their multiplicity, we now create the edges with their names, appending numbers to their names if used more than once. % \begin{macrocode} \tl_clear:N \l_@@_tmpb_tl \tl_map_inline:nn {#3} { \tl_clear:N \l_@@_tmpc_tl \tl_put_right:Nn \l_@@_tmpc_tl {##1} \int_compare:nF {\prop_item:Nn \l_@@_tmpa_prop {##1} == 0} { \tl_put_right:Nx \l_@@_tmpc_tl {\prop_item:Nn \l_@@_tmpa_prop {##1}} \prop_put:Nnx \l_@@_tmpa_prop {##1} {\int_eval:n {\prop_item:Nn \l_@@_tmpa_prop {##1} + 1}} } \tl_put_right:Nx \l_@@_tmpb_tl {{ \l_@@_tmpc_tl }} } % \end{macrocode} % Finally, we can create our tile and add it to the global tile prop. % \begin{macrocode} \prop_gput:Nnx \g_@@_tiles_prop {#2} {{\tl_use:N \l_@@_tmpb_tl} {\tl_use:N \l_@@_tmpa_tl}} % \end{macrocode} % Having created the tile, we make a TikZ pic to place it on the page. % \begin{macrocode} \tikzset{ #2/.pic={ \begin{scope}[ every~ tile~ scope/.try, every~ #2~ scope/.try, this~ tile~ scope/.try ] % \end{macrocode} % Save the name and tile type % \begin{macrocode} \tikz@fig@mustbenamed \prop_gput:NVn \g_@@_tilenames_prop \tikz@fig@name {#2} % \end{macrocode} % Were we given coordinates to align ourselves against? % \begin{macrocode} \@@_keys_get:Nn \l_@@_tmpa_tl {alignment~ start} \tl_if_empty:NTF \l_@@_tmpa_tl { % \end{macrocode} % No alignment information was given, was an anchor specified? % \begin{macrocode} \prop_get:NnN \g_@@_tiles_prop {#2} \l_@@_tmpa_tl \tl_set:Nx \l_@@_tmpc_tl {\tl_head:N \l_@@_tmpa_tl} \@@_keys_get:Nn \l_@@_tmpa_tl {anchor} \tl_if_empty:NTF \l_@@_tmpa_tl { % \end{macrocode} % No positioning information given, but we might have been asked to flip the tile % \begin{macrocode} \bool_if:NT \l_@@_cw_bool { \pgftransformxscale {-1} } } { \regex_extract_once:NVNTF \c_@@_anchor_regex \l_@@_tmpa_tl \l_@@_tmpb_tl { \regex_replace_once:NnN \c_@@_anchor_regex {} \l_@@_tmpa_tl \tl_if_eq:NnTF \l_@@_tmpb_tl {~end} { \bool_set_true:N \l_@@_cw_bool } { \bool_set_false:N \l_@@_cw_bool } } { \bool_set_false:N \l_@@_cw_bool } \tl_set:Nx \l_@@_tmpb_tl {{\tl_use:N \l_@@_tmpa_tl}} \tl_if_in:NVT \l_@@_tmpc_tl \l_@@_tmpb_tl { \@@_translate_vertex_to_origin:NnV \l_@@_cw_bool {#2} \l_@@_tmpa_tl } } } { % \end{macrocode} % Yes, we were. % So we adjust our position accordingly. % The first job is to transform so that we're aligned with the specified coordinates. % \begin{macrocode} \group_begin: % \end{macrocode} % We get the locations of the start and ending coordinates. % \begin{macrocode} \tikzset{ name~ prefix~ .. } \tikz_scan_point:n { \@@_keys_get:n {alignment~ start} } \dim_set_eq:Nc \l_@@_xa_dim {pgf@x} \dim_set_eq:Nc \l_@@_ya_dim {pgf@y} \tikz_scan_point:n { \@@_keys_get:n {alignment~ end} } \dim_set_eq:Nc \l_@@_xb_dim {pgf@x} \dim_set_eq:Nc \l_@@_yb_dim {pgf@y} \@@_keys_get:Nn \l_@@_tmpb_tl {alignment~ direction} \tl_if_eq:NnTF \l_@@_tmpb_tl {forewards} { \dim_gset_eq:NN \g_@@_xa_dim \l_@@_xa_dim \dim_gset_eq:NN \g_@@_ya_dim \l_@@_ya_dim \dim_gset_eq:NN \g_@@_xb_dim \l_@@_xb_dim \dim_gset_eq:NN \g_@@_yb_dim \l_@@_yb_dim } { \dim_gset_eq:NN \g_@@_xa_dim \l_@@_xb_dim \dim_gset_eq:NN \g_@@_ya_dim \l_@@_yb_dim \dim_gset_eq:NN \g_@@_xb_dim \l_@@_xa_dim \dim_gset_eq:NN \g_@@_yb_dim \l_@@_ya_dim } \dim_gsub:Nn \g_@@_xb_dim {\g_@@_xa_dim} \dim_gsub:Nn \g_@@_yb_dim {\g_@@_ya_dim} \dim_gset:Nn \g_@@_xb_dim {\g_@@_xb_dim * \dim_ratio:nn {1pt}{1cm}} \dim_gset:Nn \g_@@_yb_dim {\g_@@_yb_dim * \dim_ratio:nn {1pt}{1cm}} \group_end: % \end{macrocode} % We shift to the start of the edge. % \begin{macrocode} \pgftransformshift{\pgfpoint{\g_@@_xa_dim}{\g_@@_ya_dim}} % \end{macrocode} % And normalise the vector along it. % \begin{macrocode} % \pgfpointnormalised{\pgfpoint{\g_@@_xb_dim}{\g_@@_yb_dim}} % \dim_gset_eq:Nc \g_@@_xb_dim {pgf@x} % \dim_gset_eq:Nc \g_@@_yb_dim {pgf@y} % \end{macrocode} % Now rotate so that the \(x\)--axis lies along the edge. % \begin{macrocode} \pgftransformtriangle {\pgfpoint{0pt}{0pt}} {\pgfpoint{\g_@@_xb_dim}{\g_@@_yb_dim}} {\pgfpoint{-\g_@@_yb_dim}{\g_@@_xb_dim}} % \end{macrocode} % The next job is to shift and rotate the current tile so that the correct edge ends up against the receiving tile. % \begin{macrocode} \str_set:Nx \l_@@_tmpa_str {\@@_keys_get:n {alignment~ edge}} \str_set:Nx \l_@@_tmpa_str {\str_head:N \l_@@_tmpa_str} \str_put_right:Nx \l_@@_tmpa_str {\@@_keys_get:n {alignment~ new~ edge}} \str_set:Nx \l_@@_tmpb_str {\str_lowercase:f { \l_@@_tmpa_str}} \str_if_eq:NNT \l_@@_tmpa_str \l_@@_tmpb_str { \str_set:Nx \l_@@_tmpb_str {\str_uppercase:f { \l_@@_tmpa_str}} } \IfBooleanT {#1} { \bool_set:Nn \l_@@_cw_bool {!\l_@@_cw_bool} } \bool_if:NT \l_@@_cw_bool { \pgftransformyscale {-1} } \@@_transform_side_to_axis:NnV \l_@@_cw_bool {#2} \l_@@_tmpb_str } % \end{macrocode} % Now that the transformation is finalised, we can render the tile. % We clip against the tile path so that the tiles don't ``bleed''. % If we didn't do this, drawing the tile would result in overlaps which can look a bit ugly. % On the other hand, tight clipping can lead to ``gaps'' between the tiles so we make this optional by enclosing it in a style. % % We start by putting coordinates at each vertex, labelled by which edge they are. % \begin{macrocode} \@@_coordinates_at_vertices:n {#2} % \end{macrocode} % And one at the origin of the pic % \begin{macrocode} \coordinate[alias=-center] (-centre) at (0,0); % \end{macrocode} % % The first action is to clip against the tile path. % \begin{macrocode} \UseTile[ every~ tile~ clip/.try, every~ #2~ clip/.try, this~ tile~ clip/.try ]{#2} % \end{macrocode} % Any pre-actions? % \begin{macrocode} \tikzset{ every~ tile~ before~ path/.try, every~ #2~ before~ path/.try, this~ tile~ before~ path/.try } % \end{macrocode} % Now we render the tile path % \begin{macrocode} \UseTile[ every~ tile/.try, every~ #2/.try, this~ tile/.try, pic~ actions ]{#2} % \end{macrocode} % After drawing the tile and placing the coordinates, % \begin{macrocode} \tikzset{ every~ tile~ after~ path/.try, every~ #2~ after~ path/.try, this~ tile~ after~ path/.try } \end{scope} }, % \end{macrocode} % This is a shortcut for installing the \Verb+pic+ type. % \begin{macrocode} #2/.style={ every~ tile~ pic/.try, every~ #2~ pic/.try, pic~ type=#2, } } } % \end{macrocode} % \end{function} % % \begin{function}{\BakeTile} % This is the user wrapper around the tile creation macros. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_bake_tile:n #1 { \prop_get:NnN \g_@@_tiles_prop {#1} \l_@@_tmpa_tl \@@_make_tile:nV {#1} \l_@@_tmpa_tl } \NewDocumentCommand \BakeTile {m} { \@@_bake_tile:n {#1} } % \end{macrocode} % \end{function} % % \begin{function}{\UseTile} % This is the command that actually places a tile on the page. % The first argument is optional and is for styling. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_use_tile:nn #1#2 { % \end{macrocode} % We need to transform the tile to correspond to the current transformation matrix. % To ensure that we only transform the current tile, we clone it first. % \begin{macrocode} \tl_if_exist:cTF {g_@@_tile_#2_tl} { \tl_set_eq:Nc \l_@@_tmp_tile_path_tl {g_@@_tile_#2_tl} % \end{macrocode} % We get the current transformation to apply to this path. % \begin{macrocode} \pgfgettransform \l_@@_tmpa_tl % \end{macrocode} % Apply the transformation, protocol the path, and render it. % \begin{macrocode} \spath_transform:NV \l_@@_tmp_tile_path_tl \l_@@_tmpa_tl \spath_tikz_path:nV {#1} \l_@@_tmp_tile_path_tl } { \msg_error:nnn { tilings }{ not baked }{#2} } } \NewDocumentCommand \UseTile {O{} m} { \@@_use_tile:nn {#1}{#2} } % \end{macrocode} % \end{function} % % \begin{macro}{save tiling path} % This is a style for a user to take a path and make it into the path for one of the sides. % It needs to store both that side and the reverse. % \begin{macrocode} \tikzset{ save~ tiling~ path/.code={ \tikz@addmode{ % \end{macrocode} % Get the current path. % \begin{macrocode} \pgfsyssoftpath@getcurrentpath\l_@@_tmpa_tl % \end{macrocode} % Normalise the path and save. % \begin{macrocode} \@@_normalise_path:N \l_@@_tmpa_tl \tl_gclear_new:c {g_@@_side_#1_tl} \tl_gset_eq:cN {g_@@_side_#1_tl} \l_@@_tmpa_tl % \end{macrocode} % Now create the reverse path. % The name is the upper case version. % \begin{macrocode} \tl_set:Nx \l_@@_tmpb_tl {\str_uppercase:n {#1}} % \end{macrocode} % Reverse the path, and relocate to the interval \([0,1]\). % \begin{macrocode} \spath_reverse:N \l_@@_tmpa_tl \spath_transform:Nnnnnnn \l_@@_tmpa_tl {-1} {0} {0} {-1} {1} {0} \tl_gclear_new:c {g_@@_side_ \tl_use:N \l_@@_tmpb_tl _tl} \tl_gset_eq:cN {g_@@_side_ \tl_use:N \l_@@_tmpb_tl _tl} \l_@@_tmpa_tl } }, clone~ tiling~ side~ path/.style~ 2~ args={ spath/set~ name=tiling~ side, spath/clone~ global={#1}{#2} }, flip~ tile/.code={ \tl_set:Nn \l_@@_tmpa_tl {#1} \tl_set:Nn \l_@@_tmpb_tl {true} \bool_set:Nn \l_@@_cw_bool {\tl_if_eq_p:NN \l_@@_tmpa_tl \l_@@_tmpb_tl} }, flip~ tile/.default={true}, spath/prefix/tiling~side/.style={ spath/set~ prefix=g_@@_side_, }, spath/suffix/tiling~side/.style={ spath/set~ suffix=_tl, }, clone~ tile~ path/.style~ 2~ args={ spath/set~ name=tiling~tile, spath/clone~ global={#1}{#2} }, spath/prefix/tiling~tile/.style={ spath/set~ prefix=g_@@_tile_, }, spath/suffix/tiling~tile/.style={ spath/set~ suffix=_tl, }, expand~ key/.code={ \exp_args:NV \pgfkeysalso #1 } } % \end{macrocode} % \end{macro} % % \subsection{Lindenmayer System} % % This is an implementation of the Lindenmayer System description of Penrose and other tilings as a way of generating tilings from a specific starting seed. % % The implementation uses \Verb+prop+s to store \emph{rules} and \emph{actions}. % The rules are used to expand the starting seed to a certain level, after which the actions are carried out. % The syntax is based on the PGF library, but as we're already using \LaTeX3 it is reimplemented in that. % % \begin{macro}[internal]{\@@_make_lms:Nnnn} % This creates the token list of actions, starting with the seed. % The arguments are: a token list to store the result in, the name of the system, the number of iterations, and the initial state. % \begin{macrocode} \cs_new_nopar:Npn \@@_make_lms:Nnnn #1#2#3#4 { \group_begin: % \end{macrocode} % On the first time round, we start with the given seed. % \begin{macrocode} \tl_set:Nn \l_@@_tmpb_tl {#4} % \end{macrocode} % We repeat the specified number of times. % \begin{macrocode} \prg_replicate:nn {#3} { % \end{macrocode} % Duplicate the current state. % \begin{macrocode} \tl_set_eq:NN \l_@@_tmpa_tl \l_@@_tmpb_tl % \end{macrocode} % Clear the receiving token list. % \begin{macrocode} \tl_clear:N \l_@@_tmpb_tl % \end{macrocode} % Walk through the current list, appending to the receiving list according to the rules. % \begin{macrocode} \tl_map_inline:Nn \l_@@_tmpa_tl { % \end{macrocode} % If a rule exists, copy that. % \begin{macrocode} \tl_set:Nx \l_@@_action_lms_tl {\tl_head:n {##1}} \tl_set:Nx \l_@@_parameters_lms_tl {\tl_tail:n {##1}} \prop_if_in:cVTF {g_@@_#2_lms_rule_prop} \l_@@_action_lms_tl { \prop_get:cVN {g_@@_#2_lms_rule_prop} \l_@@_action_lms_tl \l_@@_tmpc_tl \tl_put_right:Nx \l_@@_tmpb_tl {\tl_use:N \l_@@_tmpc_tl} % {\prop_item:cn {g_@@_#2_lms_rule_prop} {##1} } } { % \end{macrocode} % Otherwise, just copy the token. % \begin{macrocode} \tl_if_single:nTF {##1} { \tl_put_right:Nn \l_@@_tmpb_tl {##1} } { \tl_put_right:Nn \l_@@_tmpb_tl {{##1}} } } } } % \end{macrocode} % We've done all this inside a group, now pass the result outside. % \begin{macrocode} \tl_set:Nn \l_@@_tmpa_tl { \group_end: \tl_set:Nn #1 } \tl_put_right:Nx \l_@@_tmpa_tl {{\tl_use:N \l_@@_tmpb_tl}} \tl_use:N \l_@@_tmpa_tl } \cs_generate_variant:Nn \@@_make_lms:Nnnn {Nnnx} % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\@@_invoke_lms:nn} % This carries out the actions specified by the resulting rules. % \begin{macrocode} \cs_new_nopar:Npn \@@_invoke_lms:nn #1#2 { \group_begin: % \end{macrocode} % Walk through the given list, carrying out the corresponding action if it exists. % If not, look at the default. % Otherwise, just do nothing. % \begin{macrocode} \tl_map_inline:nn {#1} { \tl_set:Nx \l_@@_action_lms_tl {\tl_head:n {##1}} \tl_set:Nx \l_@@_parameters_lms_tl {\tl_tail:n {##1}} \prop_if_in:cVTF {g_@@_#2_lms_action_prop} \l_@@_action_lms_tl { \prop_item:cV {g_@@_#2_lms_action_prop} \l_@@_action_lms_tl } { \prop_if_in:cVT {g_@@_default_lms_action_prop} \l_@@_action_lms_tl { \prop_item:cV {g_@@_default_lms_action_prop} \l_@@_action_lms_tl } } } \group_end: } \cs_generate_variant:Nn \@@_invoke_lms:nn {Vn} % \end{macrocode} % \end{macro} % % % We need some parameters. % \begin{macrocode} \dim_new:N \l_@@_step_dim \dim_set:Nn \l_@@_step_dim {1cm} % \end{macrocode} % % These are the defaults, which will be used in all the rule sets. % \begin{macrocode} \prop_new:N \g_@@_default_lms_action_prop \prop_gput:Nnn \g_@@_default_lms_action_prop {[} {\group_begin:} \prop_gput:Nnn \g_@@_default_lms_action_prop {]} {\group_end:} \prop_gput:Nnn \g_@@_default_lms_action_prop {f} {\pgftransformxshift{\l_@@_step_dim}} \prop_gput:Nnn \g_@@_default_lms_action_prop {b} {\pgftransformxshift{-\l_@@_step_dim}} % \end{macrocode} % % Holds a list of the tiles that actually draw for each tile set % \begin{macrocode} \prop_new:N \g_@@_drawables_lms_prop % \end{macrocode} % % We keep track of the number of tiles. % \begin{macrocode} \int_new:N \g_@@_tile_int \int_new:N \g_@@_tiles_int % \end{macrocode} % % \begin{function}{\TilingDecomposition} % This is the user macro to invoke the decomposition. % The arguments are: optional styles, the name, number of iterations, and starting seed. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_tiling_decomposition:nnnn #1#2#3#4 { \group_begin: \tikzset{ every~ #2~ decomposition/.try, #1 } \@@_make_lms:Nnnx \l_@@_tmpa_tl {#2} {#3} {#4} \@@_count_lms:Vn \l_@@_tmpa_tl {#2} \int_gzero:N \g_@@_tile_int \@@_invoke_lms:Vn \l_@@_tmpa_tl {#2} \group_end: } \cs_new_protected_nopar:Npn \@@_tiling_decomposition:nnn #1#2#3 { \@@_tiling_decomposition:nnnn {}{#1}{#2}{#3} } \cs_generate_variant:Nn \@@_tiling_decomposition:nnn {VVV} \NewDocumentCommand \TilingDecomposition { O{} m m m } { \@@_tiling_decomposition:nnnn {#1}{#2}{#3}{#4} } \tikzset{ pics/decomposition/.style~ n~ args={3}{ code={ \@@_tiling_decomposition:nnn {#1}{#2}{#3} } } } % \end{macrocode} % \end{function} % % \begin{macro}[internal]{\@@_count_lms:nn} % This counts the number of tiles in the string. % \begin{macrocode} \cs_new_nopar:Npn \@@_count_lms:nn #1#2 { \group_begin: \int_gzero:N \g_@@_tiles_int \prop_get:NnNT \g_@@_drawables_lms_prop {#2} \l_@@_tmpa_tl { \tl_map_variable:nNn {#1} \l_@@_tmpb_tl { \tl_set:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpb_tl} \bool_do_while:nn { !\tl_if_empty_p:N \l_@@_tmpb_tl && \tl_if_head_is_group_p:V \l_@@_tmpb_tl } { \tl_set:Nx \l_@@_tmpb_tl {\tl_head:N \l_@@_tmpb_tl} } \tl_if_in:NVT \l_@@_tmpa_tl \l_@@_tmpb_tl { \int_gincr:N \g_@@_tiles_int } } } \group_end: } \cs_generate_variant:Nn \@@_count_lms:nn {Vn} % \end{macrocode} % \end{macro} % % This is a \Verb+\tikzset+ mechanism for setting the dimensions of the tiling. % \begin{macrocode} \tikzset{ tiling~ step/.code={ \dim_set:Nn \l_@@_step_dim {#1} } } % \end{macrocode} % % \begin{macrocode} \ExplSyntaxOff % \end{macrocode} % % \iffalse % % \fi % % % \iffalse %<*penrose> % \fi % % \begin{macrocode} \RequirePackage{tikz} \usetikzlibrary{tilings} \ProvidesFile {tikzlibrarytilings.penrose.code.tex} [2023/06/01 v2.0 TikZ pics for Penrose tiles] % \end{macrocode} % % % Create the pre-defined tile shapes. % % \begin{itemize} % \item Thin Rhombus. % \begin{macrocode} \DefineTile{thin rhombus}{a A B b} { {0 , 0} {cosd(18) , sind(18)} {2*cosd(18) , 0} {cosd(18) , -sind(18)} } % \end{macrocode} % % \item Thick Rhombus. % \begin{macrocode} \DefineTile{thick rhombus}{B a A b} { {0 , 0} {cosd(36) , sind(36)} {2*cosd(36) , 0} {cosd(36) , -sind(36)} } % \end{macrocode} % % \item Dart. % \begin{macrocode} \DefineTile{dart}{c a A C} { {0 , 0} {2*sind(18)*cosd(108) , 2*sind(18)*sind(108)} {2*sind(18) , 0} {2*sind(18)*cosd(108) , -2*sind(18)*sind(108)} } % \end{macrocode} % % \item Kite. % \begin{macrocode} \DefineTile{kite}{a c C A} { {0 , 0} {cosd(36) , sind(36)} {1 , 0} {cosd(36) , -sind(36)} } % \end{macrocode} % % \item Golden Triangle. % \begin{macrocode} \DefineTile{golden triangle}{a c b} { {0 , 0} {cosd(18) , sind(18)} {cosd(18) , -sind(18)} } % \end{macrocode} % % \item Reverse Golden Triangle. % \begin{macrocode} \DefineTile {reverse golden triangle}{B C A} { {0 , 0} {cosd(18) , sind(18)} {cosd(18) , -sind(18)} } % \end{macrocode} % % \item Golden Gnomon % \begin{macrocode} \DefineTile {golden gnomon}{C b A} { {0 , 0} {cosd(36) , sind(36)} {2*cosd(36) , 0} } % \end{macrocode} % % \item Reverse Golden Gnomon % \begin{macrocode} \DefineTile {reverse golden gnomon}{a B c} { {0 , 0} {2*cosd(36) , 0} {cosd(36) , -sind(36)} } % \end{macrocode} % % \item Primary Pentagon (pentagon 5) % \begin{macrocode} \DefineTile {pentagon 5}{a a a a a} { {0 , 0} {cosd(108) , sind(108)} {1+cosd(72)+cosd(144) , sind(72)+sind(144)} {1+cosd(72) , sind(72)} {1 , 0} } % \end{macrocode} % % \item Secondary Pentagon (pentagon 3) % \begin{macrocode} \DefineTile {pentagon 3}{A b a a b} { {0 , 0} {cosd(108) , sind(108)} {1+cosd(72)+cosd(144) , sind(72)+sind(144)} {1+cosd(72) , sind(72)} {1 , 0} } % \end{macrocode} % % \item Tertiary Pentagon (pentagon 2) % \begin{macrocode} \DefineTile {pentagon 2}{d A e c A} { {0 , 0} {cosd(108) , sind(108)} {1+cosd(72)+cosd(144) , sind(72)+sind(144)} {1+cosd(72) , sind(72)} {1 , 0} } % \end{macrocode} % % \item Pentagram % \begin{macrocode} \DefineTile {pentagram}{C E C E C E C E C E} { {1 , 0} {1-cosd(36) , -sind(36)} {1-cosd(36)-cosd(108) , -sind(36)-sind(108)} {cosd(108) , -sind(108)} {-1+3*cosd(108)+cosd(36) , -sind(36)-sind(108)} {-1+2*cosd(108)+cosd(36) , -sind(36)} {-1+2*cosd(108) , 0} {2*cosd(108) , 0} {cosd(108) , sind(108)} {0 , 0} } % \end{macrocode} % % \item Boat % \begin{macrocode} \DefineTile {boat}{C E C E B D B} { {-1+2*cosd(108) , 0} {2*cosd(108) , 0} {cosd(108) , sind(108)} {0 , 0} {1 , 0} {1-cosd(36) , -sind(36)} {-1+2*cosd(108)+cosd(36) , -sind(36)} } % \end{macrocode} % % \item Diamond. % \begin{macrocode} \DefineTile {diamond}{D B B D} { {0 , 0} {cosd(18) , sind(18)} {2*cosd(18) , 0} {cosd(18) , -sind(18)} } % \end{macrocode} % \end{itemize} % % % Place the arcs % \begin{macrocode} \tikzset{ every thin rhombus before path/.code={ \path[every circle arc/.try] (-edge a end) circle[radius=1/4]; \path[every long arc/.try] (-edge b start) circle[radius=1/4]; }, every thick rhombus before path/.code={ \path[every circle arc/.try] (-edge a end) circle[radius=1/4]; \path[every long arc/.try] (-edge B start) circle[radius=3/4]; }, every kite before path/.code={ \path[every circle arc/.try] (-edge a start) circle[radius=2/(sqrt(5)+1)]; \path[every long arc/.try] (-edge c end) circle[radius=2/(3+sqrt(5))]; }, every dart before path/.code={ \path[every circle arc/.try] (-edge a end) circle[radius=1 - 2/(sqrt(5)+1)]; \path[every long arc/.try] (-edge c start) circle[radius=2/(sqrt(5)+1) - 2/(3+sqrt(5))]; } } % \end{macrocode} % % Now bake the tiles. % % \begin{macrocode} \BakeTile {thin rhombus} \BakeTile {thick rhombus} \BakeTile {dart} \BakeTile {kite} \BakeTile {golden triangle} \BakeTile {reverse golden triangle} \BakeTile {golden gnomon} \BakeTile {reverse golden gnomon} \BakeTile {pentagon 5} \BakeTile {pentagon 3} \BakeTile {pentagon 2} \BakeTile {pentagram} \BakeTile {boat} \BakeTile {diamond} % \end{macrocode} % % % \subsection{Lindenmayer System} % % \begin{macrocode} \ExplSyntaxOn % \end{macrocode} % % These are the rules for generating rhombus tilings with the Lindenmayer System procedure. % % \begin{macrocode} \prop_new:N \g_@@_rhombus_lms_rule_prop \prop_gput:Nnn \g_@@_rhombus_lms_rule_prop {T} {[f*sT][f>g]} \prop_gput:Nnn \g_@@_rhombus_lms_rule_prop {t} {[f_st][f>G]} \prop_gput:Nnn \g_@@_rhombus_lms_rule_prop {G} {[f+sG][sf>g][sf*sT]} \prop_gput:Nnn \g_@@_rhombus_lms_rule_prop {g} {[f-sg][sf>G][sf_st]} % \end{macrocode} % % These are the rules for generating kite and dart tilings. % \begin{macrocode} \prop_new:N \g_@@_kite_lms_rule_prop \prop_gput:Nnn \g_@@_kite_lms_rule_prop {T} {[f*sT][f>st][+sg]} \prop_gput:Nnn \g_@@_kite_lms_rule_prop {t} {[f_st][f>sT][-sG]} \prop_gput:Nnn \g_@@_kite_lms_rule_prop {G} {[f*+sG][sT]} \prop_gput:Nnn \g_@@_kite_lms_rule_prop {g} {[f-_sg][st]} % \end{macrocode} % % These are the rules for generating pentagon tilings. % \begin{macrocode} \prop_new:N \g_@@_pentagon_lms_rule_prop \prop_gput:Nnn \g_@@_pentagon_lms_rule_prop {P} {[s>P][1sF+Q][1+sF+Q][1*sF+Q][1-sF+Q][1_sF+Q]} % pentagon 5 \prop_gput:Nnn \g_@@_pentagon_lms_rule_prop {Q} {[s>P][1+sFR][1*sF*R][1-sF+Q][1_sF+Q][1sF+Q][->fsD]} % pentagon 3 \prop_gput:Nnn \g_@@_pentagon_lms_rule_prop {R} {[s>P][1-sF+Q][1+sF*R][1*sFR][1_sF*R][1sFR][_>fsD][>fsD]} % pentagon 2 \prop_gput:Nnn \g_@@_pentagon_lms_rule_prop {G} { [s>G] [se[>d+R][e1B]] [+se[>d+R][e1B]] [-se[>d+R][e1B]] [*se[>d+R][e1B]] [_se[>d+R][e1B]] } % pentagram \prop_gput:Nnn \g_@@_pentagon_lms_rule_prop {B} { [s>G] [se[>d+R][e1B]] [+se[>d+R][e1B]] [-se[>d+R][e1B]] } % boat \prop_gput:Nnn \g_@@_pentagon_lms_rule_prop {D} {[s>d+R][s>eG][se1B]} % diamond % \end{macrocode} % % Each of the standard tilings can also be drawn using triangles using the same rules. % \begin{macrocode} \prop_gset_eq:NN \g_@@_rtriangle_lms_rule_prop \g_@@_rhombus_lms_rule_prop \prop_gset_eq:NN \g_@@_ktriangle_lms_rule_prop \g_@@_kite_lms_rule_prop % \end{macrocode} % % These are the lists of tokens that actually draw things % \begin{macrocode} \prop_gput:Nnn \g_@@_drawables_lms_prop {rhombus} {TG} \prop_gput:Nnn \g_@@_drawables_lms_prop {kite} {Tg} \prop_gput:Nnn \g_@@_drawables_lms_prop {rtriangle} {TtGg} \prop_gput:Nnn \g_@@_drawables_lms_prop {ktriangle} {TtGg} \prop_gput:Nnn \g_@@_drawables_lms_prop {pentagon} {PQRGBD} % \end{macrocode} % % % These hold the various actions. % \begin{macrocode} \prop_new:N \g_@@_rhombus_lms_action_prop \prop_new:N \g_@@_kite_lms_action_prop \prop_new:N \g_@@_rtriangle_lms_action_prop \prop_new:N \g_@@_ktriangle_lms_action_prop \prop_new:N \g_@@_pentagon_lms_action_prop % \end{macrocode} % % The rhombus rules need a variety of turns. % \begin{macrocode} \prop_gput:Nnn \g_@@_rhombus_lms_action_prop {+} {\pgftransformrotate{144}} \prop_gput:Nnn \g_@@_rhombus_lms_action_prop {*} {\pgftransformrotate{108}} \prop_gput:Nnn \g_@@_rhombus_lms_action_prop {-} {\pgftransformrotate{216}} \prop_gput:Nnn \g_@@_rhombus_lms_action_prop {_} {\pgftransformrotate{252}} \prop_gput:Nnn \g_@@_rhombus_lms_action_prop {>} {\pgftransformrotate{180}} \prop_gput:Nnn \g_@@_rhombus_lms_action_prop {s} { \fp_set:Nn \l_@@_tmpa_fp { 2 * sind(18) * \l_@@_step_dim } \dim_set:Nn \l_@@_step_dim {\fp_to_dim:N \l_@@_tmpa_fp} } % \end{macrocode} % % Up to now, the actions for the rhombus and its triangle replacement are the same. % \begin{macrocode} \prop_gset_eq:NN \g_@@_rtriangle_lms_action_prop \g_@@_rhombus_lms_action_prop % \end{macrocode} % % Now we do the actions that actually draw something. % \begin{macrocode} \prop_gput:Nnn \g_@@_rhombus_lms_action_prop {T} { \group_begin: % \end{macrocode} % As we go through, we keep track of how many tiles we've drawn. % \begin{macrocode} \int_gincr:N \g_@@_tile_int % \end{macrocode} % Set up the position, size, and angle correctly. % \begin{macrocode} \pgftransformrotate{198} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim*2*cosd(18)} \pgftransformxshift{-\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} % \end{macrocode} % Now we draw the thin rhombus, applying every style we can possibly imagine. % The \Verb+tile+ style gets the current tile and total tile numbers passed to it. % \begin{macrocode} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ thin~ rhombus/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{thin~rhombus} \group_end: } % \end{macrocode} % % Same for the thick rhombus. % \begin{macrocode} \prop_gput:Nnn \g_@@_rhombus_lms_action_prop {G} { \group_begin: \int_gincr:N \g_@@_tile_int \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)/(2*cosd(36))} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ thick~ rhombus/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{thick~rhombus} \group_end: } % \end{macrocode} % % Now we do the same for the kite and dart tiling. % \begin{macrocode} \prop_gput:Nnn \g_@@_kite_lms_action_prop {+} {\pgftransformrotate{36}} \prop_gput:Nnn \g_@@_kite_lms_action_prop {*} {\pgftransformrotate{108}} \prop_gput:Nnn \g_@@_kite_lms_action_prop {-} {\pgftransformrotate{-36}} \prop_gput:Nnn \g_@@_kite_lms_action_prop {_} {\pgftransformrotate{-108}} \prop_gput:Nnn \g_@@_kite_lms_action_prop {>} {\pgftransformrotate{180}} \prop_gput:Nnn \g_@@_kite_lms_action_prop {s} { \fp_set:Nn \l_@@_tmpa_fp { 2 * sind(18) * \l_@@_step_dim } \dim_set:Nn \l_@@_step_dim {\fp_to_dim:N \l_@@_tmpa_fp} } % \end{macrocode} % % \begin{macrocode} \prop_gset_eq:NN \g_@@_ktriangle_lms_action_prop \g_@@_kite_lms_action_prop % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_kite_lms_action_prop {T} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{36} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ kite/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{kite} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_kite_lms_action_prop {g} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{144} \pgftransformxshift{-\l_@@_step_dim * 2 * sin(18)} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ dart/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{dart} \group_end: } % \end{macrocode} % % Now we set up the actions for the triangle variations. % \begin{macrocode} \prop_gput:Nnn \g_@@_rtriangle_lms_action_prop {T} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{18} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ reverse~ golden~ triangle/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{reverse~ golden~ triangle} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_rtriangle_lms_action_prop {t} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{-18} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ golden~ triangle/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{golden~ triangle} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_rtriangle_lms_action_prop {G} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{180} \pgftransformxshift{-\l_@@_step_dim} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)/(2*cosd(36))} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ reverse~ golden~ gnomon/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{reverse~ golden~ gnomon} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_rtriangle_lms_action_prop {g} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{180} \pgftransformxshift{-\l_@@_step_dim} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)/(2*cosd(36))} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ golden~ gnomon/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{golden~ gnomon} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_ktriangle_lms_action_prop {T} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{18} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ reverse~ golden~ triangle/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{reverse~ golden~ triangle} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_ktriangle_lms_action_prop {t} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{-18} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ golden~ triangle/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{golden~ triangle} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_ktriangle_lms_action_prop {G} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{180} \pgftransformxshift{-\l_@@_step_dim} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)/(2*cosd(36))} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ reverse~ golden~ gnomon/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{reverse~ golden~ gnomon} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_ktriangle_lms_action_prop {g} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{180} \pgftransformxshift{-\l_@@_step_dim} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)/(2*cosd(36))} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ golden~ gnomon/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{golden~ gnomon} \group_end: } % \end{macrocode} % % Now we do the same for the pentagonal tilings. % % The rules need a variety of turns. % \begin{macrocode} \int_new:N \l_@@_pentagon_parity_int \seq_new:N \l_@@_pentagon_parity_seq \seq_set_from_clist:Nn \l_@@_pentagon_parity_seq {odd,even} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {1} { \int_set:Nn \l_@@_pentagon_parity_int {3 - \l_@@_pentagon_parity_int} } \tikzset{ every~ pentagon~ decomposition/.code={% \int_set:Nn \l_@@_pentagon_parity_int {2} } } \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {+} {\pgftransformrotate{72}} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {*} {\pgftransformrotate{144}} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {-} {\pgftransformrotate{288}} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {_} {\pgftransformrotate{216}} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {>} {\pgftransformrotate{180}} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {|} {\pgftransformxscale{-1}} % \end{macrocode} % The scale factor is different. % \begin{macrocode} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {s} { \fp_set:Nn \l_@@_tmpa_fp { 1/(2 + 2 * cosd(72) ) * \l_@@_step_dim } \dim_set:Nn \l_@@_step_dim {\fp_to_dim:N \l_@@_tmpa_fp} } % \end{macrocode} % And we tend to work better vertically. % \begin{macrocode} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {f} { \fp_set:Nn \l_@@_tmpa_fp { tand(54)/2 * \l_@@_step_dim } \pgftransformyshift{\fp_to_dim:N \l_@@_tmpa_fp} } \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {F} { \fp_set:Nn \l_@@_tmpa_fp { tand(54) * \l_@@_step_dim } \pgftransformyshift{\fp_to_dim:N \l_@@_tmpa_fp} } \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {d} { \fp_set:Nn \l_@@_tmpa_fp { (tand(54)/2 - tand(72)/2 + sind(36) ) * \l_@@_step_dim } \pgftransformyshift{\fp_to_dim:N \l_@@_tmpa_fp} } \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {e} { \fp_set:Nn \l_@@_tmpa_fp { tand(54) * cosd(36) * \l_@@_step_dim } \pgftransformyshift{\fp_to_dim:N \l_@@_tmpa_fp} } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {P} { \group_begin: \int_gincr:N \g_@@_tile_int \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/2} \pgftransformxshift{-\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim*tand(54)/2} \pgftransformyshift{-\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ pentagon/.try, every~ \seq_item:Nn \l_@@_pentagon_parity_seq {\l_@@_pentagon_parity_int} \space pentagon/.try, every~ pentagon~ 5/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{pentagon~5} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {Q} { \group_begin: \int_gincr:N \g_@@_tile_int \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/2} \pgftransformxshift{-\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim*tand(54)/2} \pgftransformyshift{-\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ pentagon/.try, every~ \seq_item:Nn \l_@@_pentagon_parity_seq {\l_@@_pentagon_parity_int} \space pentagon/.try, every~ pentagon~ 3/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{pentagon~3} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {R} { \group_begin: \int_gincr:N \g_@@_tile_int \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/2} \pgftransformxshift{-\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim*tand(54)/2} \pgftransformyshift{-\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ pentagon/.try, every~ \seq_item:Nn \l_@@_pentagon_parity_seq {\l_@@_pentagon_parity_int} \space pentagon/.try, every~ pentagon~ 2/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{pentagon~2} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {G} { \group_begin: \int_gincr:N \g_@@_tile_int % \pgftransformrotate{198} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim*cosd(72)} \pgftransformxshift{\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim*tand(54)*cosd(72)} \pgftransformyshift{\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ pentagram/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{pentagram} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {B} { \group_begin: \int_gincr:N \g_@@_tile_int % \pgftransformrotate{198} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim*cosd(72)} \pgftransformxshift{\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim*tand(54)*cosd(72)} \pgftransformyshift{\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ boat/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{boat} \group_end: } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_pentagon_lms_action_prop {D} { \group_begin: \int_gincr:N \g_@@_tile_int \pgftransformrotate{90} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim*cosd(18)} \pgftransformxshift{-\fp_to_dim:N \l_@@_tmpa_fp} \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ diamond/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{diamond} \group_end: } % \end{macrocode} % % \begin{macrocode} \ExplSyntaxOff % \end{macrocode} % % \iffalse % % \fi % % \iffalse %<*polykite> % \fi % % \begin{macrocode} \RequirePackage{tikz} \usetikzlibrary{tilings} \ProvidesFile {tikzlibrarytilings.polykite.code.tex} [2023/06/01 v2.0 TikZ pics for Aperiodical Polykite tiles] % \end{macrocode} % % \begin{function}{\DefinePolykiteTile} % Define one of the family of polykite tiles. % Needs a name and length parameters. % A star option switches the side labels to enable the hat-turtle pairing of a tile with its ``opposite''. % \begin{macrocode} \DeclareDocumentCommand \DefinePolykiteTile {s m m m} { \IfBooleanTF {#1} { \DefineTile {#2} {2 2 1 1 2 2 1 1 1 1 2 2 1 1} } { \DefineTile {#2} {1 1 2 2 1 1 2 2 2 2 1 1 2 2} } { {0 : #4} ++{90 : #3} ++{150 : #3} ++{240 : #4} ++{180 : #4} ++{-90 : #3} ++{210 : #3} ++{-60 : #4} ++{0 : #4} ++{0 : #4} ++{60 : #4} ++{-30 : #3} ++{30 : #3} ++{120 : #4} } } % \end{macrocode} % \end{function} % % Some predefined tiles. % The aperiodical hat and turtle can be swapped in for each other as they use the same edge definitions. % The spectral hat and turtle are designed to be used in the same diagram. % Technically, the spectral and aperiodical hats are the same, but I figured it better to have two names for the two uses. % The spectre uses the alternating edge scheme. % % \begin{itemize} % \item Aperiodical and Spectral Hat. % \begin{macrocode} \DefinePolykiteTile{aperiodical hat}{sqrt(3)/2}{1/2} \DefinePolykiteTile{spectral hat}{sqrt(3)/2}{1/2} % \end{macrocode} % \item Aperiodical and Spectral Turtles. % \begin{macrocode} \DefinePolykiteTile{aperiodical turtle}{1/2}{sqrt(3)/2} \DefinePolykiteTile*{spectral turtle}{1/2}{sqrt(3)/2} % \end{macrocode} % \item Aperiodical Spectre. % \begin{macrocode} \DefineTile {spectre} {a A a A a A a A a A a A a A} { {0 : .75} ++{90 : .75} ++{150 : .75} ++{240 : .75} ++{180 : .75} ++{-90 : .75} ++{210 : .75} ++{-60 : .75} ++{0 : .75} ++{0 : .75} ++{60 : .75} ++{-30 : .75} ++{30 : .75} ++{120 : .75} } % \end{macrocode} % % \item Meta Clusters % % The mapping between the notation in the \href{preprint}{https://arxiv.org/abs/2303.10798} is: % % \begin{align*} % A^+, A^- &\mapsto a, A \\ % B^+, B^- &\mapsto b, B\\ % F^+, F^- &\mapsto c, C\\ % X^+, X^- &\mapsto d, D\\ % L &\mapsto 1 % \end{align*} % % \begin{macrocode} \DefineTile{meta cluster T}{A A b} { { -1.5 , -sqrt(3)/2 } { 1.5 , -sqrt(3)/2 } { 0 , sqrt(3) } } \DefineTile{meta cluster P}{1 D d A 1 D d b} { { -2.5, sqrt(3)/2 } { -2, 0 } { -1.5, -sqrt(3)/2 } { -0.5 , -sqrt(3)/2 } { 2.5 , -sqrt(3)/2 } { 2 , 0 } { 1.5 , sqrt(3)/2 } { .5 , sqrt(3)/2 } } \DefineTile{meta cluster F}{1 D d 1 D c C d b} { { -2.5, sqrt(3)/2 } { -2, 0 } { -1.5, -sqrt(3)/2 } { -0.5 , -sqrt(3)/2 } { .5 , -sqrt(3)/2 } { 1.5 , -sqrt(3)/2 } { 2 , 0 } { 1.5 , sqrt(3)/2 } { .5 , sqrt(3)/2 } } \DefineTile{meta cluster H}{B D d B D d a D d} { { -2, -sqrt(3) } { 1, -sqrt(3) } { 2, -sqrt(3) } { 2.5, -sqrt(3)/2 } { 1, sqrt(3)} { .5 , 3*sqrt(3)/2 } { -.5 , 3*sqrt(3)/2 } { -2, 0 } { -2.5, -sqrt(3)/2 } } % \end{macrocode} % \item Super Clusters % % \begin{macrocode} \DefineTile{super cluster T}{A A b} { { -30 : 3 * (1 + sqrt(5))/2 / sqrt(3) } { 90 : 3 * (1 + sqrt(5))/2 / sqrt(3) } { 210 : 3 * (1 + sqrt(5))/2 / sqrt(3) } } % 1 + 3phi, 1 + 2phi \DefineTile{super cluster P}{1 D d A 1 D d b} { { - 1.75 - sqrt(5), (sqrt(5)/2 + 1) * sqrt(3)/2 } ++{ -60 : 1 + sqrt(5) } ++{ -60 : 1} ++{ 1, 0} ++{ 3*(1 + sqrt(5))/2, 0 } ++{ 120 : 1 + sqrt(5) } ++{ 120 : 1 } ++{ -1, 0 } } \DefineTile{super cluster F}{1 D d 1 D c C d b} { { - 1.75 - sqrt(5), (sqrt(5)/2 + 1) * sqrt(3)/2 } ++{ -60 : 1 + sqrt(5) } ++{ -60 : 1} ++{ 1, 0} ++{ 1 + sqrt(5), 0 } ++{ 1, 0 } +{ -.75 + (2 + sqrt(5)) * sqrt(3)/4 * sqrt(3)/3, (2 + sqrt(5)) * sqrt(3)/4 + 3/4 * sqrt(3)/3 } ++{ -1.5, (2 + sqrt(5)) * sqrt(3)/2 } ++{ -1, 0 } } \DefineTile{super cluster H}{B D d B D d a D d} { {1.75 + 3*sqrt(5)/4, -(1 + sqrt(5))*sqrt(3)/4} ++{120 : 3*(1+sqrt(5))/2 } ++{120 : 1 } ++{-1,0} ++{240 : 3*(1+sqrt(5))/2} ++{240 : 1} ++{300 : 1} ++{ 3*(1+sqrt(5))/2, 0 } ++{1, 0} ++{60 : 1} } % \end{macrocode} % \item Subclusters % % \begin{macrocode} \DefineTile{subcluster H}{B B a} { { 0, 0 } { 3, 0 } { 60 : 3 } } \DefineTile{subcluster T}{A A b} { { 0, 0 } { 3, 0 } { 60 : 3 } } \DefineTile{subcluster P}{ 1 A 1 b } { { 0, 0 } { 1, 0 } { 4, 0 } { 3, 0 } } \DefineTile{subcluster F}{ 1 1 f F b } { { 0, 0 } { 1, 0 } +{ 60 : 1 } { 2, 0 } { 3, 0 } } % \end{macrocode} % \end{itemize} % % The P and F subclusters have no area, so clipping against them is not helpful. % \begin{macrocode} \tikzset{ no clip/.code={% \tikz@addmode{\tikz@mode@clipfalse}% }, every subcluster P clip/.style={no clip}, every subcluster F clip/.style={no clip}, } % \end{macrocode} % % % \begin{macrocode} \BakeTile {aperiodical hat} \BakeTile {aperiodical turtle} \BakeTile {spectral hat} \BakeTile {spectral turtle} \BakeTile {spectre} \BakeTile {meta cluster T} \BakeTile {meta cluster P} \BakeTile {meta cluster F} \BakeTile {meta cluster H} \BakeTile {super cluster T} \BakeTile {super cluster P} \BakeTile {super cluster F} \BakeTile {super cluster H} % \end{macrocode} % % The subclusters are deformed by default. % % \begin{macrocode} \ExplSyntaxOn \clist_map_inline:nn {a,A,b,B,f,F} { \tl_new:c {g_@@_side_polykite_#1_tl} \tl_if_exist:cF {g_@@_side_#1_tl} { \tl_new:c {g_@@_side_#1_tl} } } \tl_gset:cn {g_@@_side_polykite_A_tl} { \pgfsyssoftpath@movetotoken {0pt}{-0.3333332942822268pt} \pgfsyssoftpath@linetotoken {0.0833331478405773pt}{-0.1889954840909892pt} \pgfsyssoftpath@linetotoken {0.3333332942822268pt}{-0.3333332942822268pt} \pgfsyssoftpath@linetotoken {0.5833333235705567pt}{-0.1889954840909892pt} \pgfsyssoftpath@linetotoken {0.6666667057177732pt}{-0.3333332942822268pt} \pgfsyssoftpath@linetotoken {1pt}{-0.3333332942822268pt} } \tl_gset:cn {g_@@_side_polykite_a_tl} { \pgfsyssoftpath@movetotoken {0pt}{0.33333pt} \pgfsyssoftpath@linetotoken {0.33333pt}{0.33333pt} \pgfsyssoftpath@linetotoken {0.41667pt}{0.189pt} \pgfsyssoftpath@linetotoken {0.66667pt}{0.33333pt} \pgfsyssoftpath@linetotoken {0.91667pt}{0.189pt} \pgfsyssoftpath@linetotoken {1pt}{0.33333pt} } \tl_gset:cn {g_@@_side_polykite_B_tl} { \pgfsyssoftpath@movetotoken {0pt}{0pt} \pgfsyssoftpath@linetotoken {0.3333332942822268pt}{0pt} \pgfsyssoftpath@linetotoken {0.4166665592761237pt}{0.1443378101912376pt} \pgfsyssoftpath@linetotoken {0.6666667057177732pt}{0pt} \pgfsyssoftpath@linetotoken {0.9166666178527835pt}{0.1443378101912376pt} \pgfsyssoftpath@linetotoken {1pt}{0pt} } \tl_gset:cn {g_@@_side_polykite_b_tl} { \pgfsyssoftpath@movetotoken {0pt}{0pt} \pgfsyssoftpath@linetotoken {0.08333pt}{-0.14433pt} \pgfsyssoftpath@linetotoken {0.33333pt}{0pt} \pgfsyssoftpath@linetotoken {0.58333pt}{-0.14433pt} \pgfsyssoftpath@linetotoken {0.66667pt}{0pt} \pgfsyssoftpath@linetotoken {1pt}{0pt} } \tl_gset:cn {g_@@_side_polykite_F_tl} { \pgfsyssoftpath@movetotoken {0pt}{-2.00000070292pt} \pgfsyssoftpath@linetotoken {0.74999982427pt}{-1.566987221617321pt} \pgfsyssoftpath@linetotoken {1pt}{-2.00000070292pt} } \tl_gset:cn {g_@@_side_polykite_f_tl} { \pgfsyssoftpath@movetotoken {0pt}{2pt} \pgfsyssoftpath@linetotoken {0.25pt}{1.56699pt} \pgfsyssoftpath@linetotoken {1pt}{2pt} } \clist_map_inline:nn {a,A,b,B,f,F} { \tl_gclear_new:c {g_@@_side_backup_#1_tl} \tl_gset_eq:cc {g_@@_side_backup_#1_tl} {g_@@_side_#1_tl} \tl_gclear_new:c {g_@@_side_#1_tl} \tl_gset_eq:cc {g_@@_side_#1_tl}{g_@@_side_polykite_#1_tl} } \BakeTile{subcluster~ H} \BakeTile{subcluster~ T} \BakeTile{subcluster~ P} \BakeTile{subcluster~ F} \clist_map_inline:nn {a,A,b,B,f,F} { \tl_gset_eq:cc {g_@@_side_#1_tl} {g_@@_side_backup_#1_tl} } % \end{macrocode} % % \subsection{Lindenmayer System} % % These are the rules for generating the super cluster tilings with the Lindenmayer System procedure. % % \begin{macro}[internal]{\@@_place_cluster_tile:nn} % Useful auxiliary for placing a cluster tile from a particular set % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_place_cluster_tile:nn #1#2 { \group_begin: \int_gincr:N \g_@@_tile_int \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \pgftransformscale{\fp_use:N \l_@@_tmpa_fp} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \UseTile[ every~ tile/.try, every~ #1~#2/.try, tile~ \int_use:N \g_@@_tile_int/.try, tile/.try/.expand~ once=\l_@@_tmpc_tl ]{#1~ #2} \group_end: } \cs_generate_variant:Nn \@@_place_cluster_tile:nn {Vn} % \end{macrocode} % \end{macro} % % % \begin{macrocode} \prop_new:N \g_@@_supercluster_lms_rule_prop \prop_gput:Nnn \g_@@_supercluster_lms_rule_prop {T} { [s H] } \prop_gput:Nnn \g_@@_supercluster_lms_rule_prop {H} { [s {r{-60}} T] [s {x{\fp_to_decimal:n{1}}} {y{\fp_to_decimal:n{(1+2*\c_@@_phi_fp)}}} H] [s {x{\fp_to_decimal:n{-2-3*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{-\c_@@_phi_fp}}} H] [s {x{\fp_to_decimal:n{1+3*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{-1-\c_@@_phi_fp}}} {r{-120}} H] [s {x{\fp_to_decimal:n{-1.5-3.5*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{2.5*\c_@@_phi_fp+1.5}}} {r{-120}} P] [s {x{\fp_to_decimal:n{-1.5-2*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{-1.5-3*\c_@@_phi_fp}}} {r{180}} P] [s {x{\fp_to_decimal:n{3+5.5*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{.5*\c_@@_phi_fp}}} {r{120}} P] [s {x{\fp_to_decimal:n{-4.5-6.5*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{.5-.5*\c_@@_phi_fp}}} {r{-120}} F] [s {x{\fp_to_decimal:n{1.5+4*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{-2.5-3*\c_@@_phi_fp}}} F] [s {x{\fp_to_decimal:n{3+2.5*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{2+3.5*\c_@@_phi_fp}}} {r{120}} F] } \prop_gput:Nnn \g_@@_supercluster_lms_rule_prop {P} { [s {r{60}} P] [s {x{\fp_to_decimal:n{2.5+3.5*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{-.5-.5*\c_@@_phi_fp}}} {r{-120}} H] [s {x{\fp_to_decimal:n{-2.5-3.5*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{.5+.5*\c_@@_phi_fp}}} {r{180}} H] [s {x{\fp_to_decimal:n{4.5+6*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{.5+\c_@@_phi_fp}}} {r{120}} F] [s {x{\fp_to_decimal:n{-4.5-6*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{-.5-\c_@@_phi_fp}}} {r{-60}} F] } \prop_gput:Nnn \g_@@_supercluster_lms_rule_prop {F} { [s {r{60}} P] [s {x{\fp_to_decimal:n{2.5+3.5*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{-.5-.5*\c_@@_phi_fp}}} {r{-120}} H] [s {x{\fp_to_decimal:n{-2.5-3.5*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{.5+.5*\c_@@_phi_fp}}} {r{180}} H] [s {x{\fp_to_decimal:n{4.5+6*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{.5+\c_@@_phi_fp}}} {r{120}} F] [s {x{\fp_to_decimal:n{-4.5-6*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{-.5-\c_@@_phi_fp}}} {r{-60}} F] [s {x{\fp_to_decimal:n{3+4.5*\c_@@_phi_fp}}} {y{\fp_to_decimal:n{-2-2.5*\c_@@_phi_fp}}} F] } % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_drawables_lms_prop {supercluster} {HTPF} % \end{macrocode} % % \begin{macrocode} \fp_const:Nn \c_@@_phi_fp {(1 + sqrt(5))/2} \prop_new:N \g_@@_supercluster_lms_action_prop \prop_gput:Nnn \g_@@_supercluster_lms_action_prop {r} { \pgftransformrotate{\l_@@_parameters_lms_tl} } \prop_gput:Nnn \g_@@_supercluster_lms_action_prop {x} { \pgftransformxshift{ \fp_to_dim:n {.5 * (\l_@@_parameters_lms_tl) * \l_@@_step_dim} } } \prop_gput:Nnn \g_@@_supercluster_lms_action_prop {y} { \pgftransformyshift{ \fp_to_dim:n {.5 * sqrt(3) * (\l_@@_parameters_lms_tl) * \l_@@_step_dim} } } \prop_gput:Nnn \g_@@_supercluster_lms_action_prop {s} { \fp_set:Nn \l_@@_tmpa_fp { \l_@@_step_dim / \c_@@_phi_fp / \c_@@_phi_fp } \dim_set:Nn \l_@@_step_dim {\fp_to_dim:N \l_@@_tmpa_fp} } \prop_gput:Nnn \g_@@_supercluster_lms_action_prop {H} { \@@_place_cluster_tile:nn {super~ cluster}{H} } \prop_gput:Nnn \g_@@_supercluster_lms_action_prop {T} { \@@_place_cluster_tile:nn {super~ cluster}{T} } \prop_gput:Nnn \g_@@_supercluster_lms_action_prop {P} { \@@_place_cluster_tile:nn {super~ cluster}{P} } \prop_gput:Nnn \g_@@_supercluster_lms_action_prop {F} { \@@_place_cluster_tile:nn {super~ cluster}{F} } % \end{macrocode} % % % Parameters: % \begin{enumerate} % \item Cluster type (super cluster, meta cluster, subcluster) % \item This tile type (H, T, P, F) % \item This tile's name % \item Alignment tile's name % \item Edge to align along % \item Edge to align with % \end{enumerate} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_place_cluster_tile_as_pic:nnnnnn #1#2#3#4#5#6 { \group_begin: \int_gincr:N \g_@@_tile_int \fp_set:Nn \l_@@_tmpa_fp {\l_@@_step_dim/(1cm)} \tl_set:Nx \l_@@_tmpc_tl { {\int_use:N \g_@@_tile_int} {\int_use:N \g_@@_tiles_int} } \tl_clear:N \l_@@_tmpa_tl \tl_put_right:Nn \l_@@_tmpa_tl { \pic[ every~ tile/.try, every~ #1~#2/.try, } \tl_put_right:Nx \l_@@_tmpa_tl { tile~ \int_use:N \g_@@_tile_int/.try, tile/.try=\l_@@_tmpc_tl, scale=\fp_use:N \l_@@_tmpa_fp, } \tl_put_right:Nn \l_@@_tmpa_tl { name=#3, } \tl_if_empty:nTF {#4} { \tl_put_right:Nn \l_@@_tmpa_tl { first~ tile/.try, } } { \tl_put_right:Nn \l_@@_tmpa_tl { align~ with=#4~along~#5 } \tl_if_single:nF {#6} { \tl_put_right:Nx \l_@@_tmpa_tl { \c_space_tl using~\tl_tail:n {#6} } } \tl_put_right:Nn \l_@@_tmpa_tl {,} } \tl_put_right:Nn \l_@@_tmpa_tl { #1~ #2 ]; } \tl_use:N \l_@@_tmpa_tl \group_end: } \cs_generate_variant:Nn \@@_place_cluster_tile_as_pic:nnnnnn { Vnnnnn, VnVnnn, VnVVnn } \tikzset{ cluster~ type/.initial=super~ cluster, first~ file/.style={transform~ shape} } \prop_new:N \g_@@_cluster_lms_rule_prop % \end{macrocode} % % The first set of rules govern when the tile being replaced is a root tile, in which case one of the new tiles becomes the new root and all others are placed with respect to them. % % It's convenient for code readability to have aliases for the labels for the parent and adjoining tiles, which are stored in the \Verb!\l_@@_parameters_lms_tl! token list. % \begin{macrocode} \cs_new_nopar:Npn \@@_tile_label: { \tl_item:Nn \l_@@_parameters_lms_tl {1} } \cs_new_nopar:Npn \@@_adjoint_label: { \tl_item:Nn \l_@@_parameters_lms_tl {2} } % \end{macrocode} % % A single \(T\) tile is replaced by a single \(H\) tile % \begin{macrocode} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {T} { [s {H{\@@_tile_label:0}{}}] } % \end{macrocode} % % An \(H\) tile is replaced by \(10\) tiles, consisting of a \(T\) tile and \(3\) each of \(H\), \(P\), and \(F\). % \begin{macrocode} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {H} { [s {r{-60}} {T{\@@_tile_label:0}{}}] [{ {HTa{A1}} {\@@_tile_label:1} {\@@_tile_label:0} }] [{ {HTa{A2}} {\@@_tile_label:2} {\@@_tile_label:0} }] [{ {HT{B1}b} {\@@_tile_label:3} {\@@_tile_label:0} }] [{ {PHb{B2}} {\@@_tile_label:4} {\@@_tile_label:1} }] [{ {PHb{B2}} {\@@_tile_label:5} {\@@_tile_label:2} }] [{ {PHAa} {\@@_tile_label:6} {\@@_tile_label:3} }] [{ {FHb{B1}} {\@@_tile_label:7} {\@@_tile_label:1} }] [{ {FHb{B1}} {\@@_tile_label:8} {\@@_tile_label:2} }] [{ {FHb{B2}} {\@@_tile_label:9} {\@@_tile_label:3} }] } % \end{macrocode} % % Lastly, the \(P\) and \(F\) tile substitutions. % \begin{macrocode} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {P} { [s {r{60}} {P{\@@_tile_label:0}{}}] [{ {HPaA} {\@@_tile_label:1} {\@@_tile_label:0} }] [{ {HP{B2}b} {\@@_tile_label:2} {\@@_tile_label:0} }] [{ {FHb{B2}} {\@@_tile_label:3} {\@@_tile_label:1} }] [{ {FHb{B1}} {\@@_tile_label:4} {\@@_tile_label:2} }] } \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {F} { [s {r{60}} {P{\@@_tile_label:0}{}}] [{ {HPaA} {\@@_tile_label:1} {\@@_tile_label:0} }] [{ {HP{B2}b} {\@@_tile_label:2} {\@@_tile_label:0} }] [{ {FHb{B2}} {\@@_tile_label:3} {\@@_tile_label:1} }] [{ {FHb{B1}} {\@@_tile_label:4} {\@@_tile_label:2} }] [{ {FHb{B1}} {\@@_tile_label:5} {\@@_tile_label:1} }] } % \end{macrocode} % % The rest of the rules are for when the tile being replaced was itself positioned by aligning it with another tile. % For these tiles, one of its edge tiles will be its root and positioned alongside one of the edge tiles of the replacement of the original tile's alignment tile. % Then all the other tiles are positioned out from that root. % The labelling has to be the same regardless of the order of drawing the tiles. % % Not every edge pairing is necessary to generate a pattern as the edges that can be created are all between \(A^\pm\) edges and between \(B^\pm\) edges. % However, to avoid errors in case they are part of the seed then for now we create blank substitution rules that will effectively remove any such rogue elements. % \begin{macrocode} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {TH{A1}a} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {TH{A2}a} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {THb{B1}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {THb{B2}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {HTa{A1}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {HTa{A2}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {HT{B1}b} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {HT{B2}b} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {HPaA} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {HP{B1}b} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {HP{B2}b} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {HF{B1}b} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {HF{B2}b} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {PHAa} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {PHb{B1}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {PHb{B2}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {PF{11}{11}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {PF{12}{11}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {PF{11}{12}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {PF{12}{12}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FHb{B1}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FHb{B2}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FP{11}{11}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FP{12}{11}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FP{11}{12}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FP{12}{12}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FFfF} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FFFf} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FF{11}{11}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FF{12}{11}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FF{11}{12}} {} \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {FF{12}{12}} {} % \end{macrocode} % % To help create the rules then we start with some helper macros. % Each of these creates the substitution rule for a tile given certain information about where the parent tile is positioned. % Most of the substitution information consists of placing the tiles next to each other, so only the first tile needs to know about a tile from a different set. % This makes it relatively easy to set up some templates for the substitution rules. % \begin{macrocode} \cs_new_nopar:cpn {@@_T{A1}_creator:nnnnn} #1#2#3#4#5 { \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {T#1{A1}#2} { [{ {H#3{B1}#4} {\@@_tile_label:0} {\@@_adjoint_label:#5} }] } } \cs_new_nopar:cpn {@@_T{A2}_creator:nnnnn} #1#2#3#4#5 { \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {T#1{A2}#2} { [{ {H#3{B2}#4} {\@@_tile_label:0} {\@@_adjoint_label:#5} }] } } \cs_new_nopar:cpn {@@_Tb_creator:nnnnn} #1#2#3#4#5 { \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {T#1b#2} { [{ {H#3a#4} {\@@_tile_label:0} {\@@_adjoint_label:#5} }] } } \cs_new_nopar:cpn {@@_H{B1}_creator:nnnnn} #1#2#3#4#5 { \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {H#1{B1}#2} { [{ {P#3A#4} {\@@_tile_label:4} {\@@_adjoint_label:#5} }] [{ {HP{B2}b} {\@@_tile_label:1} {\@@_tile_label:4} }] [{ {TH{A1}a} {\@@_tile_label:0} {\@@_tile_label:1} }] [{ {HTa{A2}} {\@@_tile_label:2} {\@@_tile_label:0} }] [{ {PHb{B2}} {\@@_tile_label:5} {\@@_tile_label:2} }] [{ {HT{B1}b} {\@@_tile_label:3} {\@@_tile_label:0} }] [{ {PHAa} {\@@_tile_label:6} {\@@_tile_label:3} }] [{ {FHb{B1}} {\@@_tile_label:7} {\@@_tile_label:1} }] [{ {FHb{B1}} {\@@_tile_label:8} {\@@_tile_label:2} }] [{ {FHb{B2}} {\@@_tile_label:9} {\@@_tile_label:3} }] } } \cs_new_nopar:cpn {@@_H{B2}_creator:nnnnn} #1#2#3#4#5 { \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {H#1{B2}#2} { [{ {P#3A#4} {\@@_tile_label:5} {\@@_adjoint_label:#5} }] [{ {HP{B2}b} {\@@_tile_label:2} {\@@_tile_label:5} }] [{ {TH{A2}a} {\@@_tile_label:0} {\@@_tile_label:2} }] [{ {HTa{A1}} {\@@_tile_label:1} {\@@_tile_label:0} }] [{ {PHb{B2}} {\@@_tile_label:4} {\@@_tile_label:1} }] [{ {HT{B1}b} {\@@_tile_label:3} {\@@_tile_label:0} }] [{ {PHAa} {\@@_tile_label:6} {\@@_tile_label:3} }] [{ {FHb{B1}} {\@@_tile_label:7} {\@@_tile_label:1} }] [{ {FHb{B1}} {\@@_tile_label:8} {\@@_tile_label:2} }] [{ {FHb{B2}} {\@@_tile_label:9} {\@@_tile_label:3} }] } } \cs_new_nopar:cpn {@@_Ha_creator:nnnnn} #1#2#3#4#5 { \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {H#1a#2} { [{ {P#3b#4} {\@@_tile_label:6} {\@@_adjoint_label:#5} }] [{ {HPaA} {\@@_tile_label:3} {\@@_tile_label:6} }] [{ {THb{B1}} {\@@_tile_label:0} {\@@_tile_label:3} }] [{ {HTa{A1}} {\@@_tile_label:1} {\@@_tile_label:0} }] [{ {PHb{B2}} {\@@_tile_label:4} {\@@_tile_label:1} }] [{ {HTa{A2}} {\@@_tile_label:2} {\@@_tile_label:0} }] [{ {PHb{B2}} {\@@_tile_label:5} {\@@_tile_label:2} }] [{ {FHb{B1}} {\@@_tile_label:7} {\@@_tile_label:1} }] [{ {FHb{B1}} {\@@_tile_label:8} {\@@_tile_label:2} }] [{ {FHb{B2}} {\@@_tile_label:9} {\@@_tile_label:3} }] } } \cs_new_nopar:cpn {@@_PA_creator:nnnnn} #1#2#3#4#5 { \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {P#1A#2} { [{ {H#3{B1}#4} {\@@_tile_label:1} {\@@_adjoint_label:#5} }] [{ {PHAa} {\@@_tile_label:0} {\@@_tile_label:1} }] [{ {HP{B2}b} {\@@_tile_label:2} {\@@_tile_label:0} }] [{ {FHb{B2}} {\@@_tile_label:3} {\@@_tile_label:1} }] [{ {FHb{B1}} {\@@_tile_label:4} {\@@_tile_label:2} }] } } \cs_new_nopar:cpn {@@_Pb_creator:nnnnn} #1#2#3#4#5 { \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {P#1b#2} { [{ {H#3a#4} {\@@_tile_label:2} {\@@_adjoint_label:#5} }] [{ {PHb{B2}} {\@@_tile_label:0}{\@@_tile_label:2} }] [{ {HPaA} {\@@_tile_label:1} {\@@_tile_label:0} }] [{ {FHb{B2}} {\@@_tile_label:3} {\@@_tile_label:1} }] [{ {FHb{B1}} {\@@_tile_label:4} {\@@_tile_label:2} }] } } \cs_new_nopar:cpn {@@_Fb_creator:nnnnn} #1#2#3#4#5 { \prop_gput:Nnn \g_@@_cluster_lms_rule_prop {F#1b#2} { [{ {H#3a#4} {\@@_tile_label:2} {\@@_adjoint_label:#5} }] [{ {PHb{B2}} {\@@_tile_label:0}{\@@_tile_label:2} }] [{ {HPaA} {\@@_tile_label:1} {\@@_tile_label:0} }] [{ {FHb{B2}} {\@@_tile_label:3} {\@@_tile_label:1} }] [{ {FHb{B1}} {\@@_tile_label:4} {\@@_tile_label:2} }] [{ {FHb{B1}} {\@@_tile_label:5} {\@@_tile_label:1} }] } } % \end{macrocode} % % Now that the creators are set up it is time to invoke them. % \begin{macrocode} \clist_map_inline:nn { TH{{A1}}a HP{{{B1}}}b06, TH{{A2}}a HP{{{B2}}}b06, THb{{B1}} HPaA04, THb{{B2}} HPaA05, PHAa HP{{{B1}}}b16, PHb{{B1}} HPaA24, PHb{{B2}} HPaA25, FHb{{B1}} HPaA24, FHb{{B2}} HPaA25, } { \tl_clear:N \l_@@_tmpa_tl \tl_put_right:Nn \l_@@_tmpa_tl { \use:c } \tl_put_right:Nx \l_@@_tmpa_tl { {@@_ \tl_item:nn {#1}{2}\tl_item:nn {#1}{4} _creator:nnnnn} {\tl_item:nn {#1}{1}}{\tl_item:nn{#1}{3}} \tl_item:nn {#1}{5}\tl_item:nn{#1}{7} \tl_item:nn {#1}{9} } \tl_use:N \l_@@_tmpa_tl \tl_clear:N \l_@@_tmpa_tl \tl_put_right:Nn \l_@@_tmpa_tl { \use:c } \tl_put_right:Nx \l_@@_tmpa_tl { {@@_ \tl_item:nn {#1}{1}\tl_item:nn {#1}{3} _creator:nnnnn} {\tl_item:nn {#1}{2}}{\tl_item:nn{#1}{4}} \tl_item:nn {#1}{6}\tl_item:nn{#1}{8} \tl_item:nn {#1}{10} } \tl_use:N \l_@@_tmpa_tl } % \end{macrocode} % % \begin{macrocode} \prop_new:N \g_@@_cluster_lms_action_prop % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_drawables_lms_prop {cluster} {HTPF} % \end{macrocode} % % \begin{macrocode} \prop_gput:Nnn \g_@@_cluster_lms_action_prop {r} { \pgftransformrotate{\l_@@_parameters_lms_tl} } \prop_gput:Nnn \g_@@_cluster_lms_action_prop {x} { \pgftransformxshift{ \fp_to_dim:n {.5 * (\l_@@_parameters_lms_tl) * \l_@@_step_dim} } } \prop_gput:Nnn \g_@@_cluster_lms_action_prop {y} { \pgftransformyshift{ \fp_to_dim:n {.5 * sqrt(3) * (\l_@@_parameters_lms_tl) * \l_@@_step_dim} } } \prop_gput:Nnn \g_@@_cluster_lms_action_prop {s} { \fp_set:Nn \l_@@_tmpa_fp { \l_@@_step_dim / \c_@@_phi_fp / \c_@@_phi_fp } \dim_set:Nn \l_@@_step_dim {\fp_to_dim:N \l_@@_tmpa_fp} } % \end{macrocode} % % The first set of actions are for when this tile is the root so doesn't have a parent % \begin{macrocode} \clist_map_inline:nn {H,T,P,F} { \prop_gput:Nnn \g_@@_cluster_lms_action_prop {#1} { \@@_tikz_keys_get:Nn \l_@@_tmpa_tl {cluster~type} \tl_set:Nx \l_@@_tmpb_tl {\tl_item:Nn \l_@@_parameters_lms_tl {1}} \@@_place_cluster_tile_as_pic:VnVnnn \l_@@_tmpa_tl {#1} \l_@@_tmpb_tl {}{}{} } } % \end{macrocode} % % The second set is for when there is an adjoining edge % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_place_cluster_tile_as_pic_aux:nnnn #1#2#3#4 { \@@_tikz_keys_get:Nn \l_@@_tmpa_tl {cluster~type} \tl_set:Nx \l_@@_tmpb_tl {\@@_tile_label:} \tl_set:Nx \l_@@_tmpc_tl {\@@_adjoint_label:} \@@_place_cluster_tile_as_pic:VnVVnn \l_@@_tmpa_tl {#1} \l_@@_tmpb_tl \l_@@_tmpc_tl {#4}{#3} } \clist_map_inline:nn { TH{A1}a, TH{A2}a, THb{B1}, THb{B2}, HTa{A1}, HTa{A2}, HT{B1}b, HT{B2}b, HPaA, HP{B1}b, HP{B2}b, HF{B1}b, HF{B2}b, PHAa, PHb{B1}, PHb{B2}, PF{11}{11}, PF{12}{11}, PF{11}{12}, PF{12}{12}, FHb{B1}, FHb{B2}, FP{11}{11}, FP{12}{11}, FP{11}{12}, FP{12}{12}, FFfF, FFFf, FF{11}{11}, FF{12}{11}, FF{11}{12}, FF{12}{12} } { \prop_gput:Nnn \g_@@_cluster_lms_action_prop {#1} { \@@_place_cluster_tile_as_pic_aux:nnnn #1 } } \ExplSyntaxOff % \end{macrocode} % % \iffalse % % \fi % % \iffalse %<*penrosedep> % \fi % % \begin{macrocode} \ProvidesFile {tikzlibrarypenrose.code.tex} [2023/06/01 v2.0 TikZ pics for Penrose tiles] \usetikzlibrary{tilings.penrose} % \end{macrocode} % % Backwards compatibility mode: % % \begin{itemize} % \item \Verb+\SetPenrosePath+ is \Verb+\SetTilingPath+ % \item \Verb+\BakePenroseTile+ and \Verb+\MakePenroseTile+ are \Verb+\BakeTile+ % \item \Verb+\UsePenroseTile+ is \Verb+\UseTile+ % \item \Verb+\PenroseDecomposition+ is \Verb+\TilingDecomposition+ % \end{itemize} % \begin{macrocode} \ExplSyntaxOn \NewDocumentCommand \SetPenrosePath { m } { \@@_set_tiling_path:n {#1} } \NewDocumentCommand \BakePenroseTile {m} { \@@_bake_tile:n {#1} } \NewDocumentCommand \MakePenroseTile {m} { \@@_bake_tile:n {#1} } \NewDocumentCommand \UsePenroseTile {O{} m} { \@@_use_tile:nn {#1}{#2} } \NewDocumentCommand \PenroseDecomposition { O{} m m m } { \@@_tiling_decomposition:nnnn {#1}{#2}{#3}{#4} } \ExplSyntaxOff % \end{macrocode} % % \begin{macrocode} \tikzset{ save Penrose path/.forward to=/tikz/save tiling path, clone Penrose side path/.forward to=/tikz/clone tiling side path, spath/prefix/Penrose side/.forward to=/tikz/spath/prefix/tiling side, spath/suffix/Penrose side/.forward to=/tikz/spath/suffix/tiling side, clone Penrose tile path/.forward to=/tikz/clone tiling tile path, spath/prefix/Penrose tile/.forward to=/tikz/spath/prefix/tiling tile, spath/suffix/Penrose tile/.forward to=/tikz/spath/suffix/tiling tile, Penrose step/.forward to=/tikz/tiling step, every tile/.append style={ every Penrose tile/.try }, every tile clip/.append style={ every Penrose tile clip/.try }, every tile pic/.append style={ every Penrose pic/.try }, tile/.append style={ Penrose tile #1/.try, Penrose tile/.try=#1 } } % \end{macrocode} % % \iffalse % % \fi % % \end{implementation} %\Finale \endinput