0

I've been struggling with this for some months: I need to output an array of points for an arc segment for an ellipse, I'm attempting to draw segments of Kepler orbits, i.e. similar to KSP ship maneuvers. I found this paper which describes drawing ellipses with a fixed number of points and also has more points around the ends of the ellipse than the sides which is almost perfect for my needs: https://doi.org/10.1093/comjnl/14.1.81 However I need to:

  • Rotate/tilt around a focal point of the ellipse rather than the center, I have solved that elsewhere.
  • Draw just an arc segment starting from a given angle and either ending at a given angle or of an arc size.

Here is a link to C# code of the original function from the paper: https://gist.github.com/se5a/1135132f0f2d8d84770ca960405b9e41

I was able to solve the rotation/tilt by doing a matrix move and rotate on the resulting output rather than tilting as the original has it, if there's a more efficient way to do this I'd like to know.

The arc problem has gotten me completely stumped however. I think the number of points given as input should still be the whole ellipse, but I'll likely need to have extra points at the arc start and arc end, which is fine. idealy the arc start and end would be the true anomaly (ie focal point origin angle from the periapsis ) though I should be able to figure out from a center point origin solution.

Apologies if this should have gone on stackoverflow, I always seem to get in trouble because I cant figure out which one it's supposed to go in.

se5a
  • 11
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Apr 25 '23 at 22:54
  • How are the points spaced along the arc? Measuring along the circumference of an ellipse is a rather difficult problem involving elliptical integrals, so if you wanted equal spacing you are going to need a lot of math. – John Alexiou Apr 26 '23 at 02:38
  • See my comment in the gist. There is a bug in the code, lines 33 and 34. It is a common mistake I have seen when rotating vectors. – John Alexiou Apr 26 '23 at 11:41
  • 1
    If it is a question relating to math and equations use [Math.SE] and if it a question about coding specifically use [SO]. For example, what is the equation for an ellipse given certain parameters => Math, How do I draw an ellipse in WinForms => SO. – John Alexiou Apr 26 '23 at 15:54
  • 1
    On a side note, when the paper dated 1969 mentions computational efficiency by reducing the number of math operations, this does not apply anymore. Floating point math is nowadays many times faster than memory access. The key to modern fast computing is locality of data, not simplified math. – John Alexiou Apr 27 '23 at 01:16
  • GEOMETRY.F90 I found this Fortran code that splits a tilted ellipse into points. You have to Ctrl-F the source file for ELLIPSE_POINTS_2D to find it. – John Alexiou May 17 '23 at 13:54
  • Read also this answer here which describes how to place points on an ellipse that are equidistant. To convert to an arc reduce the coverage of the parameter from $2\pi$ to something less. – John Alexiou May 18 '23 at 11:59
  • Thanks John, I've kind of gotten disgusted with SE & SO which can't handle questions that are smack between math and code, or math questions asked in code or visa versa. Recently been messing with doing the whole thing as a circle and using matrix scale transform, which gets the points to the right spacing. not quite what I was going for with the OP but gives the same effect. – se5a May 20 '23 at 06:54

1 Answers1

1

The polar coordinates of an ellipse drawn from one of the focci is

$$ r(\theta) = \frac{a\, (1-\epsilon^2)}{1+\epsilon\,\cos \theta} $$

where $a$ is the semi-major axis, $b$ the semi-minor axus and $\epsilon = \sqrt{1-(b/a)^2}$ is the eccentricity.

To rotate the ellipse, add a phase to the angle $\theta$.

To draw a segment, limit $\theta$ to something less than $\theta = 0 \ldots 2\pi$.

To draw points, just enter the angle values you want points for.


I have made an example C# WinForms Gist that uses the built-in System.Numerics.Vector2 objects to define the geometry of objects. File Geometry.cs contains the routines that defined the points on the ellipse. File Gdi.cs contains the extension methods to draw various things on a System.Drawing.Graphics object, but using Vector2 for model-based coordinates instead of PointF pixel-based coordinates. Objects are drawn from the center of the form, and with some specified scale to convert between model coordinates and pixels.

The visual result is:

scr1

The code that draws the ellipse, the arrow and the points calls a function GetPointsOnEllipseArc() to produce the points on the ellipse.

Care must be taken because all drawing routines in Gdi.cs accept angles in degrees, and the geometry routines in Geometry.cs accept angles in radians.

