% !TeX root = jigsaw-doc.tex %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % The jigsaw package % A package to draw jigsaw pieces with tikz % Maintained by samcarter % % Project repository and bug tracker: % https://github.com/samcarter/jigsaw % % Released under the LaTeX Project Public License v1.3c or later % See http://www.latex-project.org/lppl.txt % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ProvidesPackage{jigsaw}[2023/02/21 version v0.4 Draw jigsaw pieces in TikZ] \RequirePackage{tikz} \RequirePackage{ifluatex} \RequirePackage{ifxetex} \ifluatex \let\pdfrandomseed\randomseed \fi \ifxetex \pgfmathsetseed{\time} \else \pgfmathsetseed{\number\pdfrandomseed} \fi \pgfmathparse{int(random(1,120))} % store the current scale factor % from https://github.com/samcarter/tikzlings/issues/3#issuecomment-461373494 \newcommand{\jigsaw@getscaling}{ \pgfgettransformentries{\tmpscaleA}{\tmpscaleB}{\tmpscaleC}{\tmpscaleD}{\tmp}{\tmp}% \pgfmathsetmacro{\scalingfactor}{sqrt(abs(\tmpscaleA*\tmpscaleD-\tmpscaleB*\tmpscaleC))*sqrt(abs((\pgf@xx/1cm)*(\pgf@yy/1cm)-(\pgf@xy/1cm)*(\pgf@yx/1cm)))}% } \newcommand{\side}[1]{ (0.0,#1*0.00) .. controls (0.0,#1*0.00) and (0.4,#1*-0.04) .. (0.4,#1*0.04) .. controls (0.4,#1*0.11) and (0.2,#1*0.26) .. (0.5,#1*0.26) .. controls (0.8,#1*0.26) and (0.6,#1*0.11) .. (0.6,#1*0.04) .. controls (0.6,#1*-0.04) and (1.0,#1*0.00) .. (1.0,#1*0.00) -- ++(.5\pgflinewidth/\scalingfactor,0) } \newcommand{\halfpiece}[2]{% \jigsaw@getscaling% \draw \side{#1} [rotate around={90:(0.5,0.5)}] \side{#2}; } \NewDocumentCommand{\piece}{ommmm}{% \jigsaw@getscaling% \IfValueT{#1}{% \fill[#1] \side{#2} [rotate around={90:(0.5,0.5)}] -- \side{#3} [rotate around={90:(0.5,0.5)}] -- \side{#4} [rotate around={90:(0.5,0.5)}] -- \side{#5} -- cycle; }% \draw \side{#2} [rotate around={90:(0.5,0.5)}] -- \side{#3} [rotate around={90:(0.5,0.5)}] -- \side{#4} [rotate around={90:(0.5,0.5)}] -- \side{#5} -- cycle; } \NewDocumentCommand{\tile}{ommmm}{% \begin{tikzpicture} \path (0,0) rectangle (1,0.97); \begin{pgfinterruptboundingbox} \piece[#1]{#2}{#3}{#4}{#5} \end{pgfinterruptboundingbox} \end{tikzpicture}% } \pgfmathdeclarerandomlist{inout}{{-1}{1}} \newcommand{\jigsaw}[2]{% \def\xmax{#1} \def\ymax{#2} \foreach \x in {1,...,\xmax}{ \foreach \y in {1,...,\ymax}{ \ifnum\y=1 \def\bottom{0} \else \pgfmathrandomitem{\bottom}{inout}% \fi \ifnum\x=\xmax \def\right{0} \else \pgfmathrandomitem{\right}{inout}% \fi \begin{scope}[xshift=\x cm-1cm, yshift=\y cm-1cm] \halfpiece{\bottom}{\right} \end{scope} } } \draw (0,0) -- (0,\ymax) -- (\xmax,\ymax); } \tikzset{ pics/piece/.style n args={4}{ inherit options/.code={\csname tikz@options\endcsname}, inherit options, code = { \jigsaw@getscaling% \path (0,0) rectangle (1,1); \begin{pgfinterruptboundingbox} \path[pic actions] \side{#1} [rotate around={90:(0.5,0.5)}] -- \side{#2} [rotate around={90:(0.5,0.5)}] -- \side{#3} [rotate around={90:(0.5,0.5)}] -- \side{#4} -- cycle; % expansion trick from https://topanswers.xyz/tex?q=3340#a3677 \node[draw=none,fill=none,style/.expand once=\tikzpictextoptions] at (0.5,0.5) {\tikzpictext}; \end{pgfinterruptboundingbox} } }, piece/.search also={,/tikz,/pgf}, }