# 图形学各种算法代码

1. DDA算法，算法思想参考百度百科：

2. 各种算法实现：

2.1 画直线算法：

``````//DDA算法
void drawAlgorithmDialog::drawLineDDA( int x0,int y0,int x1,int y1, QPainter* ppainter )
{
//QPainter painter(this);

int dx, dy, n, k;
float xinc, yinc, x, y;
dx = x1 - x0;
dy = y1 - y0;

if( qAbs(dx) > qAbs(dy) )
{
n = abs(dx);
}
else
{
n = abs(dy);
}

xinc = (float)dx / n;
yinc = (float)dy / n;
x = (float)x0;
y = (float)y0;

for( k = 1; k <= n; k++ )
{
ppainter->drawPoint( int(x + 0.5), int(y+0.5) );
x+=xinc;
y+=yinc;
}

return;
}
//中点画线
void drawAlgorithmDialog::drawLineMidPoint(int x0, int y0, int x1, int y1, QPainter *ppainter)
{
int a, b, d1, d2, d, x, y;
a = y0-y1;
b = x1 - x0;
d = 2 * a + b;
d1 = 2 * a;
d2 = 2 * ( a + b );
x=x0;
y=y0;
ppainter->drawPoint( x, y );
while( x < x1 )
{
if( d < 0 )
{
x++, y++, d+=d2;
}
else
{
x++, d += d1;
}
ppainter->drawPoint( x, y );
//drawpixel (x, y, color);
}
return;
}
// BresenHam画线
void drawAlgorithmDialog::drawLineBresenHam(int x1, int y1, int x2, int y2, QPainter *ppainter )
{
int dx = x2 - x1;//△x
int dy = y2 - y1;//△y
int p = (2*dy) - dx ; //P = 2△y - △x
int dobDy = 2* dy ; // 2 △y
int dobD = 2*(dy - dx) ; // 2(△y - △x)
int PointX,PointY;
//设置两个临时用来显示位置的变量
if( x1 > x2)
{ //判断线段的方向
PointX = x2;//起始坐标X
PointY = y2;起始坐标Y
x2 = x1;
}
else
{
PointX = x1;//起始坐标X
PointY = y1;//起始坐标Y
}
//达因第一个起始点
//cout<<"Point: X:"<drawPoint( PointX, PointY );
while( PointX < x2)
{
PointX++;
if(p < 0)
{
p += dobDy;
}
else
{
PointY++;
p += dobD;
}
//cout<<"Point: X:"<drawPoint( PointX, PointY );
}
return;
}``````

2.2 画圆，椭圆：

``````// 中点画圆
void drawAlgorithmDialog::MidPointCircle( int x1, int y1, int R, QPainter* ppainter )
{
int x = 0;
int y = R;
double d = 1.25 - R;
ppainter->drawPoint( x1,y1 );  //绘制圆心
while( x < y )\
{
ppainter->drawPoint( x+x1,y+y1 );
ppainter->drawPoint( y+x1,x+y1 );
ppainter->drawPoint( -x+x1,y+y1 );
ppainter->drawPoint( -y+x1,x+y1 );

ppainter->drawPoint( -x+x1,-y+y1 );
ppainter->drawPoint( -y+x1,-x+y1 );
ppainter->drawPoint( x+x1,-y+y1 );
ppainter->drawPoint( y+x1,-x+y1 );

if( d < 0 )
{
d += 2 * x + 3;
x++;
}
else
{
d += 2 * ( x - y ) + 5;
x++;
y--;
}

//ppainter->drawPoint( x, y );
}

return;
}

// Bresenham画圆
void drawAlgorithmDialog::BresenhamDrawCircle(int x1, int y1, int R, QPainter *ppainter)
{
int x = 0;
int y = R;
int p = 3 - 2 * R;

ppainter->drawPoint( x1,y1 );  //绘制圆心

for( ; x <= y; x++ )
{
ppainter->drawPoint( x+x1,y+y1 );
ppainter->drawPoint( y+x1,x+y1 );
ppainter->drawPoint( -x+x1,y+y1 );
ppainter->drawPoint( -y+x1,x+y1 );

ppainter->drawPoint( -x+x1,-y+y1 );
ppainter->drawPoint( -y+x1,-x+y1 );
ppainter->drawPoint( x+x1,-y+y1 );
ppainter->drawPoint( y+x1,-x+y1 );

if( p >= 0 )
{
p += 4 * ( x - y ) + 10;
y--;
}
else
{
p += 4 * x + 6;
}
}

return;
}

