Drawing Poincaré Geodesics in the Unit Disk

Author: Clinton P. Curry <clintonc@clintoncurry.net>
Date: April 24, 2009
Revised:November 10, 2010

I find myself reinventing the wheel pretty often when it comes to this, so I thought I would set it down here for the teeming masses of the future.

Sometimes I want a picture comprised of chords in the unit disk. One can draw them as straight line segments, but this has the disadvantage that short chords are almost indistinguishable from arcs of the circle. Hence, it makes more sense to draw Poincaré geodesics joining two points. As an example, below are two images depicting the same set of chords, once with Euclidean geodesics (straight lines) and once with Poincaré geodesics (arcs of circles). Notice how much more detailed (and, dare I say, pretty) the second picture appears.

images/rabbit_euclidean.png images/rabbit_poincare.png

The Poincaré geodesic joining two points $a$ and $b$ on the boundary of the unit circle is the unique circular arc that strikes the unit circle perpendicularly at $a$ and $b$. It is not difficult to calculate what this circular arc is: the circle $C$ of which it is a part has a particular center and radius, and it subtends a particular set of angles from the center of $C$. I will not bother showing the calculations, but I will explain why this is not a good solution to the problem.

As the size of the geodesic gets smaller and smaller (i.e., as the points it connects get closer and closer), the radius of the circle tends to zero, and the calculations are easy for a computer to do. However, as the two points being connected get further apart, the geodesic tends to a straight line, meaning that the circle's radius gets large and the angles of intersection with the unit circle get very close together. This means that, when you ask your computer to draw the section of the circle, you are unlikely to get good results. On the bright side, trying to draw the circle with infinite radius is a handy way to get strange errors from your postscript files.

The reasonable among you may ask, "Why don't you stop drawing arcs of circles when the angle gets too big? Eventually, they look like straight lines, so draw those. Doofus." I'm not satisfied by that solution. Let's do Bézier curves instead!

A Bézier curve is a parametric curve which, in each coordinate, is a polynomial (usually cubic). They have a knack for approximating smooth curves. In fact, it is quite common to approximate a circle by a spline consisting of four cubic curves; this is accurate to better than a tenth of a percent. My hope is that Bézier curves are better conditioned for drawing Poincaré geodesics than arcs of the circle are.

The happy truth is that they are. Suppose you wish to draw a Poincaré geodesic between points $a$ and $b$ on the unit circle. According to the formulas on this page, there is a self-homeomorphism of the unit disk in the complex plane given by \[ \phi(z) = \frac{z}{1+\sqrt{1-|z|^2}} \] which sends straight chords to the Poincaré geodesics joining the same endpoints. All you must do is find a Bézier curve $P(t)$ (with non-vanishing derivative) such that

These conditions give you that the endpoints of the spline are $a$ and $b$, and the control points are $\kappa a$ and $\kappa b$, where $\kappa$ is a function only of $M = \left|\frac{a+b}{2}\right|$. Specifically, \[ \kappa = \frac43 \left( \frac{1}{1 + \sqrt{1 - M^2}}-\frac14\right)\] which, miracle of miracles, gracefully approaches $\frac13$ as $a$ and $b$ tend to antipodal points.

This is now my go-to method in any setting where Bézier curves are supplied for drawing Poincaré geodesics. I have not had the occasion to extend this method to the approximation of the geodesic joining points $a$ and $b$ which are not on the unit circle, but it seems this would be straightforward.

As an example, here is a short Asymptote program which draws the chords specified in a text file.

/* chords-from-file.asy
 * Author: Clinton Curry
 * Date: April 24, 2009
 * Draw the chords whose angles (in full revolutions) are given
 * in the input file.

// Read in a filename and open
file fin=input(stdin);

// Draw chords in file
real a,b;
while( !eof(fin) ) {
  a = fin;
  b = fin;
  pair z1 = (cos(2*pi*a), sin(2*pi*a));
  pair z2 = (cos(2*pi*b), sin(2*pi*b));
  real M = length(1/2 * (z1+z2));
  real kappa = 4/3* ( 1/(1+sqrt(1-M*M)) - 1/4);
  draw(z1..controls kappa*z1 and kappa*z2..z2);