How TikZ works - How angles are converted to Bezier curves

tikz
Author

Emmanuel Jeandel

Published

March 23, 2023

This is the first of possibly (?) a series of articles on how tikz and PGF work.

The reason I had to read precisely the code of PGF is because I wanted to export some features of PGF in my own software, pygf.

It is important to note that all dimensions in TeX, internally, use scaled points, which are 1/65536th of a point, where a point is 1/72.27 inches, and an inch is 2.54cm. Every number in TeX is a multiple of a scaled point, which means TeX internally uses fixed point arithmetic

Some of the code I will expose here will seem convoluted, but that’s because it is trying to circumvent some limitations of the fixed point arithmetic inside TeX in order to do some computations

Edges and angles in TikZ

I will explain here what happens when you write

\draw (0,0) edge[in=90,out=60] (5,0);

This draws a curvy edge between the points \((0,0)\) and \((5,0)\), in such a way that the curve leaves the first point with angle 60 degrees, and goes into the second point with angle 90 degrees.

Internally, this is converted into a Bezier curve, that starts at the first point, and ends at the second point. The only thing that needs to be specified are the control points.

Here is how they are computed:

  • The distance between the two points is computed.
  • This distance is multiplied by 255/256 then by 0.3915 to obitan a number \(d\)
  • The two control points for the Bezier curve are then defined in the following way:
    • The first control point is at distance d and angle out from the first point.
    • The second control point is at distance d and angle in from the second point

The first multiplication of the distance by 255/256 is due to the way the distance is computed. Assuming \(x > y\) and both are positive:

  • The ratio \(x/\sqrt{x^2+y^2}\) is first computed, then multiplied by 65536 and divided by \(255\) to obtain the number \(a\)
  • \(x\) is multiplied by 16, then divided by \(a\), then multiplied again by \(16\).

The complete operation is therefore

\[ 16\times \left(\frac{16 \times x}{\frac{65536 \frac{x}{\sqrt{x^2+y^2}}}{255}}\right) = \frac{255\times 16 \times 16 \sqrt{x^2 + y^2}}{65536} \]

Again, this is done by steps, in fixed point arithmetics, so the final result might be slightly different.

Explanation

So, essentially, what we get is that the first control point is at an angle out from the first point, and at a distance d where d is \(0.39 = 0.3915 \times 255/256\) times the total distance between the two points.

Where does this 0.39 comes from ?

The explanation can be found when looking at what happens when we try

\draw (0,0) edge[in=-90,out=0] (1,1);

This curve leaves the point (0,0) horizontally, and reaches the point (1,1) vertically. It turns out that the factor 0.39 is tuned so this curve looks like a quarter circle.

How to draw a circle using Bezier curve is a well known problem, see for instance this page.

One good technique (written in the section “a better approximation” in the previous page) is to take the first control point at coordinates \((c,0)\) where \(c = 0.551915\) for a circle of radius 1.

In our case, the coordinates of our control point is given proportionally to the distance between the two points which is \(\sqrt{2}\), which means we put our first control point at coordinate \((\sqrt{2} p,0)\) where \(p\) is the factor of proportionality.

Therefore we should take \(p = 0.551915/\sqrt{2} = 0.39\).

Looking at additional digits shows that \(0.3918\) is probably a better choice than \(0.3915\). I don’t know if the difference comes from intrinsics of the functioning of TeX and LaTeX, or if it is irrelevant.

Source

The code that converts angles into control points is in the file generic/pgf/frontendlayer/tikz/libraries/tikzlibrarytopaths.code.tex of tikz, more precisely in the function \tikz@to@compute@distance@main.