# How to draw tangent lines at control points of a path in TikZ?

I'm drawing smooth paths by using the

\draw plot[smooth, tension=.7] coordinates ...


command. Now I would like to draw tangents at the specified coordinates. I alreade tried Jake's answer, but I cannot figure out how to define the tangent points at certain coordinates instead of path positions like 0.4.

My current code is the following:

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

\begin{document}
\begin{tikzpicture}[scale=0.35, transform shape,
tangent/.style={
decoration={
markings,% switch on markings
mark=
at position #1
with
{
\coordinate (tangent point-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,0pt);
\coordinate (tangent unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (1,0pt);
\coordinate (tangent orthogonal unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0pt,1);
}
},
postaction=decorate
},
use tangent/.style={
shift=(tangent point-#1),
x=(tangent unit vector-#1),
y=(tangent orthogonal unit vector-#1)
},
use tangent/.default=1
]

\begin{scope}[every node/.style={fill,draw,blue!50,thick,circle}]
\draw[thick, tangent=0.9] plot[smooth, tension=.7] coordinates {(-8,5) (-5.5,7) (-3,5.5)};
\node (m1) at (-8,5)   {};
\node (m2) at (-5.5,7) {};
\node (m3) at (-3,5.5) {};
\draw [blue, use tangent] (-0.5,0) -- (0.5,0);
\end{scope}

\begin{scope}[every node/.style={fill,draw,red!50,thick,circle}, rotate=8, shift={(-0.5,3.5)}]
\draw[thick] plot[smooth, tension=.7] coordinates {(-8,5) (-5.5,7) (-3,5.5)};
\node at (-8,5)   {} edge (m1);
\node at (-5.5,7) {} edge (m2);
\node at (-3,5.5) {} edge (m2);
\end{scope}

\end{tikzpicture}
\end{document}


I would like to draw tangent lines at the blue nodes and then replace the three direct connection lines by lines which start at the red nodes and finish orthogonally at the tangent lines:

-
Have a look at this question. I thought of using the -| systax together with Jake's answer, but unfortunately it didn't work. It could however be a starting point. – Tom Bombadil Sep 8 '12 at 17:11
Well, maybe you didn't see it, but I already put a link to this question into my post and tried to use Jake's answer in my code :-) – ph4nt0m Sep 8 '12 at 20:19
Ahem, yes, you're right. I just glanced at the question, it reminded me of the linked question, and then I started tickering around. Sorry for informing you of stuff you already knew ;) – Tom Bombadil Sep 8 '12 at 20:43

It didn't turn out to be as easy-to-use as I would thought about it but here is one possibility.

You first name your curves with curve prefix key and then draw them with some custom mark type my mark which places marks. An advantage is that you don't put extra nodes but as a shortcoming you have to provide mark indices={1,...,n} to actually number the marks. Also the end points are excluded from this process but you can use Jake's style anyway since pos=0 or pos=1 is always the point you wish to draw tangent from.

The node names are always names as (tpt-<curve prefix>-<mark number>) and you have to use the get tangle=<mark number> of <curve prefix>. You then use it to rotate the drawing to draw the custom tangent line.

Just put the code between \makeatletter ... \makeatother somewhere in the preamble.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{plotmarks}

\makeatletter
\tikzset{curve prefix/.code={
\xdef\pgf@mark@prefix{#1}
}
}
\tikzset{get tangle/.code args={#1 of #2}{% Looks at the previous and next marks and fakes a tangent
\pgfmathparse{int(#1-1)}
\pgfpointanchor{tpt-#2-\pgfmathresult}{center}
\pgf@xa=\pgf@x\pgf@ya=\pgf@y
\pgfmathparse{int(#1+1)}
\pgfpointanchor{tpt-#2-\pgfmathresult}{center}
\pgf@xb=\pgf@x\pgf@yb=\pgf@y
\pgfpointdiff{\pgfpoint{\pgf@xa}{\pgf@ya}}{\pgfpoint{\pgf@xb}{\pgf@yb}}
\pgfmathparse{atan2(\pgf@x,\pgf@y)}
\xdef\tangle{\pgfmathresult}
}
}

\pgfdeclareplotmark{my mark}% Places coordinates on the marks to be used above
{\pgfsetfillcolor{\pgf@mark@color}\pgfpathcircle{\pgfpoint{0cm}{0cm}}{1ex}\pgfusepathqfill
\pgfcoordinate{tpt-\pgf@mark@prefix-\the\pgf@plot@mark@count}{\pgfpointorigin}
}
\makeatother

\begin{document}
\begin{tikzpicture}
%First Curve
\draw[thick,curve prefix=a] plot[mark color=blue!50,mark=my mark,mark indices={1,...,5},smooth,tension=0.7]
coordinates {(-8,5) (-5.5,2) (-3,5.5) (-1,-2) (1,3)};

% Second curve
\begin{scope}[every node/.style={fill,draw,red!50,thick,circle}, rotate=8, shift={(-0.5,3.5)}]
\draw[thick,curve prefix=b] plot[mark color=red,mark=my mark,mark indices={1,...,4},smooth,tension=0.7]
coordinates {(-8,5) (-5.5,7) (-3,5.5) (0,3)};
\end{scope}

% First tangent drawing
\draw[get tangle=2 of a,dashed,ultra thick,purple,rotate=\tangle] (tpt-a-2) -| (tpt-b-2) (tpt-a-2) -| (tpt-b-4);

% Second tangent drawing
\draw[get tangle=4 of a,dashdotted,ultra thick,orange,rotate=\tangle] (tpt-a-4) -| (tpt-b-3) (tpt-a-4) -| (tpt-b-1);

\end{tikzpicture}
\end{document}


-
+1 Beautiful answer. In fact, with smooth plot, is tangent in point i always parallel to a line through points i-1 and i+1? How to use your solution with hobby curves? – Paul Gaborit Sep 10 '12 at 6:12
@PaulGaborit Thank you! We're actually exploiting the fact that the line that connects the control points at i are always parallel to the line i-1 and i+1. So, tension scales both control point vectors, hence the symmetry. There must be a paragraph about this in the manual but I couldn't find it. In the hobby case, it's not valid anymore since i-3,i-2,i+2, and i+3 also matters. If you look at the original hobby question, I have a failed answer that's waiting to be fixed using only PGF math but still on hold. On paper, it's possible since we actually compute those control points – percusse Sep 10 '12 at 10:16
@percusse Thank you! This solution is almost perfect, but unfortunately (as you already said) the end points of the path cannot be used. So I tried to use Jake's answer for the end points, but setting tangent = 0.0 in my above code leads to the following error: Dimension too large. Do you know what could be the reason for this? If I use tangent=0.4 for example, it works as intended. – ph4nt0m Sep 10 '12 at 10:34
@ph4nt0m At the end points one of the control points become itself and I think I can add special cases where mark index=1 and mark index=n. I'll try to have a look whenever I have the chance. But it smells like you have two point very close together or a computation leads to a division by a very small number but I'm not sure. – percusse Sep 10 '12 at 10:44