473,396 Members | 1,966 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

DrawArc and ellipse geometry (repost)

Hello!

Using the definition for en ellipse (http://en.wikipedia.org/wiki/Ellipse) I
can draw an arc of points. However, the end points of this arc do not
coincide with the end points of an arc drawn with the DrawArc method, e.g.

public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}

private void Form2_Paint(object sender, PaintEventArgs e)
{
Draw(e.ClipRectangle, e.Graphics);
}

private void RectCenter(Rectangle r, out int x, out int y)
{
x = (r.Left + r.Right) / 2;
y = (r.Top + r.Bottom) / 2;
}

private PointF PointFromEllipse(Rectangle bounds, float degrees)
{
float a = bounds.Width / 2.0f;
float b = bounds.Height / 2.0f;
float rad = ((float)Math.PI / 180.0f) * degrees;

int xCenter, yCenter;
RectCenter(bounds, out xCenter, out yCenter);

float x = xCenter + (a * (float)Math.Cos(rad));
float y = yCenter + (b * (float)Math.Sin(rad));

return new PointF(x, y);
}

private void Draw(Rectangle rect, Graphics g)
{

rect.Inflate(-5, -5);
g.DrawArc(new Pen(Color.Green), rect, 0, 315);
PointF p;

for (int i = 0; i < 315; i++)
{
p = PointFromEllipse(rect, i);
g.DrawLine(new Pen(Color.Red), p, new PointF(p.X, p.Y + 2));
}
}
}

Can anybody please give me an explanation for this difference?

--
Thank you,

Christopher Ireland
Jun 20 '07 #1
11 8670
On Wed, 20 Jun 2007 12:58:10 -0700, Christopher Ireland
<ci******@gmail.comwrote:
Using the definition for en ellipse
(http://en.wikipedia.org/wiki/Ellipse) I
can draw an arc of points. However, the end points of this arc do not
coincide with the end points of an arc drawn with the DrawArc method,
I'm not really clear on what your question is. You aren't drawing lines
that would form an arc. You are drawing vertical bars 2 pixels high at
various points around the ellipse, and that's exactly the output you get..

Here's a version of your code (minus the constant Form-derived class
implementation stuff) that corrects that along with some other problems
(you were failing to dispose of newly created pens correctly, for
example). It draws practically the same exact pixels as the DrawArc()
method, with only very minor variations that one would naturally expect
from two completely different implementations of drawing an ellipse
(especially when one implementation is actually just drawing straight line
segments between one degree intervals on the ellipse).
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Draw(ClientRectangle, e.Graphics);
}

protected override void OnResize(EventArgs e)
{
base.OnResize(e);
Invalidate();
}

private void RectCenter(Rectangle r, out int x, out int y)
{
x = (r.Left + r.Right) / 2;
y = (r.Top + r.Bottom) / 2;
}

private PointF PointFromEllipse(Rectangle bounds, float degrees)
{
float a = bounds.Width / 2.0f;
float b = bounds.Height / 2.0f;
float rad = ((float)Math.PI / 180.0f) * degrees;

int xCenter, yCenter;
RectCenter(bounds, out xCenter, out yCenter);

float x = xCenter + (a * (float)Math.Cos(rad));
float y = yCenter + (b * (float)Math.Sin(rad));

return new PointF(x, y);
}

private void Draw(Rectangle rect, Graphics g)
{
rect.Inflate(-5, -5);

g.DrawArc(Pens.Green, rect, 0, 315);
PointF p, pPrev = PointFromEllipse(rect, 0);

for (int i = 1; i < 315; i++)
{
p = PointFromEllipse(rect, i);
g.DrawLine(Pens.Red, p, pPrev);
pPrev = p;
}
}
Jun 20 '07 #2
Peter,
It draws practically the same exact pixels
as the DrawArc() method, with only very minor variations that one
would naturally expect from two completely different implementations
of drawing an ellipse (especially when one implementation is actually
just drawing straight line segments between one degree intervals on
the ellipse).
Thank you for your reply, Peter, and I'm sorry for not making myself
clearer. I've retouched your code to make my point:

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Draw(ClientRectangle, e.Graphics);
}

protected override void OnResize(EventArgs e)
{
base.OnResize(e);
Invalidate();
}

private void RectCenter(Rectangle r, out int x, out int y)
{
x = (r.Left + r.Right) / 2;
y = (r.Top + r.Bottom) / 2;
}

private PointF PointFromEllipse(Rectangle bounds, float degrees)
{
float a = bounds.Width / 2.0f;
float b = bounds.Height / 2.0f;
float rad = ((float)Math.PI / 180.0f) * degrees;

int xCenter, yCenter;
RectCenter(bounds, out xCenter, out yCenter);

float x = xCenter + (a * (float)Math.Cos(rad));
float y = yCenter + (b * (float)Math.Sin(rad));

return new PointF(x, y);
}

