图形学各种算法代码

目的:实现画直线算法,画圆,画椭圆算法,二维直线裁剪算法,种子扫描填充算法


1. DDA算法,算法思想参考百度百科:
http://baike.baidu.com/link?url=bKEk1Bmu6YO7gdPuQpXokbS2eDV8-X5UQaObYeg1NWyHvLS82d5RBZWfdr-tkHrVKfQWgdbciVf_BLNGh6jsFK


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

	}
	

}


你可能感兴趣的