15

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!

13

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

26
+500

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. ;-) ;-) – user121799 Aug 16 '18 at 17:16
  • @marmot 50:50 chance :) – user36296 Aug 16 '18 at 17:20
  • Yes, and how many % to use integers for that? ;-) – user121799 Aug 16 '18 at 17:21
  • 1
    @marmot 100%, it is so convenient to control the direction by simply multiplying :) – user36296 Aug 16 '18 at 17:24
  • @sebastian You're welcome! However I think you accepted the wrong answer, @ marmots is much more versatile, please consider accepting his instead. – user36296 Aug 17 '18 at 12:07
7

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 agree to our terms of service, privacy policy and cookie policy

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