% !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},
}
