15

I want to draw a polygon with different line color and rounded corners, but the corners of polygon are not rounded!

\documentclass[12pt]{report}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[line width=5pt]
\coordinate (A) at (0,0);
\coordinate (B) at (2,0);
\coordinate (C) at (3,2);
\coordinate (D) at (1,3);
\coordinate (E) at (-1,2);
\draw[pink] (A) -- (B);
\draw[blue] (B) -- (C);
\draw[red] (C) -- (D);
\draw [green] (D) -- (E);
\draw (E) -- (A);
\end{tikzpicture}
\end{document}

1 Answer 1

13

This does not give you rounded corners but it does, I suggest, give a much improved result. Essentially the idea is to use a clipping to cut of ragged bits and then to use a triangular cap, with length equal to half of the line width divided by tan 54, to neaten the joins within the pentagon.

\documentclass[border=10pt,multi,tikz]{standalone}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{tikzpicture}[line width=5pt]
  \foreach \i in {0,...,4}  \coordinate (p\i) at ({18+\i*72}:1);
  \clip (p0) -- (p1) -- (p2) -- (p3) -- (p4) -- cycle;
  \pgfmathsetmacro\xyz{.5*\pgflinewidth/tan(54)}
  \foreach \i [count=\j from 0, evaluate=\j as \k using {int(mod(\j+1,5))}] in {magenta,blue,green,orange,red} \draw [\i, {Triangle Cap[length=\xyz pt]}-{Triangle Cap[length=\xyz pt]}] (p\j) -- (p\k);
\end{tikzpicture}
\end{document}

fancy coloured pentagon

You can add [rounded corners] to the \clip if you wish, but I did not think the result looked at all good because you only get rounding on the outer edge of the line.

For example, adding [rounded corners=.5*\pgflinewidth] produces

outer rounded corners

For real rounding, it may be easier to fill the sectors of the polygon rather than drawing its sides. For example,

\begin{tikzpicture}[line width=10pt]
  \foreach \i in {0,...,4}  \path ({18+\i*72}:1) coordinate (p\i) ++({18+\i*72:-.5*\pgflinewidth}) coordinate (q\i);
  \clip [rounded corners=.5*\pgflinewidth] (p0) -- (p1) -- (p2) -- (p3) -- (p4) -- cycle (q0) -- (q4) -- (q3) -- (q2) -- (q1) -- cycle;
  \pgfmathsetmacro\xyz{.5*\pgflinewidth/tan(54)}
  \foreach \i [count=\j from 0, evaluate=\j as \k using {int(mod(\j+1,5))}] in {magenta,blue,green,orange,red} \path [fill, \i] (p\j) -- (p\k) -- (0,0) -- cycle;
\end{tikzpicture}

produces

rounded inner and outer corners

This does not look as neat to me as the non-rounded version, but I can imagine this might be better for certain specialist uses. You might want to fiddle a little with how rounded the corners are for best results - there is probably a trade-off here.

It is not hard to turn these into a pic for use in drawing any regular polygon - not just pentagons.

For example, the definition given below makes it possible to write

\begin{tikzpicture}
  \pic at (0,0) {rainbow polygon={sides=6,colours={blue,blue!80!cyan,blue!60!cyan,blue!40!cyan,blue!20!cyan,cyan}}};
  \pic at (2,0) {rainbow polygon={rounded corners=outer,sides=12}};
  \pic at (0,2) {rainbow polygon};
  \pic at (2,2) {rainbow polygon={rounded corners=both,sides=7,colours={red,orange,yellow,green,blue,purple,magenta},line width=8pt}};
\end{tikzpicture}

to produce

rainbow polygons

The pic rainbow polygon takes a single, optional argument. If specified, this should give customisation options. It only really makes sense to use the pics own keys here, although it will accept other TikZ keys as well.

colours={<comma separated list of colours>}
line width=<dimension>
sides=<sensible integer>
rounded corners=<none|inner|outer|both>
size=<dimension>

Complete code [use at own risk!]:

