Matt Gemmell

CHANGER is available now!

An action-thriller novel — book 1 in the KESTREL series.

★★★★★ — Amazon

Pie Menus Label Positioning

source 2 min read

Anyone have any thoughts on an algorithm for this?
For now, let's assume that I want to draw the labels horizontally 
within each slice (i.e. not rotated). Let's further assume that I 
wish to scale the labels down so that they fit within their slice 
without clipping or wrapping.

Let's ignore for the moment the fact that different-sized labels 
in the same pie would look strange, and let's further ignore that 
some long labels would become too small to read if shrunk to fit. 
Those are details to deal with later. Let's also ignore the various 
other options for displaying labels (radially within a slice, 
exploded to avoid overlap, truncated if necessary and expanded on 
mouse-over, and so forth). So, we're dealing purely with the case 
of scaling horizontal labels to fit.

Thus, the general situation is that we wish to draw the label for 
an arbitrary slice, as illustrated below:
The information we'll have available at drawing time is:
  • C - the centre point of the pie (     dot)
  • θ (theta) - the internal angle of the slice (     angle)
  • α (alpha) - the starting angle of the slice (     angle)
  • β (beta) - the ending angle of the slice (     angle)
  • r - the radius of the pie (     line)
  • k - the radius of the inner circle (     line)
  • m - the distance from the centre of the pie at which we wish the label to be vertically centred (     line)
  • L - the label point; the point at which we want the label to be vertically centred (     dot)
<em>&theta;</em> is the difference of <em>&alpha;</em> and <em>&beta;</em>. <em>L</em> is at distance <em>m</em> from <em>C</em>, at 
an angle halfway between <em>&alpha;</em> and <em>&beta;</em>, i.e. at angle <em>&alpha;</em> + (<em>&theta;</em> / 2.0).

What we require is the <span style="background-color:#FFFF00">yellow</span> 
rectangle; i.e. the largest rectangle which will fit entirely within the 
slice, not overlapping the inner circle, and vertically centred on the label 
point (but not necessarily horizontally centred there).

All angles are in degrees, and are assumed to be in the interval 
[0, 360), i.e. from 0&deg; inclusive to 360&deg; exclusive. All distances are floats, and all points are structs 
with fields <code>x</code> and <code>y</code>, both floats. The centre point of the circle 
is never the Origin, i.e. C &ne; {0, 0}, and in fact all coordinate 
values will be positive. A rectangle is a struct with an <code>origin</code> 
field (which is a point), and a <code>size</code> field, which is a struct with 
float fields <code>width</code> and <code>height</code>. The implementation 
language is Objective-C, thus pure C is also fine. Standard C math library 
functions are available, as are Cocoa AppKit and Foundation frameworks.

From the rectangle, it'll be trivial to determine the correct 
point-size of the current font which is needed in order for the 
slice's label to be rendered entirely within that rectangle. It's 
just how to determine the rectangle programmatically that I'm puzzled 
about at the moment.

Any thoughts?