1

I am trying to decorate a path using random steps and direction, and also draw normal arrows on each segment.

I am facing multiple problems:

  • The random part alone works well, but in order to draw the arrows I need to reposition the starting point, which has to be on the segment, and I am not able to determine the location where the last segment ended; I tried to get its coordinates with \pgfgetlastxy, but they seem to be limited to the state scope, and reset to 0 when a new state is entered (even if the same state is repeated). Using this command at the beginning of the state instead of the end does not help. I hence obtain a "broken" path.
  • The normal vector do not look normal (except the second); however the two arrows are on the same line, pointing to opposite directions, as expected. I do not understand the reason: is it a machine precision problem? Can it be solved?
  • The options of the draw command (red,thick it this case) are only applied to the last segment.

Here is the code I used (the \newcommand at line 6 is used to have the same random angle three times in the state instead of three different random angles), and the relative output.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing,positioning,calc,arrows}

\pgfdeclaredecoration{irregularArrows}{start}{
  \newcommand{\SetAngle}{\pgfmathsetmacro{\Angle}{\pgfmathresult * \pgfdecorationsegmentangle}}
  \pgfmathsetmacro{\Startx}{\pgfdecorationsegmentlength}
  \pgfmathsetmacro{\Starty}{0}
  \state{start}[width=\pgfdecorationsegmentlength]{
    \pgfmathrand{}
    \SetAngle{}
    \pgfmathsetmacro{\Startx}{\Startx - \pgfdecorationsegmentlength}
    \pgfsetarrowsend{>}
    \pgfpathmoveto{\pgfpoint{\Startx}{\Starty}}
    \pgfpathlineto{\pgfpointadd{\pgfpoint{\Startx}{\Starty}}{\pgfpointpolar{\Angle + 90}{6}}}
    \pgfusepath{stroke}
    \pgfpathmoveto{\pgfpoint{\Startx}{\Starty}}
    \pgfpathlineto{\pgfpointadd{\pgfpoint{\Startx}{\Starty}}{\pgfpointpolar{\Angle - 90}{6}}}
    \pgfusepath{stroke}
    \pgfpathmoveto{\pgfpoint{\Startx}{\Starty}}
    \pgfpathlineto{\pgfpointadd{\pgfpoint{\Startx}{\Starty}}{\pgfpointpolar{\Angle}{random * \pgfdecorationsegmentlength}}}
    \pgfgetlastxy{\Startx}{\Starty}
  }
  \state{final}{
    \pgfpathlineto{\pgfpointdecoratedpathlast}
  }
}

\tikzset{
  boundaryArrows/.style={decoration={irregularArrows, segment length = 3cm, angle = 30},
    decorate,
  },
}

\begin{document}
\pgfmathsetseed{3}
\begin{tikzpicture}
  \node[coordinate] (left) at (-10cm, 0) {};
  \node[coordinate] (right) at (10cm, 0) {};
  \draw[red,thick]{decorate[boundaryArrows]{(left) -- (right)}};
\end{tikzpicture}
\end{document}

Output


The code above aims at being minimal; however, in the unlikely event of my actual problem being simpler, I also include it: what I need is only one pair of arrows (which I am able to achieve using more states), positioned at about the middle of the segment (which I believe I will be able to determine once I understand hot to get the coordinates of the starting point).

2

Welcome! I was not able to fully digest your code because the macros have very long names and it is somewhat hard to stay on track. This answer is to remind you that one can nest decorations. So in order to add the arrows to each line segment one can use an appropriate adaption of show path construction. This can be used on a path subject to the random steps decoration.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta,calc,decorations.pathmorphing,decorations.pathreplacing}
\tikzset{some arrow/.style={decorate,
decoration={show path construction, 
moveto code={},
lineto code={
\draw[-Stealth] (\tikzinputsegmentfirst) --  (\tikzinputsegmentlast);
\draw[latex-latex] 
($(\tikzinputsegmentfirst)!6pt!90:(\tikzinputsegmentlast)$) 
-- ($(\tikzinputsegmentfirst)!6pt!-90:(\tikzinputsegmentlast)$);
},
curveto code={},
closepath code={},
}}}

\tikzset{
  rrr/.style={decoration={random steps,amplitude=6pt, 
  segment length = 1.5cm},
    decorate,
  }}

\begin{document}
\pgfmathsetseed{3}
\begin{tikzpicture}
  \node[coordinate] (left) at (-10cm, 0) {};
  \node[coordinate] (right) at (10cm, 0) {};
  \draw[red,thick,some arrow]{decorate[rrr]{(left) -- (right)}};
\end{tikzpicture}
\end{document}

enter image description here

| improve this answer | |
  • I shortened the macros; although I like long names, I understand that namespacing them was probably not a good idea in an short example. I cannot do much to the long names of pgf macros. – user408672 May 7 at 10:08
  • Your arrows look certainly more perpendicular than mine. I can get rid of the horizontal arrow deleting Stealth at line 7, and I can move them inside the segment changing the angles from 90 to something else. However you did not modify the decoration, so my plan of getting just one arrow for the whole path using more states do not apply, and I need an alternative for that. I also still do not understand why the red,thick options are ignored. – user408672 May 7 at 10:09
  • @user408672 It is certainly true that I do not fully understand what you want to achieve. But looking at your code there is one comment which may help: the decoration "moves along the path on its own", so you do not have to compute things like \pgfmathsetmacro{\Startx}{\Startx - \pgfdecorationsegmentlength}. At the same time, the decoration puts you in local coordinate systems so that \pgfgetlastxy{\Startx}{\Starty} won't give you the coordinates you probably want. You can define coordinates like \pgfcoordinate{irregularArrowslast}{\pgfpoint{0pt}{0pt}} ... – user194703 May 7 at 13:32
  • .... to access the previous coordinate \pgfpathmoveto{\pgfpointanchor{irregularArrowslast}{center}}. I played tiny bit with your code but unfortunately I am completely lost, cannot tell how lines in your code relate to what you want to achieve, and I am not even sure I understand what you want to achieve. However, as for your question why the color behaves the way it does: this is because of the \pgfusepath{stroke} commands you place which get execute before the stroke color gets set. – user194703 May 7 at 13:35
  • I want something similar to your result but: (1) the horizontal arrows should not be present (easy, removing Stealth at line 7); (2) I want the arrows to be placed in the middle of the segment (also easy, change 90 with something else at lines 9-10) (3) I actually want only one pair of arrows, say in the second line. I know how to do that modifying the decoration (provided that I manage to correctly draw the arrows once), but I do not know if it is possible in your example. (4) I want to be able to colour the path – user408672 May 7 at 14:29

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.