DrawArc和椭圆几何(重新发布) [英] DrawArc and ellipse geometry (repost)

查看:88
本文介绍了DrawArc和椭圆几何(重新发布)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好!


使用en ellipse的定义( http://en.wikipedia.org/wiki/Ellipse )我可以画一个弧点。但是,这个弧的终点不会与使用DrawArc方法绘制的弧的终点重合,例如


公共部分类Form2:表格

{

public Form2()

{

InitializeComponent();

}


private void Form2_Paint(对象发送者,PaintEventArgs e)

{

Draw(e.ClipRectangle,e.Graphics );

}


private void RectCenter(矩形r,out int x,out int y)

{

x =(r.Left + r.Right)/ 2;

y =(r.Top + r.Bottom)/ 2;

}


私有PointF PointFromEllipse(矩形边界,浮动度)

{

浮动a = bounds.Width / 2.0f;

float b = bounds.Height / 2.0f;

float rad =((float)Math.PI / 180.0f)*度;


int xCenter,yCenter;

RectCenter(边界,xCenter,out yCenter);


float x = xCenter +(a *(float)Mat h.Cos(rad));

float y = yCenter +(b *(float)Math.Sin(rad));


返回新的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;我< 315; i ++)

{

p = PointFromEllipse(rect,i);

g.DrawLine(new Pen(Color.Red),p,new PointF(pX,pY + 2));

}

}

}


可以请告诉我这个差异的解释?


-

谢谢,

Christopher Ireland

解决方案

2007年6月20日星期三12:58:10 -0700,Christopher Ireland

< ci *** ***@gmail.com写道:


使用en ellipse的定义

http://en.wikipedia.org/wiki/Ellipse )我可以画一个弧形的b $ b分数。但是,这个弧的终点不会与使用DrawArc方法绘制的弧的终点重合,



我'我不清楚你的问题是什么。你不会画出形成弧线的行b / b
。你正在绘制2个像素高的垂直条纹

椭圆周围的各个点,这正是你得到的输出......


这里''你的代码的sa版本(减去常量的Form派生类

实现的东西)纠正了这个以及其他一些问题

(你没有处理新创建的笔正确的,对于

例子)。它绘制的几乎与DrawArc()

方法相同的精确像素,只有很小的变化,人们自然会期望从两个完全不同的绘制椭圆的实现中获得
br />
(特别是当一个实现实际上只绘制直线时

在椭圆上间隔一度的段)。

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;

}


私有PointF PointFromEllipse(矩形边界,浮点数)

{

float a = bounds.Width / 2 .0f;

float b = bounds.Height / 2.0f;

float rad =((float)Math.PI / 180.0f)*度;


int xCenter,yCenter;

RectCenter(界限,xCenter,out yCenter);


浮动x = xCenter +( a *(float)Math.Cos(rad));

float y = yCenter +(b *(float)Math.Sin(rad));


返回新的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;我< 315; i ++)

{

p = PointFromEllipse(rect,i);

g.DrawLine(Pens.Red,p,pPrev);

pPrev = p;

}

}


Peter,
< blockquote class =post_quotes>
它绘制几乎与DrawArc()方法完全相同的精确像素

,只有非常小的变化,一个

自然期待两个完全不同的实现

绘制一个椭圆(特别是当一个实现实际上是

只需在一个等间隔之间绘制直线段

椭圆)。



感谢您的回复,彼得,我很抱歉没有让自己

更清楚。我已经修改了你的代码来说明我的观点:


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;

}


私人PointF PointFromEllipse(矩形边界,浮动度)

{

浮动a = bounds.Width / 2.0f;

浮动b = bounds.Height / 2.0f ;

float rad =((float)Math.PI / 180.0f)*度;


int xCenter,yCenter;

RectCenter(界限,输出xCenter,输出yCenter);


浮动x = xCenter +(a *(浮动)Math.Cos(rad));

float y = yCenter +(b *(float)Math.Sin(rad ));


返回新的PointF(x,y);

}


private void Draw(Rectangle) rect,Graphics g)