\documentclass[border=10pt,multi,tikz]{standalone}
\usetikzlibrary{arrows.meta}
\makeatletter
\newif\ifrainbowpolygon@rounded@outer
\newif\ifrainbowpolygon@rounded@inner
\newcounter{rainbowpolygon@colours}
\setcounter{rainbowpolygon@colours}{0}
\tikzset{%
  pics/rainbow polygon/.style={%
    code={%
      \tikzset{%
        rainbow polygon/.cd,
        defaults,
        #1
      }
      \ifrainbowpolygon@rounded@outer\tikzset{rainbow polygon/clip/.style={rounded corners=.5*\pgflinewidth}}\fi
      \begin{scope}[line width=\rainbowpolygon@linewidth]
        \foreach \i in {0,...,\rainbowpolygon@last}  \path ({90-\rainbowpolygon@eangle+\i*\rainbowpolygon@eangle}:\rainbowpolygon@size) coordinate (p\i) \ifrainbowpolygon@rounded@inner ++({90-\rainbowpolygon@eangle+\i*\rainbowpolygon@eangle}:-.5*\pgflinewidth) coordinate (q\i) \fi ;
         \clip [rainbow polygon/clip] (p0) \foreach \i in {1,...,\rainbowpolygon@last} { -- (p\i) } -- cycle \ifrainbowpolygon@rounded@inner (q0) \foreach \j in {\rainbowpolygon@last,...,1} { -- (q\j) } -- cycle \fi ;
         \ifrainbowpolygon@rounded@inner
           \foreach \i [evaluate=\i as \k using {int(mod(\i+1,\rainbowpolygon@sides))}, evaluate=\i as \j using {int(mod(\i,\therainbowpolygon@colours))}] in {0,...,\rainbowpolygon@last} \path [fill, col\j] (p\i) -- (p\k) -- (0,0) -- cycle;
         \else
           \pgfmathsetmacro\xyz{.5*\pgflinewidth/tan(.5*\rainbowpolygon@iangle)}
           \foreach \i [evaluate=\i as \k using {int(mod(\i+1,\rainbowpolygon@sides))}, evaluate=\i as \j using {int(mod(\i,\therainbowpolygon@colours))}] in {0,...,\rainbowpolygon@last} \draw [col\j, {Triangle Cap[length=\xyz pt]}-{Triangle Cap[length=\xyz pt]}] (p\i) -- (p\k);
         \fi
    \end{scope}
    }
  },
  rainbow polygon/.search also={/tikz},
  rainbow polygon/.cd,
  angles/.code={%
    \pgfmathsetmacro\rainbowpolygon@eangle{360/#1}%
    \pgfmathsetmacro\rainbowpolygon@iangle{180-\rainbowpolygon@eangle}%
  },
  last/.code={%
    \pgfmathsetmacro\rainbowpolygon@last{int(#1-1)}%
  },
  line width/.store in=\rainbowpolygon@linewidth,
  sides/.store in=\rainbowpolygon@sides,
  sides/.forward to=/tikz/rainbow polygon/angles,
  sides/.forward to=/tikz/rainbow polygon/last,
  size/.store in=\rainbowpolygon@size,
  rounded outer corners/.is if=rainbowpolygon@rounded@outer,
  rounded inner corners/.is if=rainbowpolygon@rounded@inner,
  rounded corners/.is choice,
  rounded corners/none/.style={/tikz/rainbow polygon/.cd, rounded outer corners=false, rounded inner corners=false},
  rounded corners/outer/.style={/tikz/rainbow polygon/rounded outer corners},
  rounded corners/inner/.style={/tikz/rainbow polygon/rounded inner corners},
  rounded corners/both/.style={/tikz/rainbow polygon/.cd, rounded outer corners, rounded inner corners},
  clip/.style={},
  colours/.code={%
    \setcounter{rainbowpolygon@colours}{0}%
    \edef\tempa{#1}%
    \foreach \i in \tempa {
      \edef\tempb{col\therainbowpolygon@colours}%
      \xglobal\colorlet{\tempb}{\i}%
      \stepcounter{rainbowpolygon@colours}%
    }%
  },
  colours/.default={magenta,blue,green,orange,red,gray},
  defaults/.style={%
    line width=5pt,
    sides=5,
    size=10mm,
    rounded corners=none,
    colours,
  },
}
\makeatother
\begin{document}
\begin{tikzpicture}
  \pic at (0,0) {rainbow polygon={sides=6,colours={blue,blue!80!cyan,blue!60!cyan,blue!40!cyan,blue!20!cyan,cyan}}};
  \pic at (2,0) {rainbow polygon={rounded corners=outer,sides=12}};
  \pic at (0,2) {rainbow polygon};
  \pic at (2,2) {rainbow polygon={rounded corners=both,sides=7,colours={red,orange,yellow,green,blue,purple,magenta},line width=8pt}};
\end{tikzpicture}

\begin{tikzpicture}[line width=5pt]
  \foreach \i in {0,...,4}  \coordinate (p\i) at ({18+\i*72}:1);
  \clip (p0) -- (p1) -- (p2) -- (p3) -- (p4) -- cycle;
  \pgfmathsetmacro\xyz{.5*\pgflinewidth/tan(54)}
  \foreach \i [count=\j from 0, evaluate=\j as \k using {int(mod(\j+1,5))}] in {magenta,blue,green,orange,red} \draw [\i, {Triangle Cap[length=\xyz pt]}-{Triangle Cap[length=\xyz pt]}] (p\j) -- (p\k);
\end{tikzpicture}
\begin{tikzpicture}[line width=5pt]
  \foreach \i in {0,...,4}  \path ({18+\i*72}:1) coordinate (p\i);
  \clip [rounded corners=.5*\pgflinewidth] (p0) -- (p1) -- (p2) -- (p3) -- (p4) -- cycle;
  \pgfmathsetmacro\xyz{.5*\pgflinewidth/tan(54)}
  \foreach \i [count=\j from 0, evaluate=\j as \k using {int(mod(\j+1,5))}] in {magenta,blue,green,orange,red} \draw [\i, {Triangle Cap[length=\xyz pt]}-{Triangle Cap[length=\xyz pt]}] (p\j) -- (p\k);
\end{tikzpicture}
\begin{tikzpicture}[line width=10pt]
  \foreach \i in {0,...,4}  \path ({18+\i*72}:1) coordinate (p\i) ++({18+\i*72:-.5*\pgflinewidth}) coordinate (q\i);
  \clip [rounded corners=.5*\pgflinewidth] (p0) -- (p1) -- (p2) -- (p3) -- (p4) -- cycle (q0) -- (q4) -- (q3) -- (q2) -- (q1) -- cycle;
  \pgfmathsetmacro\xyz{.5*\pgflinewidth/tan(54)}
  \foreach \i [count=\j from 0, evaluate=\j as \k using {int(mod(\j+1,5))}] in {magenta,blue,green,orange,red} \path [fill, \i] (p\j) -- (p\k) -- (0,0) -- cycle;
\end{tikzpicture}
\end{document}
3
  • What wondeful things you can do with TikZ! Could you explain to me this part of the code evaluate=\j as \k using {int(mod(\j+1,5))}? Does it means that j goes from 1 to 5 while k goes from 2 to 5 and then 1? (I don't even try to understand your last example :), but if I could I'd upvote twice!)
    – CarLaTeX
    Jul 28, 2016 at 5:45
  • 1
    int just makes the result an integer. mod is modulo. So \k will be \j+1 modulo 5. This bit doesn't touch \j. It just calculates \k from \j. So, if \j is the count from 0, for example, then \j will be 0,1,2,3,4 and \k will be 1,2,3,4,0. If \j was 0,1,2,3,4,5,6,7, then \k would be 1,2,3,4,0,1,2 etc. (Obviously, we only have 5 values for the pentagon - but just in theory.)
    – cfr
    Jul 28, 2016 at 12:00
  • thank you, I hadn't understood that \j wasn't touched and I know how modulo works but I forgot about 0!
    – CarLaTeX
    Jul 28, 2016 at 13:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .