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

2
  • 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
    Commented Jun 22, 2016 at 9:25
  • 2
    are you familiar with meta-decorations?
    – percusse
    Commented Jun 22, 2016 at 9:36

2 Answers 2

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}
3
  • 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
    Commented Jun 22, 2016 at 11:23
  • @kromuchi I have updated my answer.
    – esdd
    Commented Jun 22, 2016 at 20:43
  • using \path instead \draw is even better. thanks!
    – kromuchi
    Commented Jun 23, 2016 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

You must log in to answer this question.

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