分享

椭圆中点生成算法

 勤奋不止 2012-03-12

椭圆中点生成算法

(2008-12-02 10:37:16)

椭圆对称性质原理:

(1)圆是满足x轴对称的,这样只需要计算原来的1/2点的位置;

(2)圆是满足y轴对称的,这样只需要计算原来的1/2点的位置;

通过上面分析可以得到实际上我们计算椭圆生成时候,只需要计算1/4个椭圆就可以实现对于所有点的生成了。

例如:分析出来目标点(x,y)必然存在(x,-y),(-x,y),(-x,-y)的另外3个点。关于中心画圆算法,通过计算x = 0到 y = 0 的1/4椭圆的范围,然后通过对称原理得到其他3/4个点的信息。(R2表示椭圆厂轴的半径)



椭圆中点生成算法是将椭圆在第一象限中分为两个部分:

(1)对于斜率绝对值小于1的区域内在x方向取单位量;

(2)对于斜率绝对值大于1的区域内在y方向取单位量;



斜率可以通过椭圆的标准方程中获得为
K = - (ry*ry)*x/(rx*rx)*y;



这里中点椭圆生成算法同样和Bresenham算法有很多相似之处,同样有一个决定下一个位置的关键值P来做权衡处理。在中点画椭圆算法中,通过平移的方法将假设圆心在坐标原点,然后计算,最后再平移到真实原心位置。

中点椭圆算法内容:

1,输入椭圆的两个半径r1和r2,并且输入椭圆的圆心。设置初始点(x0,y0)的位置为(0,r2);

2,计算区域1中央决策参数的初始值

p = ry*ry - rx*rx*ry + 1/4*(rx*rx);

3,在区域1中的每个Xn为止,从n = 0 开始,直到|K|(斜率)小于-1时后结束;

(1)如果p < 0 ,绘制下一个点(x+1,y),并且计算
p = p + r2*r2*(3+2*x);

(2)如果P >=0 ,绘制下一个点(x+1,y-1),并且计算
p = p + r2*r2*(3+2*point.x) - 2*r1*r1*(y-1)

4,设置新的参数初始值;

p = ry*ry(X0+1/2)*(X0+1/2) + rx*rx*(Y0-1) - rx*rx*ry*ry;

5,在区域2中的每个Yn为止,从n = 0开始,直到y = 0时结束。

(1)如果P>0的情况下,下一个目标点为(x,y-1),并且计算
p = p - 2rx*rx*(Yn+1) + rx*rx;

(2)如果p<=0的情况下,下一个目标点为(x+1,y-1),并且计算
p = p - 2rx*rx*Y(n+1) + 2ry*ry*(Xn+1)+rx*rx;

6,更具对称性原理计算其他3个象限的坐标。

7,急速拿出中心位置在(x1,y1)的位置

x = x + x1;

y = y + y1;



实例代码:

#include <iostream>

#include <math.h>

using namespace std;



struct Point{

int x;

int y;

};



void PointsEllipse(int x,int y,int r1,int r2){

Point point;

int p ;//参数

int k ; //斜率

point.x = 0;

point.y = r2; //

计算区域1中央决策参数的初始值

p = r2*r2 - r1*r1*r2 + 1/4*(r1*r1);

while( point.x < point.y){

if( p < 0){

point.x ++;

p = p + r2*r2*(3+2*point.x);

}

else{

point.x++;

point.y--;

p = p + r2*r2*(3+2*point.x) - 2*r1*r1*(point.y-1) ;

}

temp.x = point.x + x;
temp.y = point.y + y;
printf("Point X:%d Y:%d\r\n",temp.x,temp.y);
printf("Point X:%d Y:%d\r\n",temp.x,-temp.y);
printf("Point X:%d Y:%d\r\n",-temp.x,temp.y);
printf("Point X:%d Y:%d\r\n",-temp.x,-temp.y);

}

p = r2*r2*(0+1/2)*(0+1/2) + r1*r1*(r1-1)*(r1-1) - r1*r1*r2*r2;

while(point.y > 0){

if(p > 0){

point.y--;

p = p - 2*r1*r1*point.y - 2*r1*r1 + r1*r1;

}

else{

point.y--;

point.x++;

p = p - 2*r1*r1*point.y - 2*r1*r1 + r1*r1 + 2*r2*r2*point.x + 2*r2*r2 ;

}

temp.x = point.x + x;
temp.y = point.y + y;
printf("Point X:%d Y:%d\r\n",temp.x,temp.y);
printf("Point X:%d Y:%d\r\n",temp.x,-temp.y);
printf("Point X:%d Y:%d\r\n",-temp.x,temp.y);
printf("Point X:%d Y:%d\r\n",-temp.x,-temp.y);

}

}

 

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

已知 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.14158265358979;

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 填三角形或填直线就可以了。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多