22

How can parallel lines elegantly be added to an existing path? I am looking for a solution or hint to, how a general style can be made, that works with any path.

Example path:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
  \draw (0,0) -- (1,1) -| (2,2) -- (3,2) -- (3,1);
\end{tikzpicture}
\end{document}

original path

Same path, with customizable extra lines:

path with extra parallel lines

Here I have drawn two extra lines, just to show, what I mean. Ideally a solution should only add one extra line, but somehow be expandable to any number of lines.

The question: How to build parallel paths between nodes?, where my solution is less than elegant, has inspired me to ask this question.

5
  • I'm not sure if the "parallel path" is well defined. Intuitively I can see what you mean, but, what would be its mathematical definition? For example, lets say that the parallel path at distance X is the path such that, at every point, the minimal distance of that point to the original path is X. This sound a reasonable definition, but would produce rounded corners instead of angles...
    – JLDiaz
    Mar 17, 2013 at 23:45
  • @JLDiaz: I see your point. Let us say our original path is closed and not self intersecting (a 'loop' of sort). Then you can take each line segment and shift it parallel outward(or inward). Extend(or shorten) the line segments, to make the new path. I am sure that similar ideas can be applied to the general path. Mar 17, 2013 at 23:55
  • Does the path consist of straight line segments only?
    – g.kov
    Mar 18, 2013 at 1:28
  • @g.kov: I must admit, that I do not have an actual application for this ...yet. I am sure that a solution that works for straight line segments will be useful for me and others. Mar 18, 2013 at 1:42
  • What (I think) is required here, is what vector graphics applications call "outsetting" and "insetting" (usually with closed paths). The shifting/shortening approach is (very) broadly correct, but AFAIK you also need to take into account the angle between consecutive segments. It's ages since I looked at this, but I think a segment should be lengthened by -h*cot(A/2) (A is the angle between segments, h is the outset distance). Mar 18, 2013 at 10:13

2 Answers 2

20

It turns out some of the work is already done, but an important macro \pgfdecoratedangletonextinputsegment is undocumented (and incorrectly defined - possibly why it is undocumented). Here's a not-very-well tested solution for straight lines only with no mid-path moveto commands. I think dealing with curveto and closepath segments will also prove extra-tricky.

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations}

\def\pgfdecoratedcontourdistance{0pt}

\pgfkeys{/pgf/decoration/contour distance/.code={%
    \pgfmathparse{#1}%
    \let\pgfdecoratedcontourdistance=\pgfmathresult}%
}

\pgfdeclaredecoration{contour lineto}{start}
{
    \state{start}[next state=draw, width=0pt]{
        \pgfpathmoveto{\pgfpoint{0pt}{\pgfdecoratedcontourdistance}}%
    }
    \state{draw}[next state=draw, width=\pgfdecoratedinputsegmentlength]{       
        \pgfmathparse{-\pgfdecoratedcontourdistance*cot(-\pgfdecoratedangletonextinputsegment/2+90)}%
        \let\shorten=\pgfmathresult%
        \pgfpathlineto{\pgfpoint{\pgfdecoratedinputsegmentlength+\shorten}{\pgfdecoratedcontourdistance}}%  
    }
    \state{final}{
        \pgfpathlineto{\pgfpoint{\pgfdecoratedinputsegmentlength}{\pgfdecoratedcontourdistance}}%
    }   
}

\begin{document}

\begin{tikzpicture}

\draw [
    postaction={
        decoration={contour lineto, contour distance=-5pt},
        draw=red, dotted, decorate},
    postaction={
        decoration={contour lineto, contour distance=15pt}, 
        draw=blue, dashed, decorate},
    postaction={
        decoration={contour lineto, contour distance=10pt}, 
        draw=green, decorate}
    ] 
    (0, 0) -- (3, 1) -- (4, 4) -- (6, 4) -- 
    (8,-1) -- (2,-2) -- (5, 2) -- (6, 0);

\end{tikzpicture}


\end{document}

contour example

4
  • This looks like it is exactly, what I imagined. Does your comment about an incorrectly defined macro means, that there is anything wrong with this code? When time permits, I will try to understand the low level part of your code. Mar 18, 2013 at 16:43
  • 1
    Check out closed path, e.g. (0,0)--(6,0)--(3,4.5)--cycle; It might be a good idea to add edge constrains as the lines that intersect the path at the first and the last point.
    – g.kov
    Mar 19, 2013 at 6:03
  • 1
    @Hans-PeterE.Kristiansen: in the low-level decorations code the macro is (for some reason) defined as B-A instead of A+180-B where A and B are the angle from the horizontal of consecutive segments. The calculation in the cot function given above takes this into account. @k.gov: As it says in the answer "dealing with ... closepath segments will prove extra-tricky". By "extra-tricky", I mean probably impossible to do with out ugly hacking. Mar 19, 2013 at 6:55
  • 1
    I’d love your input on this answer which uses almost all of your decoration code. Sep 16, 2013 at 22:03
6

I just found the nfold library from 2023 by Jonathan Schulz. It can do exactly that - also for Bézier curves and closed curves.

\documentclass[tikz, border=1cm]{standalone}
\usetikzlibrary{nfold}
\begin{document}
\begin{tikzpicture}
\draw[save path=\savedpath] (0,0) -- (1,1) -| (2,2) -- (3,2) -- (3,1) to[bend left] (2,0) --cycle;
\pgfoffsetpath{\savedpath}{-4pt}
\pgfsetlinewidth{2pt} \color{red} \pgfusepathqstroke
\pgfoffsetpath{\savedpath}{10pt}
\pgfsetdash{{1pt}{1pt}}{0cm} \pgfsetlinewidth{1pt} \color{blue} \pgfusepathqstroke
\end{tikzpicture}
\end{document}

Three curves inside each other

I do not know if this can be made into a high level TikZ \draw.

You must log in to answer this question.

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