Here is the drawing code inside the form

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.TranslateTransform(ClientSize.Width / 2, ClientSize.Height / 2);
float scale = 20;

Gdi.Stroke.Color = Color.Black;
Gdi.Stroke.DashStyle = DashStyle.Dash;
Vector2 center = Vector2.Zero;
float semiMajor = 5f, semiMinor = 3f;
float tiltAngle = 15;
e.Graphics.DrawEllipse(scale, center, semiMajor, semiMinor, tiltAngle);
Gdi.Stroke.DashStyle = DashStyle.Solid;

Gdi.Stroke.AddEndArrow(4f);
Gdi.Stroke.Color = Color.Red;
float factor = 4 / 3f;
e.Graphics.DrawEllipseArc(scale, center, factor*semiMajor, factor*semiMinor, 0, 20, tiltAngle);
Gdi.Stroke.RemoveEndArrow();

float focusDistance = (float)Math.Sqrt(semiMajor * semiMajor - semiMinor * semiMinor);
Vector2 focus = center + new Vector2(focusDistance * (float)Math.Cos(tiltAngle*Geometry.deg), focusDistance * (float)Math.Sin(tiltAngle*Geometry.deg));
Gdi.Fill.Color = Color.Black;
e.Graphics.FillPoint(scale, focus);
Gdi.Stroke.Color = Color.Purple;
var points = Geometry.GetPointsOnEllipseArc(focus, semiMajor, semiMinor, 24, 0, 180 * Geometry.deg, tiltAngle * Geometry.deg);
foreach (var point in points)
{
    e.Graphics.DrawPoint(scale, point);
}

}

Notice the manual calculation of the focus point, and the calling of Geometry.GetPointsOnEllipseArc() to return the list of points on the ellipse. This uses the polar equation shown above.

/// <summary>
/// Gets points on an ellipse arc (partial ellipse).
/// </summary>
/// <remarks>
/// The points are drawn from the focus of the ellipse and are spaced
/// by equal angles in polar coordinates.
/// </remarks>
/// <param name="focus">The focus point of the ellipse.</param>
/// <param name="semiMajor">The semi-major axis.</param>
/// <param name="semiMinor">The semi-minor axis.</param>
/// <param name="numPoints">The number points.</param>
/// <param name="azimuthOffset">The azimuth offset angle in radians, CCW.</param>
/// <param name="azimuthSweep">The azimuth sweep angle in radians, CCW.</param>
/// <param name="tiltAngle">The tilt angle in radians, CCW from horizontal.</param>
/// <returns>An array of <see cref="Vector2"/> points.</returns>
static public Vector2[] GetPointsOnEllipseArc(Vector2 focus, float semiMajor, float semiMinor, int numPoints, float azimuthOffset, float azimuthSweep, float tiltAngle = 0)
{
    float e = (float)Math.Sqrt(1 - (semiMinor / semiMajor) * (semiMinor / semiMajor));
float Δθ = azimuthSweep / (numPoints - 1);
float ct = (float)Math.Cos(tiltAngle), st = (float)Math.Sin(tiltAngle);

Vector2[] points = new Vector2[numPoints];
for (int i = 0; i &lt; numPoints; i++)
{
    // get azimuth angle along the ellipse
    float θ = azimuthOffset + i * Δθ;
    // get polar coordinate of ellipse r(θ)
    float r = semiMajor * (1 - e * e) /(float)(1 + e * Math.Cos(θ));
    // get axis aligned (x,y) point from foci
    float x = r * (float)Math.Cos(θ), y = r * (float)Math.Sin(θ);
    // get rotated (x,y) point
    Vector2 localPoint = new Vector2(ct * x - st * y, st * x + ct * y);
    points[i] = focus + localPoint;
}

return points;

}