private void Draw(Rectangle rect, Graphics g)
{
rect.Inflate(-5, -5);

using(Pen pen = new Pen(Color.Green, 3)) { //let's be good :-)
g.DrawArc(pen, rect, 0, 315);
}
PointF p, pPrev = PointFromEllipse(rect, 0);

for (int i = 1; i <= 315; i++)
{
p = PointFromEllipse(rect, i);
g.DrawLine(Pens.Red, p, pPrev);
pPrev = p;
}
}
}

Here you can see that the green line doesn't reach as far around the arc as
the red line, despite the fact that both are, in theory, drawing an arc
through 315º. It is this effect, that the DrawArc method seems to draw
"short", of which I would be interested in hearing an explanation.

--
Thank you,

Christopher Ireland
Jun 21 '07 #3
On Wed, 20 Jun 2007 23:28:11 -0700, Christopher Ireland
<ci******@gmail.comwrote:
[...]
Here you can see that the green line doesn't reach as far around the arc
as
the red line, despite the fact that both are, in theory, drawing an arc
through 315º. It is this effect, that the DrawArc method seems to draw
"short", of which I would be interested in hearing an explanation.
Ahhh...I understand the question now.

The answer is that your ellipse function and what Windows does aren't the
same (obviously). More specifically, the algorithm you've used assumes
your ellipse was once a circle that's been squashed, and you are
designating the degrees in the coordinate space of the original perfectly
round circle. Of course, when you squash the circle in one dimension or
the other to get an ellipse, you wind up squashing your angles too.

Windows, on the other hand, is doing a true polar coordinate clipping of a
circle to obtain the arc. That is, the beginning and ending point of the
arc, specified in polar coordinates, assumes that you're really drawing an
ellipse, but designating the start and end points in an unmodified polar
coordinate space. That is, take the original ellipse, find where it
intersects with lines drawn from the center outward at the given angles,
and draw the arc between those lines.

IMHO, the Windows version is more mathematically correct, but I feel that
the main point is to decide which is more appropriate to your needs and
use it consistently. Obviously though, you can't mix and match without
seeing the discrepancy you're asking about.

For what it's worth, here's yet another version of your code (see below)
that I hopes makes it much clearer what's going on. I added a lot more
stuff, so that you can use the arrow keys to adjust the limits of your
arc, as well as drawing a perfectly round circle so that you can compare
the angles for that circle with the angles for the ellipse. In
particular, note that the version of the ellipse drawn with DrawArc()
aligns perfectly with the circle, while your ellipse calculate lags and
leads the circle depending on where in the arc you are.

Hope that helps.

Pete
Here's the code:

protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Draw(ClientRectangle, e.Graphics);
}

protected override void OnResize(EventArgs e)
{
base.OnResize(e);
Invalidate();
}

private float _degreesTotal = 360.0f;

protected override bool ProcessDialogKey(Keys keyData)
{
bool fHandled = false;

switch (keyData)
{
case Keys.Left:
_degreesTotal -= 1.0f;
fHandled = true;
break;
case Keys.Right:
_degreesTotal += 1.0f;
fHandled = true;
break;
}

if (fHandled)
{
if (_degreesTotal < 0)
{
_degreesTotal += 360.0f;
}
else if (_degreesTotal >= 360.0f)
{
_degreesTotal -= 360.0f;
}
Invalidate();
}

return base.ProcessDialogKey(keyData);
}

private Point RectCenter(Rectangle r)
{
return new Point((r.Left + r.Right) / 2, (r.Top + r.Bottom) /
2);
}

private PointF PointFromEllipse(Rectangle bounds, float degrees)
{
float a = bounds.Width / 2.0f;
float b = bounds.Height / 2.0f;
float rad = ((float)Math.PI / 180.0f) * degrees;

Point ptCenter = RectCenter(bounds);

float x = ptCenter.X + (a * (float)Math.Cos(rad));
float y = ptCenter.Y + (b * (float)Math.Sin(rad));

return new PointF(x, y);
}

