How to Divide a Circle into \(N\) Equal Slices from a Non-Central Point.
You can hover/tap the pizza above for an interactive demonstration.
Let's say you want to slice a pizza into equal slices, but not from the central point. This question came into my mind and I decided to find a formula for it. In the following article I'll demonstrate how to form up a trigonometric function and inverse it to achieve equal slices from an arbitrary point on the circle/pizza. Then I show how I created the above interactive web version with Javascript.
Let's say we want to make our first slice from \(C'\), with \( \alpha\) defined as angle of this slice:
As you can see from the picture, you can divide this slice into two parts:
Now that we were able to decompose the first slice into two parts, let's compute their areas one-by-one:
Based on the Law of Sines, we know that the following equation holds:
$$ \frac{\sin{\alpha}}{r}=\frac{\sin{\beta}}{d}$$
as \( \alpha\), \( d\), and \( r\) are known, we can calculate \( \beta\) as follows:
$$ \beta=\arcsin{\left(\frac{d \sin{\left(\alpha \right)}}{r} \right)}$$
As two angles of this triangle are \( \alpha\) and \( \beta\), the third one would be \( \pi-\alpha-\beta\). Now that we know a SAS of the triangle, the area can be calculated:
$$a_1=\frac{1}{2}\cdot d\cdot r\cdot\sin\left(\alpha+\beta\right)$$
As the blue region is a circular sector and we already know \( \alpha\) and \( \beta\), the area simply is:
$$ \begin{aligned} a_2 &=\pi r^2\cdot\frac{\alpha+\beta}{2\pi}\\ &=\frac{r^2}{2}\cdot(\alpha+\beta) \end{aligned} $$
For simplicity, we define \(v\) as the relative distance between \( C\) and \( C'\):
$$ v:=d/r$$
Now that we know \( a_1\) and \( a_2\), let's define \(f\) as the relative area of the slice:
$$ \begin{aligned} f(\alpha) &:= \frac{\text{area of first slice}}{\text{total area of circle}} \\ &= \frac{a_1 + a_2}{\pi r^2} \\ &= \frac{\frac{1}{2}\cdot d \cdot r \cdot \sin(\alpha + \beta) + \frac{r^2}{2}\cdot(\alpha+\beta)}{\pi r^2} \\ &= \frac{\frac{d}{r}\sin\left({\alpha+\beta}\right)+\alpha+\beta}{2\pi} \end{aligned} $$
Substituting \( v=d/r\) and \( \beta=\arcsin{\left(\frac{d \sin{\left(\alpha \right)}}{r} \right)}\), we'll have:
$$ f(\alpha)=\frac{v \sin{\left(\alpha + \arcsin{\left(v \sin{\left(\alpha \right)} \right)} \right)} + \alpha + \arcsin{\left(v \sin{\left(\alpha \right)} \right)}}{2 \pi} $$
Now that we have \( f(\alpha)\) defined, we can determine the area of our first slice as a function of \( \alpha\). Now if we use \( f^{-1}\), we can for example compute \( f^{-1}(1/8)\) to make the first slice of 8 equal slices we wanted to achieve. As \( f^{-1}\) doesn't have a closed-form, I'm using Newton's Method for calculating it.
Using Newton's method for calculating \( f^{-1}(x)\), we need to know \( f'(x)\). I used SymPy for calculating the derivative of this function. Here's the Python code:
import sympy as sp
# define the symbols
d, r, v, alpha = sp.symbols('d r v ⍺')
beta = sp.asin(sp.sin(alpha)*d/r)
a1_rel = (d * r / 2 * sp.sin(alpha + beta)) / (sp.pi * r**2)
a2_rel = r**2 / 2 * (alpha + beta) / (sp.pi * r**2)
at_rel = a1_rel + a2_rel
at_rel = at_rel.subs(d/r, v)
# calculate the derivative
at_rel_diff = sp.diff(at_rel, alpha)
sp.print_latex(at_rel_diff)
And the formula:
$$ \begin{align*} f'(\alpha)&=\frac{v \left(\frac{v \cos{\left(\alpha \right)}}{\sqrt{- v^{2} \sin^{2}{\left(\alpha \right)} + 1}} + 1\right) \cos{\left(\alpha + \arcsin{\left(v \sin{\left(\alpha \right)} \right)} \right)}}{2 \pi} \\ &+ \frac{\frac{v \cos{\left(\alpha \right)}}{\sqrt{- v^{2} \sin^{2}{\left(\alpha \right)} + 1}} + 1}{2 \pi} \end{align*} $$
In this section, we came up with the closed form of the relative area as a function of alpha, and we also obtained the derivative of this function. So in theory it's possible to select angles \(\alpha_1, \alpha_2, \cdots, \alpha_n\) such that we obtain equal slices. So the problem is solved :tada: -- but only in theory.
Also, the detailed calculations are available in this jupyter notebook which is using SymPy.
In the next section, I'm describing how it's actually done in practice in my web application.
Now that we can calculate slices' angles via the area function and Newton's method, It's time to make a real-time demo using HTML5 and JS. Once you know the parameters of the problem (number of slices, v, and rotation angle), it's about doing the math in code and drawing it on screen. In this part I only cover the math-related part of the code, but the whole thing is 150 lines of HTML, CSS and JS. I suggest you to have a look at the single file of the application if you're interested.
Based on SymPy's result, the Area function and its derivative can be defined as follows. Unlike formulas, JS functions are not very complicated.
function relAreaFraction(alpha, v) {
const term1 = alpha + Math.asin(v * Math.sin(alpha));
const numerator = v * Math.sin(term1) + term1;
return numerator / (2 * Math.PI);
}
function relAreaFractionDiff(alpha, v) {
const term1 = v * Math.sin(alpha);
const term2 = Math.sqrt(1 - term1 * term1);
const numerator =
(term2 + v * Math.cos(alpha)) *
(1 + v * Math.cos(alpha + Math.asin(term1)));
return numerator / (2 * Math.PI * term2);
}
Then these functions are being used in solve
function, which is Newton's Method:
function solve(funcVal, v) {
let alpha = funcVal * 2 * Math.PI;
const maxStep = alpha / 2;
let numIterations = 0;
while (numIterations < 100) {
const funcValCur = relAreaFraction(alpha, v);
if (Math.abs(funcVal - funcValCur) < 1e-4) {
break;
}
numIterations++;
let step = -(funcValCur - funcVal) / relAreaFractionDiff(alpha, v)
step = Math.max(step, -maxStep);
step = Math.min(step, maxStep);
alpha += step;
}
return alpha;
}
Let's say \(v=0.4\) and we want to slice the circle into \(n=8\) equal slices. This is how it's done:
So we call Newton's method only \(\left\lfloor\frac{n-1}{2}\right\rfloor\) times.
In this post, I described the math behind the problem and derived the formulas, and used SymPy for keeping track of calculations and formulas in a structured way. Then I created the Python version and Javascript version of it, and the latter is interactive. Newton's method is used in Python and Javascript for mathematical approximation.