Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to divide an ellipse to equal segments?

This calculates vertex coordinates on ellipse:

function calculateEllipse(a, b, angle) 
{
    var alpha = angle * (Math.PI / 180) ;
    var sinalpha = Math.sin(alpha);
    var cosalpha = Math.cos(alpha);

    var X = a * cosalpha - b * sinalpha;
    var Y = a * cosalpha + b * sinalpha;
}

But how can I calculate the "angle" to get equal or roughly equal circumference segments?

like image 904
Riko Avatar asked Oct 21 '22 20:10

Riko


1 Answers

So from what Jozi's said in the OP's comments, what's needed isn't how to subdivide an ellipse into equal segments (which would require a whole bunch of horrible integrals), it's to construct an ellipse from line segments of roughly equal length.

There are a whole pile of ways to do that, but I think the best suited for the OP's purposes would be the concentric circle method, listed on the page as 'the draftman's method'. If you don't mind installing the Mathematica player, there's a neat lil' app here which illustrates it interactively.

The problem with those methods is that the segment lengths are only roughly equal at low eccentricities. If you're dealing in extreme eccentricities, things get a lot more complicated. The simplest solution I can think of is to linearly approximate the length of a line segment within each quadrant, and then solve for the positions of the endpoints in that quadrant exactly.

In detail: this is an ellipse quadrant with parameters a = 5, b = 1: enter image description here

And this is a plot of the length of the arc subtended by an infinitesimal change in the angle, at each angle:

enter image description here

The x axis is the angle, in radians, and the y axis is the length of the arc that would be subtended by a change in angle of 1 radian. The formula, which can be derived using the equations in the Wikipedia article I just linked, is y = Sqrt(a^2 Sin^2(x) + b^2 Cos^2(x)). The important thing to note though is that the integral of this function - the area under this curve - is the length of the arc in the whole quadrant.

Now, we can approximate it by a straight line:

enter image description here

which has gradient m = (a-b) / (Pi/2) and y intercept c = b. Using simple geometry, we can deduce that the area under the red curve is A = (a+b)*Pi/4.

Using this knowledge, and the knowledge that the area under the curve is the total length of the curve, the problem of constructing an approximation to the ellipse reduces to finding say a midpoint-rule quadrature (other quadratures would work too, but this is the simplest) of the red line such that each rectangle has equal area.

Converting that sentence to an equation, and representing the position of a rectangle in a quadrature by it's left hand boundary x and its width w, we get that:

(v*m)*w^2 + (m*x+c)*w - A/k == 0

where k is the number of pieces we want to use to approximate the quadrant, and v is a weighting function I'll come to shortly. This can be used to construct the quadrature by first setting x0 = 0 and solving for w0, which is then used to set x1 = w0 and solve for w1. Then set x2 = w1, etc etc until you've got all k left-hand boundary points. The k+1th boundary point is obviously Pi/2.

The weighting function v effectively represents where the rectangle crosses the red line. A constant v = 0.5 is equivalent to it crossing in the middle, and gets you this with 10 points:

enter image description here

but you can play around with it to see what better balances the points. Ideally it should stay in the range [0, 1] and the sum of the values you use should be k/2.

If you want an even better approximation without messing around with weighting functions, you could try least-squares fitting a line rather than just fitting it to the endpoints, or you could try fitting a cubic polynomial to the blue curve instead of a linear polynomial. It'll entail solving quartics but if you've a maths package on hand that shouldn't be a problem.

like image 86
Andy Jones Avatar answered Oct 24 '22 03:10

Andy Jones