This question led to a new package:
jigsaw

I would like to draw a jigsaw puzzle boundary layer, ideally connecting two half-circle segments. The two segments should be connected by a nicely curved typical jigsaw boundary like in the following picture:

Royalty free shutterstock image

I couldn't find any tikz boilerplate code for such a shape, besides a simplified version here on tex.sx

If you have already drawn such a shape, please share!

up vote 12 down vote accepted

And a version with pics. That may make it a bit easier to build a full puzzle.

\documentclass[tikz,border=3.14mm]{standalone}
\begin{document}
\tikzset{pics/.cd,
  jigsaw/.style={
    code={
\fill[#1] (-2,-0.35) to[out=90,in=135] (-1.5,-0.45) arc(-135:135:0.6 and
{0.45*sqrt(2)}) to[out=-135,in=-90] (-2,0.35) |- (-0.35,2)
to[out=0,in=-45] (-0.45,2.5) arc(225:-45:{0.45*sqrt(2)} and 0.6)
to[out=-135,in=180] (0.35,2) -| (2,0.35) 
to[out=-90,in=225] (2.5,0.45) arc(135:-135:0.6 and {0.45*sqrt(2)})
to[out=135,in=90] (2,-0.35) |- (0.35,-2)
to[out=180,in=-135] (0.45,-1.5) arc(-45:225:{0.45*sqrt(2)} and 0.6) 
to[out=-45,in=0] (-0.35,-2) -| cycle;
}}}
\begin{tikzpicture}
\draw (-2,-2) pic{jigsaw=blue} (2,-2) pic{jigsaw=red}
(-2,2) pic[rotate=90]{jigsaw=purple} (2,2) pic[rotate=90]{jigsaw=green!60!black};
\end{tikzpicture}
\end{document}

enter image description here

UPDATE: With multipurpose jigsaw pics: the syntax is

pic{multipurpose jigsaw=fill <color> and <left>/<top>/<right>/<bottom>}

where <color> determines the fill color and the other arguments specify the lug: -1 means that lug goes in, 1 that the lug goes out and 0 means no lug. (Also tried to improve on the colors. ;-)

