3

If I draw a path with the -|(horizontal-first-then-vertical) or |- (vertical-first-then-horizontal) commands and decorate the path with the snake-morphing operation, the latter half of the path is misplaced.

Here is an example:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}

\begin{document}
\begin{figure}
\centering
\begin{tikzpicture}
\path[draw=red,  ->]                              (0,0) -| (5,5);
\path[draw=black,->,decorate,decoration={snake}]  (0,0) -| (5,5);
\end{tikzpicture}
\caption{Wrong}
\end{figure}
\begin{figure}
\centering
\begin{tikzpicture}
\path[draw=red,  ->]                              (0,0) -| (5,5);
\path[draw=blue,->,decorate,decoration={snake}]   (5,0) -- (5,5);
\end{tikzpicture}
\caption{Correct}
\end{figure}
\end{document}

In this special case the (black) vertical part has an offset by the same amount as the amplitude of the snake, i.e. the black sine curve is not centered around the red vertical path. The second figure shows how the sine curve is actually expected to look like (cp. blue curve).

The amount of displacement varies with the actual values of the coordinates and it happens to look really ugly in combination with the arrow head, because the arrow remains centered at the correct position.

How do I fix this?

2
  • This is not related to -| as you can check this by replacing it by (0,0) -- (5,0) -- (5,5). This looks like an imprecision bug to me.
    – Kpym
    Mar 22, 2019 at 19:03
  • 1
    @marmot As I said, I would like to have the second half of the path’s decoration to be centered around its middle line the same way as it happens to be, if I only draw the vertical part as in the 2nd example. Yes, I understand that this causes problems or ugly artifacts at the corner, however I would rather prefer that than the misalignment at the arrow heads.
    – nagmat84
    Mar 23, 2019 at 16:35

1 Answer 1

3

Here is a way to resolve it. It is based on tobias closed zigzag, where neither closed nor zigzag are important. What is, however, important is that the local extrema get shifted in tangent space, see this picture. Result:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}

\begin{document}


\pgfdeclaredecoration{centered zigzag}{initial}{
\state{initial}[
        width=+0pt,
        next state=big down,
        persistent precomputation={
            \pgfmathsetmacro{\myint}{int(\pgfdecoratedinputsegmentlength/\pgfdecorationsegmentlength)}
            \ifodd\myint
             \pgfmathsetmacro\matchinglength{
             \pgfdecoratedinputsegmentlength / int(1+\pgfdecoratedinputsegmentlength/\pgfdecorationsegmentlength)}
            \else
             \pgfmathsetmacro\matchinglength{
             \pgfdecoratedinputsegmentlength / int(\pgfdecoratedinputsegmentlength/\pgfdecorationsegmentlength)}
            \fi
            \setlength{\pgfdecorationsegmentlength}{\matchinglength pt}
            \pgfmathsetmacro{\myint}{int(\pgfdecoratedinputsegmentlength/\pgfdecorationsegmentlength)}
        }] {
        \pgfcoordinate{zigzag-cycle-start}{\pgfqpoint{0pt}{-\pgfdecorationsegmentamplitude}}
        \pgfpathmoveto{\pgfqpoint{0pt}{0pt}}
        }
  \state{big down}[switch if less than=+.5\pgfdecorationsegmentlength to center finish,
                   width=+.5\pgfdecorationsegmentlength,
                   next state=big up]
  {
    \pgfpathlineto{\pgfqpoint{0pt}{-\pgfdecorationsegmentamplitude}}
  }
  \state{big up}[switch if less than=+.5\pgfdecorationsegmentlength to center finish,
                 width=+.5\pgfdecorationsegmentlength,
                 next state=big down]
  {
    \pgfpathlineto{\pgfqpoint{0pt}{\pgfdecorationsegmentamplitude}}
  }
  \state{center finish}[width=0pt, next state=final]{
   % this state is unecessary at the moment
  }
  \state{final}
  {
  }
}
\begin{figure}
\centering
\begin{tikzpicture}
\path[draw=red,  ->]                              (0,0) -| (5,5);
\path[draw=blue,->,decorate,rounded corners,decoration={
            centered zigzag,
            segment length=10pt,
            amplitude=2mm
        }] (0,0) -| (5,5);
\end{tikzpicture}
\caption{Centered zigzag with rounded corners.}
\end{figure}
\end{document}

enter image description here

3
  • (+1) It is awesome, but not simple at all :))
    – user156344
    Mar 23, 2019 at 6:14
  • Thank’s! That is exactly what I was looking for. The start and end of the decoration is placed correctly while accepting some deformation at the corner. However, I am surprised that the solution is as complicated as defining its own decoration. I had expected this behavior to be the default of the provided standard decoration.
    – nagmat84
    Mar 23, 2019 at 16:44
  • @nagmat84 I would like to argue that the "tobias" prescription of defining the decorations should be the default one. That is, when the decoration is being built up by drawing many straight segments in tangent space, the centers and not the left-most points in tangent space should be used to draw a segment. (I am not good at explaining, I am afraid, but what I want to say is expressed in this picture.
    – user121799
    Mar 23, 2019 at 16:48

You must log in to answer this question.

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