1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
% !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},
}
|