private void Draw(Rectangle rect, Graphics g)
{
rect.Inflate(-5, -5);

Rectangle rectSquare;
Point ptCenter = RectCenter(rect);
int dxySquare = Math.Min(rect.Width, rect.Height);

rectSquare = new Rectangle(new Point(ptCenter.X - dxySquare /
2, ptCenter.Y - dxySquare / 2), new Size(dxySquare, dxySquare));

g.DrawLine(Pens.Black, rect.Location, new Point(rect.Left
+ rect.Width, rect.Top + rect.Height));
g.DrawLine(Pens.Black, new Point(rect.Left + rect.Width,
rect.Top), new Point(rect.Left, rect.Top + rect.Height));
g.DrawString("_degreesTotal: " + _degreesTotal.ToString(),
Font, Brushes.Black, 10.0f, 10.0f);

using (Pen penGreen = new Pen(Color.Green, 3.0f))
{
g.DrawArc(penGreen, rect, 0, _degreesTotal);
g.DrawArc(penGreen, rectSquare, 0, _degreesTotal);
}

PointF ptPrevSquare = PointFromEllipse(rectSquare, 0),
ptPrev = PointFromEllipse(rect, 0);

for (int i = 1; i <= _degreesTotal; i++)
{
PointF ptSquare = PointFromEllipse(rectSquare, i),
pt = PointFromEllipse(rect, i);
g.DrawLine(Pens.Red, pt, ptPrev);
g.DrawLine(Pens.Red, ptSquare, ptPrevSquare);
ptPrev = pt;
ptPrevSquare = ptSquare;
}
}
Jun 21 '07 #4
Peter,
In particular, note that the version of the ellipse
drawn with DrawArc() aligns perfectly with the circle, while your
ellipse calculate lags and leads the circle depending on where in the
arc you are.
Thank you again for your time, Peter.

Yes, I noticed that affect as well.

Now then, what I'm after is to get a _correct_ point back from the ellipse
drawn by DrawArc when I pass PointFromEllipse a given angle. Given that the
wikipedia ellipse algorithm turns out to be a squashed circle, do you happen
to know what the actual windows (mathematically correct) algorithm is so I
can make an accurate calculation?

--
Thank you,

Christopher Ireland

"Growth for the sake of growth is the ideology of the cancer cell."
Edward Abbey
Jun 21 '07 #5
On Thu, 21 Jun 2007 12:37:34 -0700, Christopher Ireland
<ci******@gmail.comwrote:
[...]
Now then, what I'm after is to get a _correct_ point back from the
ellipse
drawn by DrawArc when I pass PointFromEllipse a given angle. Given that
the
wikipedia ellipse algorithm turns out to be a squashed circle, do you
happen
to know what the actual windows (mathematically correct) algorithm is so
I
can make an accurate calculation?
Not off the top of my head, no. It should be a simple geometry problem
though. Possibly easier if solved in polar coordinate space than in
Cartesian.

Pete
Jun 21 '07 #6
Peter,
Not off the top of my head, no. It should be a simple geometry
problem though. Possibly easier if solved in polar coordinate space
than in Cartesian.
Ok. I'm not sure it's that trivial.

I'll always have the alternative of drawing the windows arc to a graphics
path, grabbing the array of points and reading in the last one. Not as
elegant though :-)

-
Thank you,

Christopher Ireland
Jun 21 '07 #7
On Thu, 21 Jun 2007 13:34:30 -0700, Christopher Ireland
<ci******@gmail.comwrote:
>Not off the top of my head, no. It should be a simple geometry
problem though. Possibly easier if solved in polar coordinate space
than in Cartesian.

Ok. I'm not sure it's that trivial.
Gracious...don't give up so easily.

The Wikipedia article on Ellipse has exactly the formula you want. And I
was right, in polar coordinates it's a pretty simple calculation (assuming
you've got the Wikipedia article to give you the exact formula :)...I'm
happy to not have to have derived it myself).

Try this:

private PointF PointFromEllipse(Rectangle rectBounds, float
degrees)
{
// Convert the basic input into something more usable
Point ptCenter = RectCenter(rectBounds);
float radians = ((float)Math.PI * degrees) / 180.0f;
float radiusH = rectBounds.Width / 2.0f,
radiusV = rectBounds.Height / 2.0f;

// Calculate the radius of the ellipse for the given angle
bool fXMajor = radiusH radiusV;
float a = fXMajor ? radiusH : radiusV,
b = fXMajor ? radiusV : radiusH;
float eccentricity = (float)Math.Sqrt(1 - (b * b) / (a * a));
float radiusAngle = b / (float)Math.Sqrt(1 - (eccentricity *
eccentricity) * Math.Pow(Math.Cos(radians), 2));

// Convert the radius back to Cartesian coordinates
if (fXMajor)
{
return new PointF(ptCenter.X + radiusAngle *
(float)Math.Cos(radians),
ptCenter.Y + radiusAngle * (float)Math.Sin(radians));
}
else
{
return new PointF(ptCenter.X + radiusAngle *
(float)Math.Sin(radians),
ptCenter.Y + radiusAngle * (float)Math.Cos(radians));
}
}

Pete
Jun 21 '07 #8
On Thu, 21 Jun 2007 14:53:35 -0700, Peter Duniho
<Np*********@nnowslpianmk.comwrote:
Try this:

[function snipped]
Oops.

Well, there's a pretty significant bug, in that the routine doesn't handle
vertically-oriented ellipses (major axis parallel to the Y axis)
correctly. I tried to include that, but screwed it up and didn't bother
to test that case before posting.