\documentclass[x11names, svgnames, dvipsnames,tikz,border=3.14mm]{standalone}
\begin{document}
\tikzset{pics/.cd,
  jigsaw/.style={
    code={
\fill[#1] (-2,-0.35) to[out=90,in=135] (-1.5,-0.45) arc(-135:135:0.6 and
{0.45*sqrt(2)}) to[out=-135,in=-90] (-2,0.35) |- (-0.35,2)
to[out=0,in=-45] (-0.45,2.5) arc(225:-45:{0.45*sqrt(2)} and 0.6)
to[out=-135,in=180] (0.35,2) -| (2,0.35) 
to[out=-90,in=225] (2.5,0.45) arc(135:-135:0.6 and {0.45*sqrt(2)})
to[out=135,in=90] (2,-0.35) |- (0.35,-2)
to[out=180,in=-135] (0.45,-1.5) arc(-45:225:{0.45*sqrt(2)} and 0.6) 
to[out=-45,in=0] (-0.35,-2) -| cycle;
}},
multipurpose jigsaw/.style args={fill #1 and #2/#3/#4/#5}{
    code={%
\fill[#1] (-2,-0.35) to[out=90,in={90+#2*45}] ({-2+0.5*#2},-0.45) 
arc({-135-(#2-1)*45}:{(#2-1)*180+135+(#2-1)*45}:0.6 and
{0.45*sqrt(2)}) to[out=-90-#2*45,in=-90] (-2,0.35) |- (-0.35,2)
to[out=0,in={0+#3*45}] (-0.45,2-0.5*#3) arc(180-#3*45:{(#3+1)*180+#3*45}:{0.45*sqrt(2)} and 0.6)
to[out=-180-#3*45,in=180] (0.35,2) -| (2,0.35) 
to[out=-90,in=270+#4*45] (2-#4*0.5,0.45) 
arc(90-#4*45:{(#4+1)*180-90+#4*45}:0.6 and {0.45*sqrt(2)})
to[out=90-#4*45,in=90] (2,-0.35) |- (0.35,-2)
to[out=180,in=-180+#5*45] (0.45,-2+#5*0.5) arc(-#5*45:{(#5-1)*180+180+#5*45}:{0.45*sqrt(2)} and 0.6) 
to[out=-#5*45,in=0] (-0.35,-2) -| cycle;
}}}
% order : left/top/right/bottom and -1 is out, 1 is in, 0 none
\begin{tikzpicture}
\draw (-4,-4) pic{multipurpose jigsaw=fill FireBrick and 0/-1/1/0}
(0,-4) pic{multipurpose jigsaw=fill Blue and -1/-1/1/0}
(4,-4) pic{multipurpose jigsaw=fill ForestGreen and -1/1/0/0}
(-4,0) pic{multipurpose jigsaw=fill ForestGreen and 0/1/-1/1}
(0,0) pic{multipurpose jigsaw=fill FireBrick and 1/-1/1/1}
(4,0) pic{multipurpose jigsaw=fill Blue and -1/1/0/-1}
(-4,4) pic{multipurpose jigsaw=fill Blue and 0/0/1/-1}
(0,4) pic{multipurpose jigsaw=fill ForestGreen and -1/0/1/1}
(4,4) pic{multipurpose jigsaw=fill FireBrick and -1/0/0/-1};
\end{tikzpicture}
\end{document}

enter image description here

  • Also a great solution, thanks! If I only could accept several answers. – sebastian Aug 17 at 12:04

Based on a single side, one can easily draw jigsaw pieces. In the following example, the macro \piece can be used to draw a piece of the desired shape. For all four sides it can be controlled if the nose should face outward (-1) or inward (1) or a straight line (0).

\documentclass{standalone}

\usepackage{tikz}

\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)
}

\newcommand{\piece}[4]{
    \draw 
    \side{#1}
    [rotate around={90:(0.5,0.5)}] \side{#2} 
    [rotate around={180:(0.5,0.5)}] \side{#3} 
    [rotate around={270:(0.5,0.5)}] \side{#4};
}

\begin{document}

\begin{tikzpicture}[scale=3]
\piece{1}{1}{1}{1}
\end{tikzpicture}

\begin{tikzpicture}[scale=3]
\piece{1}{-1}{1}{1}
\end{tikzpicture}


\begin{tikzpicture}[scale=3]
\piece{1}{-1}{-1}{1}
\end{tikzpicture}


\begin{tikzpicture}[scale=3]
\piece{1}{-1}{-1}{-1}
\end{tikzpicture}


\begin{tikzpicture}[scale=3]
\piece{-1}{-1}{-1}{-1}
\end{tikzpicture}


\begin{tikzpicture}[scale=3]
\piece{-1}{1}{-1}{1}
\end{tikzpicture}

\end{document}

enter image description here

These pieces can also be used to build a puzzle:

\documentclass{standalone}

\usepackage{tikz}

\newcommand{\side}[1]{
(0.5,0.5) -- 
(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)
}

\newcommand{\piece}[5][white]{
    \fill[#1] 
    \side{#2}
    [rotate around={90:(0.5,0.5)}] \side{#3} 
    [rotate around={180:(0.5,0.5)}] \side{#4} 
    [rotate around={270:(0.5,0.5)}] \side{#5} 
    -- cycle;
}

\begin{document}

\begin{tikzpicture}

\begin{scope}
    \piece[red]{1}{1}{0}{0}
\end{scope}
\begin{scope}[xshift=1cm]
    \piece[blue]{1}{-1}{-1}{0}
\end{scope}
\begin{scope}[xshift=2cm]
    \piece[green]{1}{0}{1}{0}
\end{scope}

\begin{scope}[yshift=-1cm]
    \piece[green]{1}{-1}{0}{-1}
\end{scope}
\begin{scope}[xshift=1cm,yshift=-1cm]
    \piece[red]{1}{-1}{1}{-1}
\end{scope}
\begin{scope}[xshift=2cm,yshift=-1cm]
    \piece[blue]{-1}{0}{1}{-1}
\end{scope}

\begin{scope}[yshift=-2cm]
    \piece[blue]{0}{-1}{0}{-1}
\end{scope}
\begin{scope}[xshift=1cm,yshift=-2cm]
    \piece[green]{0}{-1}{1}{-1}
\end{scope}
\begin{scope}[xshift=2cm,yshift=-2cm]
    \piece[red]{0}{0}{1}{1}
\end{scope}

\end{tikzpicture}

\end{document}

enter image description here

Or to produce a random puzzle:

\documentclass{standalone}

\usepackage{tikz}
\pgfmathparse{int(random(1,120))}

\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)
}

\newcommand{\piece}[2]{
    \draw[ultra thick] \side{#1} [rotate around={90:(0.5,0.5)}] \side{#2};
}

\pgfmathdeclarerandomlist{inout}{{-1}{1}}

\begin{document}

\begin{tikzpicture}[scale=5]

    \def\xmax{10}
    \def\ymax{10}


    \foreach \x in {0,...,\xmax}{
        \foreach \y in {0,...,\ymax}{

            \ifnum\y=0
                \def\bottom{0}
            \else
                \pgfmathrandomitem{\bottom}{inout}%
            \fi

            \ifnum\x=\xmax
                \def\right{0}
            \else
                \pgfmathrandomitem{\right}{inout}%
            \fi

            \begin{scope}[xshift=\x cm, yshift=\y cm]
                \piece{\bottom}{\right}
            \end{scope}
        }
    }

    \draw (0,0) -- (0,\ymax+1) -- (\xmax+1,\ymax+1);

\end{tikzpicture}

\end{document}

enter image description here

With background image

\documentclass{standalone}

\usepackage{tikz}
\pgfmathparse{int(random(1,120))}

\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)
}

\newcommand{\piece}[2]{
    \draw[thick] \side{#1} [rotate around={90:(0.5,0.5)}] \side{#2};
}

\pgfmathdeclarerandomlist{inout}{{-1}{1}}

\begin{document}

\begin{tikzpicture}

    \node at (5.5,4) {\includegraphics[width=11cm,height=8cm]{example-image-duck}};

    \def\xmax{10}
    \def\ymax{7}


    \foreach \x in {0,...,\xmax}{
        \foreach \y in {0,...,\ymax}{

            \ifnum\y=0
                \def\bottom{0}
            \else
                \pgfmathrandomitem{\bottom}{inout}%
            \fi

            \ifnum\x=\xmax
                \def\right{0}
            \else
                \pgfmathrandomitem{\right}{inout}%
            \fi

            \begin{scope}[xshift=\x cm, yshift=\y cm]
                \piece{\bottom}{\right}
            \end{scope}
        }
    }

    \draw (0,0) -- (0,\ymax+1) -- (\xmax+1,\ymax+1);

\end{tikzpicture}

\end{document}

enter image description here

  • I didn't see your update till now. Coincidently we have the same conventions for in and out. Weird. ;-) ;-) – marmot Aug 16 at 17:16
  • @marmot 50:50 chance :) – samcarter Aug 16 at 17:20
  • Yes, and how many % to use integers for that? ;-) – marmot Aug 16 at 17:21
  • 1
    @marmot 100%, it is so convenient to control the direction by simply multiplying :) – samcarter Aug 16 at 17:24
  • great solution, thank you! – sebastian Aug 17 at 12:03

An option using [out=Angle,in=Angle,out looseness=Value,in looseness=Value] and coordinate calculations to draw rotated shape; then other tricks to control sizes, angles ,positions and colors.

RESULT:

enter image description here

MWE:

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows.meta,calc,fit,shapes}

\begin{document}
    \begin{tikzpicture}
    \def\JigzawPiece(#1)[#2]#3#4{
    \begin{scope}[shift={(#1)},rotate=#4,transform shape]
    \coordinate (a) at (0:#2);\coordinate (b) at (90:#2);\coordinate (c) at (180:#2);\coordinate (d) at (270:#2);
    \foreach \nodA/\nodB in {a/b,b/c,c/d,d/a}{
    \coordinate (\nodA\nodB1) at ($ (\nodA)!{0.4}!(\nodB) $);
    \coordinate (\nodA\nodB2) at ($ (\nodA)!{0.6}!(\nodB) $); 
    \coordinate (\nodA\nodB3) at ($ (\nodA)!{0.5}!(\nodB) $);
    \coordinate (\nodA\nodB4) at ($(\nodA\nodB3)!0.5*#2 cm!90:(\nodA)$);
    \coordinate (\nodA\nodB5) at ($(\nodA\nodB3)!-0.5*#2 cm!90:(\nodA)$);
    }
    \draw[fill=#3]
        (a) -- (ab1) 
            to [out=133,in=-45,out looseness=1,in looseness=2] (ab5) 
            to [out=135,in=-45,out looseness=2,in looseness=1] (ab2) --
        (b) -- (bc1) 
            to [out=-135,in=45,out looseness=1,in looseness=2] (bc4) 
            to [out=-135,in=45,out looseness=2,in looseness=1] (bc2) --
        (c) -- (cd1) 
            to [out=-45,in=135,out looseness=1,in looseness=2] (cd4) 
            to [out=-45,in=135,out looseness=2,in looseness=1] (cd2) --
        (d) -- (da1) 
            to [out=45,in=-135,out looseness=1,in looseness=2] (da5) 
            to [out=45,in=-135,out looseness=2,in looseness=1] (da2) --(a);
    \end{scope}
    }

    \foreach \x in {0,1,...,7}{
        \foreach \y in {0,1,...,5}{
        \pgfmathparse{0.9*rnd+0.3}
             \definecolor{Rcolor}{rgb}{\pgfmathresult,\pgfmathresult,\pgfmathresult} % from https://tex.stackexchange.com/a/37279/154390
            \JigzawPiece(\x,\y)[0.5]{blue!50!Rcolor}{0}
            \JigzawPiece(\x+0.5,\y+0.5)[0.5]{blue!30!Rcolor}{0}
        }
    }
    \foreach \ang [count=\j from 0] in {0,90,180,270} {
        \JigzawPiece(0.5+\j*2,7)[1]{red}{\ang}
    }

    \foreach \ang [count=\j from 0] in {-45,45,45,-45,-45} {
        \JigzawPiece(0.5+\j*1.4142,9)[1]{red}{\ang}
    }
    \end{tikzpicture}

\end{document}

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.