3

I'm trying to create a format for arrows in tikzcd which is effectively a stretched tilde: arrow example

I have drawn this example using Option 1 in this answer, but I have had to manually calculate the correct segment length for the snake.

Is there a way to calculate this automatically? Say for example:

arrows={decorate, decoration={snake, segment length=DISTANCE/2, amplitude=0.5mm}}

If not, is there an alternative approach?

Any help would be much appreciated.

Dave
  • 235
  • Here there is a possible solution also with tikz-cd. https://tex.stackexchange.com/questions/87204/wavy-arrows-in-xy-pic – Sebastiano Jan 10 '21 at 13:07
  • 1
    Thanks for the comment. I'm currently using one of the answers to that question, but the number of "waves" in the arrow varies according to the length of the arrow. I'm trying to get a single "wave" regardless of the length, and can't see an obvious way to adapt the answers given there to achieve this. – Dave Jan 10 '21 at 13:53

1 Answers1

2

I have a partial solution based on this answer.

I have copied their helper macro in its entirety, along with most of the first half of their style definition. The only code I am responsible for is that which is below the comment "Draw the wave":

\makeatletter

% This helper macro finds the start and endpoints of a line between the source and target nodes and stores them in \sourcecoordinate and \targetcoordinate. % #1 -- source node % #2 -- target node \def\findedgesourcetarget#1#2{ \let\sourcecoordinate\pgfutil@empty \ifx\tikzcd@startanchor\pgfutil@empty % Check that the source doesn't have a specified anchor \def\tempa{\pgfpointanchor{#1}{center}}% if so, start by taking the center of that coordinate \else \edef\tempa{\noexpand\pgfpointanchor{#1}{\expandafter@gobble\tikzcd@startanchor}} % If it has an anchor, use that \let\sourcecoordinate\tempa \fi \ifx\tikzcd@endanchor\pgfutil@empty % check that the target doesn't have a specified anchor \def\tempb{\pgfpointshapeborder{#2}{\tempa}}% if so, our end point is the point on the boundary of node b that is in the direction of our initial start coordinate \else \edef\tempb{\noexpand\pgfpointanchor{#2}{\expandafter@gobble\tikzcd@endanchor}}% If it has a specified anchor, use that \fi \let\targetcoordinate\tempb \ifx\sourcecoordinate\pgfutil@empty% \def\sourcecoordinate{\pgfpointshapeborder{#1}{\tempb}}% \fi }

\tikzset{wave/.style = { -, to path={\pgfextra{ \findedgesourcetarget{\tikzcd@ar@start}{\tikzcd@ar@target} % find endpoints % Rotate coordinate system so that line goes in x direction \ifx\tikzcd@startanchor\pgfutil@empty \def\tikzcd@startanchor{.center} \fi \ifx\tikzcd@endanchor\pgfutil@empty \def\tikzcd@endanchor{.center} \fi \pgfmathanglebetweenpoints{\pgfpointanchor{\tikzcd@ar@start}{\expandafter@gobble\tikzcd@startanchor}}{\pgfpointanchor{\tikzcd@ar@target}{\expandafter@gobble\tikzcd@endanchor}} \pgftransformrotate{\pgfmathresult} % Draw the wave \newdimen\xdiff \pgfextractx{\xdiff}{\pgfpointdiff{\sourcecoordinate}{\targetcoordinate}} \newdimen\ydiff \pgfextracty{\ydiff}{\pgfpointdiff{\sourcecoordinate}{\targetcoordinate}} \newdimen\finalDist \pgfmathparse{abs(veclen(\xdiff,\ydiff))*0.85} \pgfmathsetlength\finalDist{\pgfmathresult pt}

\pgfmathsetlength\pgfdecorationsegmentlength{\finalDist}

\pgfmathparse{0.038*\finalDist+0.6}
\pgfmathsetlength\pgfdecorationsegmentamplitude{\pgfmathresult pt}

\pgfsetarrows{->}

\pgfpathmoveto{\sourcecoordinate}
\pgfpathsnaketo{snake}{\targetcoordinate}

\pgfusepath{stroke}

}}}}

\makeatother

Using the helper macro, I retrieve the points to be joined and calculate the distance between them. I then use this to define the amplitude and segment length of the snake.

The constants I use in these definitions appear arbitrary, I found them through trial and improvement, but I'll work on a more rigorous approach.


Then

\begin{center}
    Original method:
    \begin{tikzcd}[arrows={decorate, decoration={snake,segment length=7.3mm, amplitude=0.5mm}}]
        A \arrow[r,"",decorate=true] & B
    \end{tikzcd}
\end{center}
\hspace{2cm}
\begin{center}
    Custom style
    \begin{tikzcd}
        A \arrow[r, wave] & B & & \\
        A \arrow[rr, wave] & & B & \\
        A \arrow[rrr, wave] & & & B
    \end{tikzcd}
\end{center}

gives results comparison


My main issue currently is that labels above the arrows no longer work. I will try to fix this, and update this answer if I can.

If anybody has a simpler approach which avoids such problems then please let me know!

Dave
  • 235