# Macro for rounded polygon around some nodes

I would like to create a tikz-macro that draws a nice rounded polygon around a given list of nodes. Something like:

\myroundpoly{p1,p2,...,pn}{dist}


Here, p1,p2,....,pn are the vertices of a polygon given in a clockwise order and dist is a parameter for the distance of the rounded polygon of these vertices.

A MWE is the following:

\documentclass[border=10pt]{standalone}

\usepackage{tikz}
\usepackage{tkz-euclide}
\usetkzobj{all}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}

%Some saple vertices
\node (a1) at (-1,-1) {1};
\node (a4) at (2,-2) {4};
\node (a3) at (3,3) {3};
\node (a2) at (-2,1) {2};

%---------------------------------------------------------------------%
%This is what I would like to type -> \myrondpoly{{a1,a2,a3,a4},0.3cm}%
%---------------------------------------------------------------------%

%----------------------------------%
%And this is what it should compute%
%----------------------------------%
\def\dist{0.3cm}

%Calculate the auxiliary coordinates for the arcs
\foreach \from/\to in {{a1/a2},{a2/a3},{a3/a4},{a4/a1}}{%calculates the points for the arcs and draws the straight lines
\coordinate (\from\to) at ($(\from)!\dist!90:(\to)$);
\coordinate (\to\from) at ($(\to)!\dist!-90:(\from)$);
}
%Draw the straight lines
\foreach \from/\to in {{a1/a2},{a2/a3},{a3/a4},{a4/a1}}
\draw (\from\to) -- (\to\from);
%Draw the arcs
\foreach \pred/\mid/\succ in {{a4/a1/a2},{a1/a2/a3},{a2/a3/a4},{a3/a4/a1}}{
\tkzDrawArc[color=black](\mid,\mid\succ)(\mid\pred)
}

\end{tikzpicture}
\end{document}


Some example outputs of the intended procedure can be seen here:

Here is a list of features that would be nice to have:

• the polygons should not be filled, i.e., if two polygons overlap then none obscures the other (except for the lines of course)

• special case of 2-polygon and 1-polygon does not break the code

• short code with few packages

• Each iteration of \foreach is in a separate group, so you need to use \global definitions to pass information. Instead of trying to access the next value, you could access the last two values. – John Kormylo Mar 3 '17 at 0:29
• It would be easier to use \myroundpoly{{p1,p2,...,pn}}{dist} – John Kormylo Mar 3 '17 at 0:37

The following is the simplest way

\documentclass[border=10pt]{standalone}

\usepackage{tikz}
\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

\begin{document}

