椭圆成生算法

发布网友 发布时间:2022-04-27 00:32

我来回答

5个回答

热心网友 时间:2022-06-21 18:28

设已知一长轴为len,及另一长轴的端点坐标(x1,y1)和(x2,y2)
求椭圆步骤:
1、求a,b: a=len/2 b=sqr((x1-x2)^2+(y1-y2)^2)
2、求旋转角α :求出(y1-y2)/(x1-x2)的反正切值即为α
3、求椭圆中心坐标(x0,y0): x0=(x1+x2)/2 y0=(y1+y2)/2

3、计算椭圆上点的坐标(x,y):
x=acosθ , y=bsinθ ( 0<=θ< 2*π)
4、计算图形绕原点旋转α 弧度后的坐标(xx,yy):
xx=x*cos(-α )+y*sin(-α )
yy=-x*sin(-α )+y*cos(-α )
5、计算椭圆中心从原点平移到(x0,y0)后椭圆上点的坐标(xxx,yyy):
xxx=xx+x0
yyy=yy+y0
6、在坐标(xxx,yyy)处画一各点
7、在( 0<=θ< 2*π)范围内,按一定间隔取值,重复3-7步骤,即得所要求的椭圆。

以下是vb写的简单示例,新建一各工程,把代码粘贴进去替换原来的所有代码,运行即可看效果

Option Explicit
Dim X1, Y1, X0, Y0, X2, Y2 As Double
Dim A, B, PI As Double
Dim F As Boolean

Private Sub Form_Load()
PI = 3.141592653579
F = False
DrawWidth = 2
Width = 10000
Height = 8000
End Sub

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
X1 = X
Y1 = Y
B = 1000
F = True

End Sub

Public Sub tuoYuan()
Dim Jiao As Double
Dim i, m, n, m1, n1 As Double

Cls
X0 = (X1 + X2) / 2
Y0 = (Y1 + Y2) / 2
A = Sqr((X0 - X2) ^ 2 + (Y0 - Y2) ^ 2)

If X1 <> X2 Then
Jiao = Atn((Y1 - Y2) / (X1 - X2))
Else
Jiao = PI / 2
End If

Form1.PSet (X1, Y1), RGB(255, 0, 0)
Form1.PSet (X0, Y0), RGB(255, 0, 0)
Form1.PSet (X2, Y2), RGB(255, 0, 0)

For i = 0 To PI * 2 Step 0.01
m = A * Cos(i)
n = B * Sin(i)
'Form1.PSet (m + X0, n + Y0), RGB(255, 0, 0)

m1 = m * Cos(-Jiao) + n * Sin(-Jiao)
n1 = -m * Sin(-Jiao) + n * Cos(-Jiao)

Form1.PSet (m1 + X0, n1 + Y0), RGB(0, 255, 0)

Next i

End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If F = True Then
X2 = X
Y2 = Y
Call tuoYuan
End If
End Sub

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
F = False
X2 = X
Y2 = Y
Call tuoYuan
End Sub

热心网友 时间:2022-06-21 18:29

(两个帖子都回复了楼主)

只写步骤,不写代码了。
和楼主共通过,楼主也是这方面的专家,因此步骤就不写太详细了,只写几个关键点吧。

方法1:(最通常)
通过 sin 和 cos 乘两轴长在原点画出正向椭圆,然后倾斜、偏移即可。
这样需要考虑弧度的间隔,否则两点之间并不连续。而盲目的细分弧度,会加重运算负担。
在许多 CAD 软件中,是通过设置圆的内接 n 边形来代表圆的,就是用线段连接。
将 n 边型的取值增大,椭圆就会很平滑了。
问题还有,就是长轴端的弧度,点会分布的比较稀少,因为屏幕分辨率并不是很高,所以可以用 长轴/短轴 的比值,来非等步长的增加弧度取值。

方法2:(近似求解)
通过4条贝塞尔曲线,可以连接成一个近似的椭圆。每段贝塞尔曲线代表原轴向椭圆的1/2*PI弧度,这样做最大误差只有0.027%。
每条贝塞尔曲线的四个控制点可以通过椭圆的外接矩形运算得出。

以扫描线方法的实现:
与楼主沟通过程中,提到了以扫描线的形式实现椭圆绘制过程。

常规方法:
纵向一个像素的移动扫描线,计算其与椭圆的两个交点,并与上一条扫描线的两个交点通过直线连接。第一次和最后一次与椭圆相交需要连接两个交点。
这种方法比较麻烦。

采用缓冲区的解决办法:
许多游戏都使用绘图缓冲区,不过这里用来实现扫描线绘制。
在内存中创建一个 DC 设备,将所有的绘图都转移到该 DC 设备上,然后通过 DC 设备和屏幕设备之间简单的行复制就可以了。

这样应该就完美的解决了楼主的问题。

热心网友 时间:2022-06-21 18:29

很简单。
先把椭圆放在原点,不旋转:

