4

I would like to modify a bezier curve in tikz, e.g.

\draw (0,0) .. controls +(87:2.3) and +(50:-0.7) .. (1,1);

in such a way, that a part in the middle is draw with dots (instead of a full solid line), while the start and the end remain solid. This problem I could solve in priciple with the following MWE (see below), but the parameters pre length= and post length= have to be defined in absolute coordinates. How can I change this in order to specify relative positions (e.g. from 0.3 to 0.8 of the path's length?

In particular, there is a \pgfdecoratedpathlength variable (Length of curve in TikZ), but I don't know how to include this in my dotted part of curve definition without getting errors. Or is there a different, even better approach?

MWE:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings,calc}
\begin{document}

\begin{tikzpicture}[scale=1] % <- except of line/dot width drawing should be independent of scaling

\tikzset{
    dotted part of curve/.style args={between #1 and #2 with color #3}{
        #3,
        decorate,
        decoration={
            markings,
            mark=between positions 0 and 1 step 3*\pgflinewidth with{\fill[radius=\pgflinewidth,#3] (0,0) circle;},
            pre length=#1,
            post length=#2,
            pre=curveto,
            post=curveto,
            %post=moveto, % <-- alternate end: no drawing
        }
    },
    dotted part of curve/.default={between 0.5cm and 0.3cm with color red},
    % dotted part of curve/.default={between 0.3 and 0.8 with color red}, % <-- desired: relative positions
}

\draw (0,0) .. controls +(87:2.3) and +(50:-0.7) .. (1,1);
\draw[dotted part of curve] (0,0) .. controls +(87:2.3) and +(50:-0.7) .. (1,1);

\end{tikzpicture}
\end{document}

black: initial, red: desired path

  • ps: the solution should also work with the alternate approach post=moveto, instead of post=curveto, such that there is no line drawn after the dotted part. – kromuchi Jun 22 '16 at 9:25
  • 2
    are you familiar with meta-decorations? – percusse Jun 22 '16 at 9:36
5

You can use \pgfdecoratedinputsegmentlength:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}

\tikzset{
  dotted part of curve/.style args={between #1 and #2 with color #3}{
    postaction={decorate,draw,#3,
      decoration={
        markings,
        mark=between positions 0 and 1 step 3*\pgflinewidth 
          with{\fill[radius=\pgflinewidth,#3] (0,0) circle;},
        pre=curveto, pre length=#1*\pgfdecoratedinputsegmentlength,
        post=curveto, post length=(1-#2)*\pgfdecoratedinputsegmentlength
  }}},
  dotted part of curve/.default={between 0.3 and 0.8 with color red}
}

\begin{document}
\begin{tikzpicture}[scale=1] 
\draw
  [dotted part of curve]
  (0,0) .. controls +(87:2.3) and +(50:-0.7) .. (1,1);
\end{tikzpicture}
\end{document}

Result:

enter image description here

If post=curveto is replaced by post=moveto the result changes to

enter image description here


If there should be no black line in the background you can use \path instead \draw in the code above:

\path% <-
  [dotted part of curve]
  (0,0) .. controls +(87:2.3) and +(50:-0.7) .. (1,1);

enter image description here

or

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings}

\tikzset{
  dotted part of curve/.style args={between #1 and #2 with color #3}{
    decorate,
    #3,
    decoration={
      markings,
      mark=between positions 0 and 1 step 3*\pgflinewidth 
        with{\fill[radius=\pgflinewidth,#3] (0,0) circle;},
      pre=curveto, pre length=#1*\pgfdecoratedinputsegmentlength,
      post=curveto, post length=(1-#2)*\pgfdecoratedinputsegmentlength
  }},
  dotted part of curve/.default={between 0.3 and 0.8 with color red}
}

\begin{document}
\begin{tikzpicture}[scale=1] 
\draw
  [dotted part of curve]
  (0,0) .. controls +(87:2.3) and +(50:-0.7) .. (1,1);
\end{tikzpicture}
\end{document}
  • Nice result! I would only change the outer decoration declaration back to #3,decorate,decoration={...} as I don't want to see the black line later (this was added only for demonstration purposes). Apparently, I did't specify this correctly in my question. – kromuchi Jun 22 '16 at 11:23
  • @kromuchi I have updated my answer. – esdd Jun 22 '16 at 20:43
  • using \path instead \draw is even better. thanks! – kromuchi Jun 23 '16 at 7:59
4

For a single Bézier curve the basic layer \pgfpathcurvebetweentime command may be useful and certainly much more efficient than a decoration. Unfortunately, there is no TikZ interface by default, but a somewhat crude (although serviceable) approach is shown below:

\documentclass[tikz,border=5]{standalone}
\tikzset{part curve/.style args={%
  from #1 to #2 curve #3 .. controls #4 and #5 .. #6}{insert path={
    #3 coordinate (@1) #4 coordinate (@2)
    #5 coordinate (@3) #6 coordinate (@4)
    \pgfextra{\pgfpathcurvebetweentime{#1}{#2}%
      {\pgfpointanchor{@1}{center}}{\pgfpointanchor{@2}{center}}%
      {\pgfpointanchor{@3}{center}}{\pgfpointanchor{@4}{center}}}
}}}
\begin{document}
\begin{tikzpicture}
\path
  (0,0) coordinate (P1)
  +(87:2.3) coordinate (P2)
  (1,1) coordinate (P4)
  +(50:-0.7) coordinate (P3);
\draw [help lines] (P1) .. controls (P2) and (P3) .. (P4);
\draw [red, thick,
  part curve={from 0.0 to 0.3 curve (P1) .. controls (P2) and (P3) .. (P4)}];
\draw [green!50!black, thick, dotted,
  part curve={from 0.3 to 0.8 curve (P1) .. controls (P2) and (P3) .. (P4)}];
\draw [blue, thick, dashed,
  part curve={from 0.8 to 1.0 curve (P1) .. controls (P2) and (P3) .. (P4)}];
\end{tikzpicture}
\end{document}

enter image description here

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.