3

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: Nice polygons with round corners

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
6

New Answer

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}

Old Answer

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
1

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}

Some examples of rounded polygons

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.