I leave the fix as an exercise for the reader. It's not actually that
hard. :)
Jun 21 '07 #9
Peter,
Gracious...don't give up so easily.
I'm sorry, I don't think I implied I was going to give up, did I?
The Wikipedia article on Ellipse has exactly the formula you want. And I
was right, in polar coordinates it's a pretty simple
calculation (assuming you've got the Wikipedia article to give you
the exact formula :)...I'm happy to not have to have derived it
myself).
Well, I guess if it was that trivial one would have got it right first time,
huh ;-)?
Try this:
Thank you again Peter, I'll see if I can make this work for me.

--
Thank you,

Christopher Ireland
Jun 22 '07 #10
On Thu, 21 Jun 2007 23:30:12 -0700, Christopher Ireland
<ci******@gmail.comwrote:
Well, I guess if it was that trivial one would have got it right first
time,
huh ;-)?
I don't think I used the word "trivial". The formula is simple, that's
all.

Still, you'd think one would, wouldn't you? :)

At least I recognized the need to deal with the case, even if I didn't
handle it correctly. That said, I botched it up well enough that it
occurs to me that if you start with the code I posted, you could spend a
while figuring out what needs to be taken out altogether.

I like leaving _something_ for the reader to figure out on their own, but
in this case that seems a little unfair. So, here's the correct function:

private PointF PointFromEllipse(Rectangle rectBounds, float
degrees)
{
// Convert the basic input into something more usable
Point ptCenter = RectCenter(rectBounds);
float radians = ((float)Math.PI * degrees) / 180.0f;
float radiusH = rectBounds.Width / 2.0f,
radiusV = rectBounds.Height / 2.0f;

// Calculate the radius of the ellipse for the given angle
bool fXMajor = radiusH radiusV;
float a = fXMajor ? radiusH : radiusV,
b = fXMajor ? radiusV : radiusH;
float eccentricity = (float)Math.Sqrt(1 - (b * b) / (a * a));
float radiusAngle = b / (float)Math.Sqrt(1 - (eccentricity *
eccentricity) *
Math.Pow(fXMajor ? Math.Cos(radians) : Math.Sin(radians),
2));

// Convert the radius back to Cartesian coordinates
return new PointF(ptCenter.X + radiusAngle *
(float)Math.Cos(radians),
ptCenter.Y + radiusAngle * (float)Math.Sin(radians));
}
Jun 22 '07 #11
Peter,
At least I recognized the need to deal with the case, even if I didn't
handle it correctly.
And I didn't know how to deal with the case, you're quite correct. That's
why I wrote to this group with the hope that somebody like you did :-)
I like leaving _something_ for the reader to figure out on their own,
but in this case that seems a little unfair.
LOL!
>So, here's the correct function:
That's perfect, thank you Peter.

--
Thank you,

Christopher Ireland
Jun 22 '07 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: Jon | last post by:
Hello all, I'm certain this question has been asked before; I was unsure what terms to search for within the newsgroup archive to find the proper answer I wanted. Hopefully someone can point me...
5
by: lgeastwood | last post by:
I have tweaked the PictureBox97.mdb (Stephen Lebans <www.lebans.com>) code to nicely draw lines, rectangles and circles to the specs that I input. I'm at a loss though with trying to setup an...
7
by: Chris | last post by:
Hi, If a user resizes a Toplevel window, or I set a Toplevel's geometry using the geometry() method*, is there any way to have the geometry reset to that required for all the widgets? I think...
2
by: weird0 | last post by:
I wanted to draw an ellipse using c# with System.Drawing.Graphics. I tried out several tutorials and none of them worked and there seems to be something missing. One did execute without any errors...
1
by: pooker75 | last post by:
'Draw a face Dim xInteger As Integer = Convert.ToInt32(Me.Width / 8) Dim yInteger As Integer = Convert.ToInt32(Me.Height / 8) Dim yellowPen As New Pen(Color.Yellow, 2) ...
3
by: illusion.admins | last post by:
I am trying to code something to tell me if a selected point is in a particular ellipse. For the ellipse I know how it was constructed (know the x,y, and width, height). But if I just check to see...
1
by: PankajGaur | last post by:
Hi, I need to create a Ellipse shaped user control which have folloiwng attributes: 1) The edges are smooth 2) The control shuld only be selected when click on the ellipse shape & not when...
8
by: =?Utf-8?B?RGFu?= | last post by:
I would like to draw an ellipse on a windows form and through mouse drags stretch, rotate and relocate the ellipse. Thanks in advance - Dan
0
by: =?Utf-8?B?UGFua2FqR2F1cg==?= | last post by:
Hi, I need to create a Ellipse shaped user control which have folloiwng attributes: 1) The edges are smooth 2) The control shuld only be selected when click on the ellipse shape & not when...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.