\def\drawpolygon#1,#2;{
\begin{pgfonlayer}{background}
\filldraw[line width=20,join=round      ](#1.center)foreach\A in{#2}{--(\A.center)}--cycle;
\filldraw[line width=19,join=round,white](#1.center)foreach\A in{#2}{--(\A.center)}--cycle;
\end{pgfonlayer}
}
\tikz{
\node (a1) at (-1,-1) {1};
\node (a2) at (-2,1) {2};
\node (a4) at (2,-2) {4};
\node (a3) at (3,3) {3};
\node (a5) at (4,2) {5};
\node (a6) at (-1,3) {6};
\drawpolygon a2,a4,a3;
\drawpolygon a1,a5,a6;
}

\end{document}


I have two approaches. The first one is pure TikZ. It is more complicated for reasons discussed in Draw a path between many nodes using foreach

The second one is pure PGF and is (much) more simpler. They both support 2-polygon (aka digon).

\documentclass[border=10pt]{standalone}

\usepackage{tikz}
\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

\begin{document}

% pure TikZ version

\begin{tikzpicture}
\node (a1) at (-1,-1) {1};
\node (a2) at (-2,1) {2};
\node (a4) at (2,-2) {4};
\node (a3) at (3,3) {3};
\begin{pgfonlayer}{background}
\filldraw[line width=20,line join=round](a1.center)--(a2.center)--(a3.center)--(a4.center)--cycle;
\filldraw[line width=19,line join=round,white](a1.center)--(a2.center)--(a3.center)--(a4.center)--cycle;
\end{pgfonlayer}
\end{tikzpicture}

% pure pgf version

\def\drawpolygon#1,#2;{
\begin{pgfonlayer}{background}
\pgfsetroundjoin
\pgfpathmoveto{\pgfpointanchor{#1}{center}}
\foreach\P in{#2}{\pgfpathlineto{\pgfpointanchor{\P}{center}}}
\pgfpathclose\pgfsetlinewidth{20}\pgfsetcolor{black}\pgfusepath{fill,stroke}
\pgfpathmoveto{\pgfpointanchor{#1}{center}}
\foreach\P in{#2}{\pgfpathlineto{\pgfpointanchor{\P}{center}}}
\pgfpathclose\pgfsetlinewidth{19}\pgfsetcolor{white}\pgfusepath{fill,stroke}
\end{pgfonlayer}
}
\tikz{
\node (a1) at (-1,-1) {1};
\node (a2) at (-2,1) {2};
\node (a4) at (2,-2) {4};
\node (a3) at (3,3) {3};
\node (a5) at (4,2) {5};
\drawpolygon a2,a4,a3;
\drawpolygon a1,a5;
}


• Is there also a way, to have the polygons to be non-opaque? – bitt.j May 22 '17 at 13:28
• Very nice! Love the results. – Dr. Manuel Kuehner Jun 11 '17 at 12:52

For the sake of completeness, I do post the code I have used to solve my problem. It has quite some flaws: sometimes lines do not match perfectly, it takes rather long to compile, it is quite some code for such an easy looking problem.

\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes}
%Necessary for the mypoly command%
\usepackage{tkz-euclide}
\usetkzobj{all}
\usepackage{xstring}

%------------------------%
%---The mypoly command---%
%------------------------%

%--Getting the last Element of a list--%
\def\splicelist#1{
\StrCount{#1}{,}[\numofelem]
\ifnum\numofelem>0\relax
\StrBehind[\numofelem]{#1}{,}[\mylast]%
\else
\let\mylast#1%
\fi
}

%--The mypoly macro--%
%How to use:
%\myroundpoly[decorative commands]{list of names of nodes}{distance}
%list of names has to be given in clockwise order
\newcommand{\myroundpoly}[3][thin,color=black]{
%Get the last element
\splicelist{#2}
%Calculate the auxiliary coordinates for the arcs
\foreach \vertex [remember=\vertex as \succvertex
(initially \mylast)] in {#2}{
\coordinate (\succvertex-next) at ($(\succvertex)!#3!90:(\vertex)$);
\coordinate (\vertex-previous) at ($(\vertex)!#3!-90:(\succvertex)$);
\draw[#1] (\succvertex-next) --  (\vertex-previous);
}
%Draw the arcs
\foreach \vertex in {#2}{
\tkzDrawArc[#1](\vertex,\vertex-next)(\vertex-previous)
}
}

%-------------------%
%---Some examples---%
%-------------------%
\begin{document}
\begin{tikzpicture}
%%%%%%%%%%%%
%This works%
%%%%%%%%%%%%

%--doing a triangle--%
\node (a1) at (0,0) {1};
\node (a2) at ($(a1)+(-120*1:1)$)  {2};
\node (a3) at ($(a1)+(-120*2:1)$)  {3};

\myroundpoly{a1,a2,a3}{0.3cm}

%--doing a 'cartwheel'--%
\node[circle, fill = black] (b0) at (2,0) {};
\node[circle, fill = black] (b1) at ($(b0)+(-120*1:1)$)  {};
\node[circle, fill = black] (b2) at ($(b0)+(-120*2:1)$)  {};
\node[circle, fill = black] (b3) at ($(b0)+(-120*3:1)$)  {};

\myroundpoly[color = black, thick]{b3,b0,b2}{0.3cm}
\myroundpoly[color = black, thick]{b2,b0,b1}{0.3cm}
\myroundpoly[color = red]{b1,b0,b3}{0.3cm}

%%%%%%%%%%%%%%%%%%%%
%This does not work%
%%%%%%%%%%%%%%%%%%%%
\node (c1) at (5,0) {I};
\node (c2) at ($(c1)+(-120*1:1)$)  {II};
\node (c3) at ($(c1)+(-120*2:1)$)  {III};

\myroundpoly{c1,c3,c2}{0.3cm}%wrong order
\end{tikzpicture}
\end{document}