已知 x0,y0,x1,y1;
得:轴长 = sqrt((y1-y0)^2 + (x1-x0)^2)
另一 轴长已知 len.
半轴长 a = 0.5 * sqrt() ; b = 0.5 * len.
离心率 e = sqrt( 1 - (b/a) ^ 2);
原点 椭圆极坐标方程 r = b / sqrt(1-e^2* [cos(sita)]^2)

好啦,现在做椭圆转动,再做平移就可以了。
sita 可以给得很小,例如1度。

程序如下:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

main()
{
double x0,y0,x1,y1;
double ox,oy;
double phi,sinphi,cosphi;
double pi;
double a,b,e,r,sita,sn,cn,xx,yy;
double x[360],y[360];
double len;
int i;

len = 2.0;
x0 = -1.0;
x1 = 3.0;
y0 = 1.0;
y1 = 5.0;

pi = 3.141582653579;

a = 0.5 * sqrt( (y1-y0) * (y1-y0) + (x1-x0) * (x1-x0) );
b = 0.5 * len;
e = sqrt(1.0 - b * b / a / a);

ox = 0.5 * (x0+x1); // 椭圆中心点
oy = 0.5 * (y0+y1);

if (x1-x0 == 0) {phi = pi / 2.0;} else{
phi = atan ( (y1 - y0) / (x1 - x0));
}; // 椭圆倾斜角
sinphi = sin(phi);
cosphi = cos(phi);

for (i=0;i< 360; i++){
sita = pi / 180.0 * i ; // 极座标 sita
cn = cos (sita);
sn = sin (sita);
r = b / sqrt( 1.0 - e * e * cn * cn); // 极座标 r
x[i] = r * cn ;
y[i] = r * sn;
xx = x[i] * cosphi - y[i] * sinphi; // 转动
yy = y[i] * cosphi + x[i] * sinphi; // 转动
x[i] = xx + ox; // 平移
y[i] = yy + oy; // 平移
}

for (i=0;i<360;i++) printf("%.4lf %.4lf 1.0\n",x[i],y[i]);

}

填椭圆用 x[i],y[i],x[i+1],y[i+1] 与 ox,oy 填三角形或填直线就可以了。

热心网友 时间:2022-06-21 18:30

直接给你源代码好了

void CTestView::MyDrawEllipse(CPoint start,CPoint end)

{

CClientDC dc(this);

int a=abs(end.x-start.x);

int b=abs(end.y-start.y);

CPoint p;

p.x=int(start.x+end.x)/2;

p.y=int(start.y+end.y)/2;

int x=0,y=b;

double d1,d2;

d1=b*b+a*a*(-b+0.25);

dc.SetPixel(x+p.x,y+p.y,color);

dc.SetPixel(x+p.x,-y+p.y,color);

dc.SetPixel(-x+p.x,y+p.y,color);

dc.SetPixel(-x+p.x,-y+p.y,color);

while(b*b*(x+1)<a*a*(y-0.5))

{

if(d1<0)

{

d1+=b*b*(2*x+3);

x++;

}

else

{

d1+=b*b*(2*x+3)+a*a*(-2*y+2);

x++;

y--;

}

dc.SetPixel(x+p.x,y+p.y,color);

dc.SetPixel(x+p.x,-y+p.y,color);

dc.SetPixel(-x+p.x,y+p.y,color);

dc.SetPixel(-x+p.x,-y+p.y,color);

}

d2=b*b*(x+0.5)*(x+0.5)+float(a)*a*(y-1)*(y-1)-float(a)*a*b*b;

while(y>0)

{

if(d2<0)

{

d2+=float(b)*b*(2*x+2)+float(a)*a*(-2*y+3);

x++;

y--;

}

else

{

d2+=float(a)*a*(-2*y+3);

y--;

}

dc.SetPixel(x+p.x,y+p.y,color);

dc.SetPixel(x+p.x,-y+p.y,color);

dc.SetPixel(-x+p.x,y+p.y,color);

dc.SetPixel(-x+p.x,-y+p.y,color);

}

}

热心网友 时间:2022-06-21 18:30

%%%%%%%%%%%%%%以下MATLAB6.5测试通过%%%%%%%%%%%%%%

clear
x0=-2;
y0=1;
x1=4;
y1=3;
len=4;

a=sqrt((x1-x0)^2+(y1-y0)^2)/2;
b=len/2;
xmid=(x0+x1)/2;
ymid=(y0+y1)/2;
alpha=atan((y1-y0)/(x1-x0));
matrix=[cos(alpha),sin(alpha);-sin(alpha),cos(alpha)]; %坐标变换矩阵

N=100; %点数
dx=2*a/N;
x=-a:dx:a;
xx=a-dx:-dx:-a;
y = b*sqrt(1-x .^2/a^2);
yy=-b*sqrt(1-xx.^2/a^2);
x=[x,xx];
y=[y,yy];
xynew=inv(matrix)*[x;y];
xnew=xynew(1,:)+xmid;
ynew=xynew(2,:)+ymid;

plot(xnew,ynew);
hold on
plot([x0,x1],[y0,y1],'r');

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com