# Draw a spline with tangents with Metapost

I wish to reproduce the same figure. Only, the curve is not exactly the one expected and I want to make a loop to trace the tangents.

     \documentclass[border=5mm]{standalone}
\usepackage{luatex85}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
beginfig(1);
pickup pencircle scaled 1bp;

% parameters
u = 1cm;
ymin = 0;
ymax = 12;
xmin = 0;
xmax = 8;

% make a plain grid
path xx, yy;
xx = ((xmin,0) -- (xmax,0)) scaled u;
yy = ((0,ymin) -- (0,ymax)) scaled u;

drawoptions( withcolor .8 white);
for i = ceiling ymin upto floor ymax: draw xx shifted (0,i*u); endfor
for i = ceiling xmin upto floor xmax: draw yy shifted (i*u,0); endfor
drawoptions( withcolor black);

% make a curve
z0=(u,u);
z1=(3u,3u);
z2=(5u,5u);
z3=(7u,11u);
path p;
p = z0 {dir 14} .. z1{dir 63} .. z2{dir 0} .. z3{dir 79};
draw p;

% Specify a time along the path
numeric ta[]; ta0 := 2;

% Pick the point at that time
pair a;     a := point ta0 of p;

% Draw a tangent at a particular point
path tangent; tangent := (-2cm,0) -- (2cm,0);
tangent := tangent rotated (angle direction ta0 of p) shifted a;
draw tangent dashed evenly  withcolor blue;
fill fullcircle scaled 3bp shifted a;

endfig;
\end{mplibcode}
\end{document}

• You might want to get a look at the "spline" and "repere" package of MetaPost. – Franck Pastor Oct 19 at 12:35
• You want to make the third segment of the path more "tense" -- so change .. to ... before z3 in your path. – Thruston Oct 19 at 21:37
• And you don't need to calculate the angles to set the directions you can use a pairs in curly braces, like so path p; p = ((1,1) {4,1} .. (3,3) {1,2} .. (5,5) {1,0} ... (7, 11) {1, 5}) scaled u; – Thruston Oct 19 at 21:40
• Thank you. Here is to draw the tangents using a loop : for i=0 upto 3: numeric ta[]; ta[i] = i; path tangent; tangent := (-5cm,0) -- (5cm,0); tangent := tangent rotated (angle direction ta[i] of p) shifted point ta[i] of p; draw tangent withcolor magenta; fill fullcircle scaled 3bp shifted point ta[i] of p ; endfor;To mark the points with a cross, I have to write a macro. – Fabrice Oct 20 at 8:51

Here's a version with some notes as comments. Compile with lualatex.

\documentclass[border=5mm]{standalone}
\usepackage{luatex85}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
beginfig(1);

numeric u; u = 20;

% grid
drawoptions(withpen pencircle scaled 1/4 withcolor 3/4 white);
z1 = (8, 12);
for x = 0 upto x1: draw ((x,0) -- (x, y1)) scaled u; endfor
for y = 0 upto y1: draw ((0,y) -- (x1, y)) scaled u; endfor
drawoptions();

% path ff is the one you want with "... = .. tension atleast 1 .."
% path gg is just for comparison with the default tension

path ff; ff = ((1,1) {4,1} ... (3,3) {1,2} ... (5,5) {1,0} ... (7,11) {1,5}) scaled u;
path gg; gg = ((1,1) {4,1} .. (3,3) {1,2} .. (5,5) {1,0} .. (7,11) {1,5}) scaled u;

% draw a tangent at each point along the path ff
% draw these first so that they appear underneath the curve

for t=0 upto length(ff):
draw
(left--right) scaled 2u
rotated angle direction t of ff
shifted point t of ff
dashed withdots scaled 1/4
withpen pencircle scaled 3/4
withcolor 1/2[blue, white];
endfor

% now draw the curve(s)

draw ff withcolor 3/4 red;
draw gg dashed evenly withcolor 3/4 green;  % this is just for comparison

% now label the points with letters and crosses.

% First let's make a cross picture
picture X; X = image(
drawoptions(withpen pencircle scaled 1 withcolor 1/4[blue, white]);
draw (left--right) scaled 2;
draw (down--up) scaled 2;
drawoptions();
);

% And finally use a list of strings to control the loop
% and the magical "incr" operator to increment the index
% Note that we have mblibtextextlabel turned on, so each
% string is automatically wrapped in "TEX()" by the label macro
numeric t;
t = -1;
for a = "$B$", "$E$", "$F$", "$L$":
label.ulft(a, point incr t of ff);
draw X shifted point t of ff;
endfor

endfig;
\end{mplibcode}
\end{document}


Note that the green path (with the default tension) is the same as the red path from B..E..F. Here MP has found a nice smooth curve anyway. But from F..L the default tension means that the curve balloons out to the right to avoid a sharp turn. But increasing the tension brings the curve back to the desired line. Essentially using ... instead of .. means the curve will stay within the triangle formed by the two tangents and the segment joining the two points.

• Great ! Thank you for your help and your teaching. – Fabrice Oct 22 at 8:30