0

How can I limit the drawing of a curve defined with \draw .. controls .. to a specific range?

Example: \draw is defined up till x=9, but I would like to stop the \draw for x>=8

 \draw[->] 
  (3,1) .. controls (3.75,1.4) and (4.25,1.4) ..
  (5,1) .. controls (5.75,0.6) and (6.25,0.6) ..
  (7,1) .. controls (7.75,1.4) and (8.25,1.4) ..
  (9,1);
FiLou
  • 1

1 Answers1

2

In your simple case – because you want to stop the curve exactly at half the length and time – you could use the PGF level command \pgfpathcurvebetweentime which has no proper TikZ path operation.

Instead of

(7,1) .. controls (7.75,1.4) and (8.25,1.4) .. (9,1)

you need to write

(7,1) to[shorten controls={0 .. (7.75,1.4) and (8.25,1.4) .. .5}] (9,1)

where the curve is only drawn between times 0 and 1 - .5. (If both are 0 everything of the curve will be drawn.)

You can't place nodes along that path (but I believe that can be implemented pretty easily).

For more complex situation, I think the best would be to use the spath3 library.

I've also added a very similar curve with sin and cos which doesn't give the exact same curve but might be good enough in your case.

Code

\documentclass[tikz]{standalone}
\makeatletter
\tikzset{
  shorten controls/.code args={#1..#2..#3}{
    \pgfutil@in@{and}{#2}%
    \ifpgfutil@in@\expandafter\pgfutil@firstoftwo
      \else\expandafter\pgfutil@secondoftwo\fi
    {\pgfkeysvalueof{/tikz/@shorten controls/.@cmd}#1..#2..#3\pgfeov}
    {\pgfkeysvalueof{/tikz/@shorten controls/.@cmd}#1..#2and#2..#3\pgfeov}%
  },
  @shorten controls/.style args={#1..#2and#3..#4}{
    to path={
      \pgfextra
        \pgfpathcurvebetweentime{#1}{1-(#4)}
          {\tikz@scan@one@point\pgfutil@firstofone(\tikztostart)}
          {\tikz@scan@one@point\pgfutil@firstofone#2}
          {\tikz@scan@one@point\pgfutil@firstofone#3}
          {\tikz@scan@one@point\pgfutil@firstofone(\tikztotarget)}%
      \endpgfextra
    }
  }
}
\makeatother
\begin{document}
\begin{tikzpicture}[dashed]
\draw[->, red, dash phase=3pt] 
  (3,1) .. controls (3.75,1.4) and (4.25,1.4) ..
  (5,1) .. controls (5.75,0.6) and (6.25,0.6) ..
  (7,1) to[shorten controls={0 .. (7.75,1.4) and (8.25,1.4) .. .5}]
  (9,1);
\draw[->, blue] 
  (3,1) sin ++(1,.3) cos ++(1,-.3) sin ++(1,-.3) cos ++(1,.3) sin ++(1,.3);
\end{tikzpicture}

\tikz\draw[->] (3,1) .. controls (3.75,1.4) and (4.25,1.4) .. (5,1) .. controls (5.75,0.6) and (6.25,0.6) .. (7,1) to[shorten controls={0 .. (7.75,1.4) and (8.25,1.4) .. .5}] (9,1); \tikz\draw[->] (3,1) sin ++(1,.3) cos ++(1,-.3) sin ++(1,-.3) cos ++(1,.3) sin ++(1,.3); \end{document}

Output

enter image description here enter image description here enter image description here

Qrrbrbirlbel
  • 119,821
  • There's also \tikz\draw[->] plot[smooth, domain=0:10] (\x/2+3, 1+.3*sin(\x*45); but that's a bit too much. – Qrrbrbirlbel Sep 13 '22 at 11:42
  • @Qrrbrbirblbel thx. Really like your last solution. Small correction. Should be \draw[->] plot[smooth, domain=0:10] ({\x/2+3}, {1+0.4*sin(\x*45)}) – FiLou Sep 13 '22 at 18:33