John Alexiou
  • 14,616
  • PLEASE read the linked paper and the given code (which is a direct C# conversion of the math formula given in the paper) The paper is fairly easy to peruse and answers how the points are spaced, and defines why its the good option for drawing this way. – se5a Apr 26 '23 at 08:27
  • 1
    The paper is behind a paywall. You should pull out the relevant equations and include them in your question to make it self-contained. – John Alexiou Apr 26 '23 at 11:35
  • The code uses constant interval of the parameter $t$ in the parametric equation for the ellipse $$(x,y) = (a \cos t,,b \sin t)$$ This will not result in equidistant and this draws a centered ellipse. The parametric form is not the same as the polar form $(x,y) = (r(\theta) \cos \theta, r(\theta) \sin \theta))$. I propose using the polar form from the foci as it is the simplest form and what you are requesting in the question. – John Alexiou Apr 26 '23 at 11:47
  • I'm out of time this morning but: – se5a Apr 26 '23 at 21:44
  • Stupid hitting enter and then take longer than 5 min to edit, have to start again: I'm out of time this morning but: Paper is not behind a paywall, you should be able to click the pdf icon and it'll open, I've tested this on two different devices. I believe the error you mentioned in the code is not an error but intentional, it appears to match the paper and gives the correct results: Imgur you can see it's adding xn,yn to teh points[] array first. your image doesn't look quite right as the points are bunched up at one apex but not the other. see my image. – se5a Apr 26 '23 at 21:53
  • I'll throw up the version I have with my (working)attempt at rotation around the foci, I didn't do it originally as it uses home rolled vector2 (using doubles) and hand rolled matrix as well and originally wanted to keep tangents to a minimum. as a side note I'm using SDLDrawPoint to render in in my versions. – se5a Apr 26 '23 at 22:02
  • @se5a - this is why I included System.Numerics vectors so I don't roll my own. I know they use float but when it comes to the screen it does not matter, and in some ways float works better with graphics. I have my own Vector2 structures that I chose not to use. – John Alexiou Apr 27 '23 at 01:07
  • My points are spaced at equal angles as seen from the focus point (black dot). So at large radius, the arc lengths are much larger than at small radial distances. – John Alexiou Apr 27 '23 at 01:12
  • I read the pdf. I see that the "optimized" algo looks erroneous to the casual reader. At this point, I would recommend using the original algo as stated in the paper for clarity. I can help transform this algo to a focus-centered one, or you can just find where the center of the ellipse is from the focus and the tilt angle. This is what I am doing in the OnPaint method where I calculate Vector2 focus from the center and angle. – John Alexiou Apr 27 '23 at 01:22
  • ok posted the matrix version and also the un-optomised paper version to the gist.
    using doubles because I'm dealing with solar system distances in meters, I'm getting all the points in full sized distances, then converting them all to whatever zoom, pan etc the viewscreen requires them in and changing to int there (SDL uses ints rather than floats). I'm more worried about figuring out how to modify the code to do an arc than the rotation around the foci, as I think the matrix version should be performant enough. (though I'll take optimizations I can get)
    – se5a Apr 27 '23 at 10:56
  • @se5a - You are using a parametrized version of the ellipse and so you restrict the parameter values to get an arc. But in the code posted, I don't see how it is easy to do this since each sin and cos are not evaluated inside the loop, but rather the direction vector (cndp,sndp) adjusted for each iteration. – John Alexiou Apr 27 '23 at 11:52
  • Hence the question. doing it the polar way is fairly easy and I could have figured that out, I seem to like trying to do things the hard way. it must be possible though, it has tilt/rotate... as a slight aside, what does "Parametric/Parametrized" mean exactly in this context? – se5a Apr 27 '23 at 13:56
  • Now you understand what I'm trying to do, how would you re-word the original question to better explain the problem? As a backup solution, it has occurred to me that I might be able to use the polar as you've done, and switch foci half way to give me a similar effect to the parametrized version. – se5a Apr 27 '23 at 15:26
  • @se5a - A parametric curve is one where the x and y components are evaluated for each value of a parameter $t=0\ldots1$. For a centered ellipse this is $$ \pmatrix{x \ y} = \pmatrix{ a \cos 2\pi t \ b \sin 2\pi t}$$ – John Alexiou Apr 27 '23 at 21:48
  • But this is not polar notation because what multiplies the $\cos$ and $\sin$ are different values. The polar equation of a centered ellipse is $$ \pmatrix{x \ y} = \pmatrix{ r \cos \theta \ r \sin \theta}$$ where $r = r(\theta)$ is some complicated function. But if you offset the x coordinate by the focus $c=\sqrt{a^2-b^2}$ the parametric form gets complicated, and the polar form is by far simpler (see my answer). – John Alexiou Apr 27 '23 at 21:48