# Creating a line of given length with variable number of “snags” equally separated (TikZ)?

I want to achieve the following in TikZ:

To get the exact width of the line I have no issues with - the problem lies in adding an arbitrary number of snags along the line which are equally distanced apart. I would also like to be able to add text between the snags (like 0, 1, 2, ..., but that's just an example) And I don't want to add and position the snags manually because I believe TikZ will do a much better job for me. But how?

-

You could use the border decoration implemented in TikZ (see the manual, page 324). Unfortunately, the decoration does not draw the last tick on a line, so I did some workaround drawing a second decoration backwards:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{decorations}
\usetikzlibrary{decorations.pathreplacing}

\newcommand{\tickedline}[6]{% Start, End, line options, segment length, amplitude, angle
\begin{scope}[decoration={border, segment length=#4, amplitude=#5, angle=#6}]%
\draw[#3,postaction={decorate,draw}] (#1) -- (#2);%
\draw[decoration={border, segment length=#4, amplitude=#5, angle=180-#6, mirror}, #3, postaction={decorate,draw}] (#2) -- (#1);%
\end{scope}%
}

\begin{document}

\begin{tikzpicture}
\tickedline{0,0}{5.7,0}{thin, green}{3mm}{5mm}{45}
\tickedline{1,1}{6,1}{very thick, red}{5mm}{2mm}{90}
\tickedline{0,2}{5,5}{thick, blue}{2mm}{4mm}{38}
\end{tikzpicture}

\end{document}


Some examples:

You may notice that the first and last blue line are thinner than all the others. This is due to the fact that I draw a forward and a backward decorarion, and that the length of the line is no integer multiple of the line width. So one has to either choose appropriate segment lengths for your linewidth or find a way to force TikZ to draw the decoration line on the last segment.

Edit 1: I solved the issue. Instead of specifying the segment length, you can now either specify the number of segments or the number of ticks (which is segments+1):

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{decorations}
\usetikzlibrary{decorations.pathreplacing}

\newcommand{\tickedline}[6]{% Start, End, line options, segment length, amplitude, angle
\begin{scope}[decoration={border, segment length=#4, amplitude=#5, angle=#6}]%
\draw[#3,postaction={decorate,draw}] (#1) -- (#2);%
\draw[decoration={border, segment length=#4, amplitude=#5, angle=180-#6, mirror}, #3, postaction={decorate,draw}] (#2) -- (#1);%
\end{scope}%
}

\newcommand{\tikzsegments}[8]{% x1,y1, x2,x2, line options, number of segments, amplitude, angle
\pgfmathsetmacro{\lengthsegment}{sqrt(pow(#3-#1,2)+pow(#4-#2,2))/#6}
\begin{scope}[decoration={border, segment length=\lengthsegment cm, amplitude=#7, angle=#8}]%
\draw[#5,postaction={decorate,draw}] (#1,#2) -- (#3,#4);%
\draw[decoration={border, segment length=\lengthsegment cm, amplitude=#7, angle=180-#8, mirror}, #5, postaction={decorate,draw}] (#3,#4) -- (#1,#2);%
\end{scope}%
}

\newcommand{\tikzticks}[8]{% x1,y1, x2,x2, line options, number of ticks, amplitude, angle
\pgfmathsetmacro{\lengthsegment}{sqrt(pow(#3-#1,2)+pow(#4-#2,2))/(#6-1)}
\begin{scope}[decoration={border, segment length=\lengthsegment cm, amplitude=#7, angle=#8}]%
\draw[#5,postaction={decorate,draw}] (#1,#2) -- (#3,#4);%
\draw[decoration={border, segment length=\lengthsegment cm, amplitude=#7, angle=180-#8, mirror}, #5, postaction={decorate,draw}] (#3,#4) -- (#1,#2);%
\end{scope}%
}

\begin{document}

%\begin{tikzpicture}
%\tickedline{0,0}{5.7,0}{thin, green}{3mm}{5mm}{45}
%\tickedline{1,1}{6,1}{very thick, red}{5mm}{2mm}{90}
%\tickedline{0,2}{5,5}{thick, blue}{2mm}{4mm}{38}
%\end{tikzpicture}

\begin{tikzpicture}
\tikzsegments{0}{0}{5.7}{0}{thin, green}{19}{5mm}{45}
\tikzsegments{1}{1}{6}{1}{very thick, red}{14}{2mm}{90}
\tikzsegments{0}{2}{5}{5}{thick, blue}{30}{4mm}{38}
\end{tikzpicture}
\hspace{2cm}
\begin{tikzpicture}
\tikzticks{0}{0}{5.7}{0}{thin, green}{11}{5mm}{45}
\tikzticks{1}{1}{6}{1}{very thick, red}{11}{2mm}{90}
\tikzticks{0}{2}{5}{5}{thick, blue}{11}{4mm}{38}
\end{tikzpicture}

\end{document}


Now even on non-horizontal lines it works fine:

-
These decorations bring back the AutoCAD days, yuck :) –  percusse Sep 30 '11 at 11:22

Here you have an example. A new command \drawsnags with three parameters, starting point, line length and number of snags.

\documentclass[border=3mm]{standalone}
\usepackage{tikz}

%\drawsnags{starting point}{line width}{number of snags}
\newcommand{\drawsnags}[3]{
\draw[line width=3pt, line cap=rect] #1--++(#2,0);
\foreach \i in {0,...,#3}
\draw[line width=3pt,shift={#1}] ({\i*#2/#3},0) --++(0,0.2);}

\begin{document}
\begin{tikzpicture}
\drawsnags{(0,0)}{5}{3};
\drawsnags{(0,2)}{8}{5};
\drawsnags{(1,-1)}{3}{4};
\end{tikzpicture}
\end{document}


You will have to adjust joins at starting and ending point.

EDIT: Following Andrew's suggestion I've added line cap=rect option. The new result is:

Still not perfect but better.

-
With regard to the joins at the starting and ending point, if you put line cap=rect on the horizontal line then it looks better (though I find that on different zooms I get different values of "better"). –  Loop Space Sep 30 '11 at 9:43
Re the "still not perfect", this is what I meant about different zooms. If I zoom to 400% then it looks fine, so I think it's a rendering issue. One way to ensure that it looked fine would be for the first and last to be part of the initial path and then use the foreach to draw only the inner ones. –  Loop Space Sep 30 '11 at 13:11