// 中点画椭圆
void drawAlgorithmDialog::MidPointEllise( int xcenter, int ycenter, int a, int b, QPainter *ppainter) //中点画椭圆法
{
int x = 0;
int y = b;
double d1 = 0;
double d2 = 0;
d1 = b * b + a * a * ( -b + 0.25 );
ppainter->drawPoint( xcenter + x,ycenter + y);
ppainter->drawPoint( xcenter - x,ycenter + y);
ppainter->drawPoint( xcenter + x,ycenter - y);
ppainter->drawPoint( xcenter - x,ycenter - y);

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

ppainter->drawPoint( xcenter + x,ycenter + y);
ppainter->drawPoint( xcenter - x,ycenter + y);
ppainter->drawPoint( xcenter + x,ycenter - y);
ppainter->drawPoint( xcenter - x,ycenter - y);
}

d2 = b*b*(x+0.5)*(x+0.5) + a*a*(y-1)*(y-1)-a*a*b*b;
while( y > 0 )
{
if( d2 < 0 )
{
d2 += b*b*(2*x+2) + a*a*(-2*y+3);
x++;
y--;
}
else
{
d2 += a*a*(-2*y+3);
y--;
}

ppainter->drawPoint( xcenter + x,ycenter + y);
ppainter->drawPoint( xcenter - x,ycenter + y);
ppainter->drawPoint( xcenter + x,ycenter - y);
ppainter->drawPoint( xcenter - x,ycenter - y);
}
return;
}``````

2.3 直线裁剪算法：

``````// 二维直线裁剪-区域编码法裁剪算法：
void LineTrimDialog::makecode(double x, double y, int &c)
{
c = 0;
if( x < xl )
{
c = 1;
}
else if( x > xr )
{
c = 2;
}

if( y < yb )
{
c += 4;
}
else if( y > yt )
{
c += 8;
}

return;
}

//xl 窗口左边x坐标
//xr 窗口右边x坐标
//yb 窗口底部y坐标
//yt 窗口顶部y坐标
//由于坐标原点默认在左上角，故，xr, xl, yt, tb应该为：
// xl = vertexPoint[0].x();
//  xr = vertexPoint[1].x();
//  yb = vertexPoint[0].y();
//  yt = vertexPoint[1].y();
// vertexPoint[0]为裁剪窗口左上角坐标
// vertexPoint[1]为裁剪窗口右下角坐标

// 区域编码法裁剪
void LineTrimDialog::Cohen_Sutherland( double x0, double y0, double x2, double y2, QPainter *pPainter, int i  )
{
// pPainter->drawLine( 100, 100, 300, 300 );
// QMessageBox::warning(this,tr("Warning"),"cohen",QMessageBox::Yes);
// update();
int c = 0;
int c1 = 0;
int c2 = 0;
double x = 0;
double y = 0;
makecode( x0, y0, c1 );
makecode( x2, y2, c2 );
while( c1 != 0 || c2 != 0 )
{
if( c1&c2 == 1 )
{
return;
}
c = c1;
if( c == 0 )
{
c = c2;
}
if( c&1 == 1 )
{
y = y0 + ( y2 - y0 ) * ( xl - x0 ) / ( x2 - x0 );
x = xl;
}
else if( c&2 )
{
y = y0 + ( y2 - y0 ) * ( xr - x0 ) / ( x2 - x0 );
x = xr;
}
else if( c&4 )
{
x = x0 + ( x2 - x0 ) * ( yb - y0 ) / ( y2 - y0 );
y = yb;
}
else if( c&8 )
{
x = x0 + ( x2 - x0 ) * ( yt - y0 ) / ( y2 - y0 );
y = yt;
}
if( c == c1 )
{
x0 = x;
y0 = y;
makecode( x, y, c1 );
}
else
{
x2 = x;
y2 = y;
makecode( x, y, c2 );
}
}
/*
if( x0 - (int)(x0) > 0.5 ) //防止double转int丢失较大精度
{
x0++;
}
if( y0 - (int)(y0) > 0.5 )
{
y0++;
}
if( x2 - (int)(x2) > 0.5 )
{
x2++;
}
if( y2 - (int)(y2) > 0.5 )
{
y2++;
}*/
// QMessageBox::warning(this,tr("Warning"),"t344st",QMessageBox::Yes);
// LinePointArray[i] = QPoint( x0, y0 ); //会把x0,y0,x2,y2转换为int，会丢失精度
//  LinePointArray[i+1] = QPoint( x2, y2 );
//在这里直接绘制，可以避免由double转换为int时丢失的精度
pPainter->drawLine( x0, y0, x2, y2 );  //向上偏移一下，方便看到裁剪后的直线
update();
return;
}

