Just for fun (cough) with TikZ (and PGF decorations).
The biggest part of the decoration code has already been provided by Mark Wilbrow in his answer to Draw additional parallel paths in TikZ. His decoration contour lineto
works very fine but doesn’t deal with closed paths.
To work around this issue, the angle of the first segment (here (A) -- (B)
is saved in \pgf@decorate@firstsegmentangle
and later used if the input segment is a closepath
/-- cycle
.
If the contour line is drawn on the outer (longer) side of the polygon his code for the start
state
\pgfpathmoveto{\pgfpoint{0pt}{\pgfdecoratedcontourdistance}}%
would have been fine
but this point would lie on the outer side of a contour polygon that lies inside the original path. I don’t know a way to access the last segment’s angle to correct this in the very first state for the first segment. As a work-around the actual first segment of the contour line starts halfway between the first points (here, halfway between (A)
and (B)
).
This is sub-optimal. It is advised that the -- cycle
operator actually travels a certain distance (so that an angle can be calculated). A path like
\path (0,0) -| (1,1) -| (0,0) -- cycle;
cannot be decorated successfully.
If the option rounded corners
shall be used on the decorated contour line, the contour
option (and rounded corners
) has to be included in a pre- or postaction.
Code
\documentclass[tikz]{standalone}
\makeatletter
\usetikzlibrary{decorations,backgrounds}
\def\pgfdecoratedcontourdistance{0pt}
\pgfset{
decoration/contour distance/.code=%
\pgfmathsetlengthmacro\pgfdecoratedcontourdistance{#1}}
\pgfdeclaredecoration{contour lineto closed}{start}{%
\state{start}[
next state=draw,
width=0pt,
persistent precomputation=\let\pgf@decorate@firstsegmentangle\pgfdecoratedangle]{%
\pgfpathmoveto{\pgfpointlineattime{.5}
{\pgfqpoint{0pt}{\pgfdecoratedcontourdistance}}
{\pgfqpoint{\pgfdecoratedinputsegmentlength}{\pgfdecoratedcontourdistance}}}%
}%
\state{draw}[next state=draw, width=\pgfdecoratedinputsegmentlength]{%
\ifpgf@decorate@is@closepath@%
\pgfmathsetmacro\pgfdecoratedangletonextinputsegment{%
-\pgfdecoratedangle+\pgf@decorate@firstsegmentangle}%
\fi
\pgfmathsetlengthmacro\pgf@decoration@contour@shorten{%
-\pgfdecoratedcontourdistance*cot(-\pgfdecoratedangletonextinputsegment/2+90)}%
\pgfpathlineto
{\pgfpoint{\pgfdecoratedinputsegmentlength+\pgf@decoration@contour@shorten}
{\pgfdecoratedcontourdistance}}%
\ifpgf@decorate@is@closepath@%
\pgfpathclose
\fi
}%
\state{final}{}%
}
\makeatother
\tikzset{
contour/.style={
decoration={
name=contour lineto closed,
contour distance=#1
},
decorate}}
\begin{document}
\begin{tikzpicture}
\path
(-2, 3) coordinate (A)
( 3, 4) coordinate (B)
( 2,-1) coordinate (C)
(-2,-4) coordinate (D)
(-4, 0) coordinate (E);
\draw[preaction={contour=10pt, rounded corners, fill=gray}]
(A) -- (B) -- (C) -- (D) -- (E) -- cycle;
\foreach \coord in {A,...,E} \fill (\coord) circle [radius=2pt];
\end{tikzpicture}
\begin{tikzpicture}[gridded, line width=.25cm, opacity=.75]
\draw (0,2) rectangle (2,3);
\draw[contour=.5\pgflinewidth] (0,0) rectangle (2,1);
\draw[contour=-.5\pgflinewidth] (3,0) rectangle (4,3);
\path[xshift=5cm,contour=.5\pgflinewidth,draw,line join=round]
(0,0) -| (1,3) -- (2,1) -- (0,1) -- cycle;
\end{tikzpicture}
\end{document}
Output