{

rect.Inflate(-5,-5);


using(Pen pen =新笔(Color.Green,3)){//让'好':-)

g.DrawArc(笔,矩形,0,315);

}

PointF p,pPrev = PointFromEllipse(rect,0);


for(int i = 1;我< = 315; i ++)

{

p = PointFromEllipse(rect,i);

g.DrawLine(Pens.Red,p,pPrev);

pPrev = p;

}

}

}


这里你可以看到绿线并没有像红线那样到达尽可能远的地方,尽管事实上这两条线在理论上都是画了一个弧线

到315o。正是这种效果,DrawArc方法似乎绘制了

short,其中我有兴趣听取解释。


-

谢谢,


Christopher Ireland


2007年6月20日星期三23:28: 11 - 0700,Christopher Ireland

< ci ****** @ gmail.comwrote:


[...]

在这里你可以看到绿线并没有到达弧线附近

为红线,尽管事实是从理论上讲,两者都是通过315?o画出一个弧形
。正是这种效果,DrawArc方法似乎绘制了

short,我有兴趣听一个解释。



啊......我现在明白了这个问题。


答案是你的椭圆函数和Windows所做的不是什么

相同(显然)。更具体地说,您使用的算法假设您的椭圆曾经是一个被压扁的圆圈,并且您是

指定坐标空间中的度数原来完美的

圆圈。当然,当你在一个方向上压扁圆圈或者另一个方圆来获得一个椭圆时,你最终也会压扁你的角度。


Windows,on另一方面,正在对一个

圆进行真正的极坐标剪裁以获得弧。也就是说,在极坐标中指定的

弧的起点和终点假定你确实绘制了一个

椭圆,但指定了起点和终点指向未修改的极地

坐标空间。也就是说,取原始椭圆,找到它与给定角度从中心向外绘制的线相交的位置,

并在这些线之间绘制弧线。 />

恕我直言,Windows版本在数学上更正确,但我觉得

的主要观点是决定哪种更适合您的需求和

一直使用它。显然,你不能混合搭配没有

看到你所询问的差异。


对于它的价值,这是你的代码的另一个版本(见下文)

我希望能让它更加清晰。我添加了更多

的东西,这样你就可以使用箭头键来调整你的
弧线的极限,以及绘制一个完美的圆形圆圈以便你可以比较

该圆的角度与椭圆的角度。特别是

,请注意使用DrawArc()

绘制的椭圆版本与圆圈完美对齐,而椭圆计算滞后和

取决于你在弧线的哪个位置引导圆圈。


希望有所帮助。


Pete

这是代码:


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;


开关(keyData)

{

案例Keys.Left:

_degreesTotal - = 1.0f;

fHandled = true;

休息;

case Keys.Right:

_degreesTotal + = 1.0f;

fHandled = true;

休息;

}


if(fHandled)

{

if(_degreesTotal< 0)

{

_degreesTotal + = 360.0f;

}

else if(_degreesTotal> = 360.0 f)

{

_degreesTotal - = 360.0f;

}

无效();

}


返回base.ProcessDialogKey(keyData);

}


私有Point RectCenter(矩形r)

{

返回新点((r.Left + r.Right)/ 2,(r.Top + r.Bottom)/

2);

}


私人PointF PointFromEllipse(矩形边界,浮动度)

{

float a = bounds.Width / 2.0f;

float b = bounds.Height / 2.0f;

float rad =((float)Math。 PI / 180.0f)*度;


点ptCenter = RectCenter(边界);


浮动x = ptCenter.X +(a * (float)Math.Cos(rad));

float y = ptCenter.Y +(b *(float)Math.Sin(rad));


返回新的PointF(x,y);

}


private void Draw(Rectangle rect,Graphics g)

{

rect.Inflate(-5,-5);


矩形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),新尺寸(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);


使用(Pen penGreen = new Pen(Color。绿色,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;

}

}


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

解决方案

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;
}
}


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 315o. 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


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?o. 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;
}
}


这篇关于DrawArc和椭圆几何(重新发布)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