// 二维直线裁剪-梁友栋-Barsky算法：
bool LineTrimDialog::cansee(double q, double d, double &t0, double &t1)
{
double r;
if( q < 0 )
{
r = d / q;
if( r > t1 )
{
return false;
}
else if( r > t0 )
{
t0 = r;
}
}
else if( q > 0 )
{
r = d / q;
if( r < t0 )
{
return false;
}
else if( r < t1 )
{
t1 = r;
}
else if( d < 0 )
{
return false;
}
}
return true;
}
void LineTrimDialog::L_Barsky(double x0, double y0, double x2, double y2, QPainter *pPainter, int i )
{
//QMessageBox::warning(this,tr("Warning"),"barsky",QMessageBox::Yes);
double t0, t1, deltax, deltay;
t0 = 0.0;
t1 = 1.0;
deltax = x2 - x0;

if( !cansee( -deltax, x0 - xl, t0, t1 ) )
{
return;
}

if( !cansee( deltax, xr - x0, t0, t1 ) )
{
return;
}

deltay = y2 - y0;

if( !cansee( -deltay, y0 - yb, t0, t1 ) )
{
return;
}

if( !cansee( deltay, yt - y0, t0, t1 ) )
{
return;
}

x2 = x0 + t1 * deltax;
y2 = y0 + t1 * deltay;
x0 = x0 + t0 * deltax;
y0 = y0 + t0 * deltay;

// LinePointArray1.push_back( DPoint( x0, y0 ) );
// LinePointArray1.push_back( DPoint( x2, y2 ) );

pPainter->drawLine( x0, y0, x2, y2 );
update();

/* if( x0 - (int)(x0) > 0.5 ) //防止double转int丢失较大精度
{
x0++;
}

if( y0 - (int)(y0) > 0.5 )
{
y0++;
}

if( x2 - (int)(x2) > 0.5 )
{
x2++;
}

if( y2 - (int)(y2) > 0.5 )
{
y2++;
}*/

//pPainter->drawLine( x0, y0, x2, y2 );

//LinePointArray[i] = QPoint( x0, y0 );
//LinePointArray[i+1] = QPoint( x2, y2 );

return;
}``````

2.4 种子扫描填充算法

``````// 种子扫描填充算法 (x,y)为种子点
void CZhztchView::boundaryfill4(int x, int y, int boundarycolor, int newcolor)
{
/*
int color;
CClientDC dc(this);      //获取客户区设备描述表
color=dc.GetPixel(x,y);

if(color!=newcolor&&color!=boundarycolor)
{
dc.SetPixel(x,y,newcolor);
boundaryfill4(x,y+1,boundarycolor,newcolor);
boundaryfill4(x,y-1,boundarycolor,newcolor);
boundaryfill4(x-1,y,boundarycolor,newcolor);
boundaryfill4(x+1,y,boundarycolor,newcolor);
} */

int color;
//color=dc.GetPixel(x,y);

CClientDC dc(this);      //获取客户区设备描述表
using namespace std;
int x0 = 0;
int xl = 0;
int xr = 0;
int y0 = 0;
int xid = 0;
bool flag = false;
int count = 0;
stack s;
Point p;
s.push( Point( x, y ) );

while( !s.empty() ) //判断栈是否为空
{
p = s.top();
s.pop();
x = p.x;
y = p.y;
dc.SetPixel(x,y,newcolor);
//painter->drawPoint( x, y );
// SetPixel( hdc, x, y, 16711935 );
// repaint();
x0 = x + 1;

while( dc.GetPixel( x0, y ) != boundarycolor && dc.GetPixel( x0, y ) != newcolor )// 填充种子右方像素
{
//painter->drawPoint( x0, y );
dc.SetPixel(x,y,newcolor);
//SetPixel( hdc, x, y, 16711935 );
// repaint();
x0++;
//repaint();

}

xr = x0 - 1; //最右边像素位置
x0 = x - 1;

while( dc.GetPixel( x0, y ) != boundarycolor && dc.GetPixel( x0, y ) != newcolor ) //填充种子左边像素
{
//painter->drawPoint( x0, y );
dc.SetPixel(x,y,newcolor);
//SetPixel( hdc, x, y, 16711935 );
// repaint();
x0--;
}

xl = x0 + 1; //最左边像素位置
y0 = y;

for( int i = 1; i >= -1; i -= 2 )
{
x0 = xr;
y = y0 + i;
while( x0 >= xl )
{
flag = false;

while( ( dc.GetPixel( x0, y ) != boundarycolor ) && ( dc.GetPixel( x0, y ) != newcolor ) && ( x0 >= xl ) )
{
if( !flag )
{
flag = true;
xid = x0;
}
x0--;
}

if(flag)
{
s.push( Point( xid, y ) );
flag = false;
}

while( ( dc.GetPixel( x0, y ) == boundarycolor ) || ( dc.GetPixel( x0, y ) == newcolor ) && ( x0 >= xl ) )
{
x0--;
}
}
}

}

}``````